feat: 添加点云着色按钮 适配调整后的下位机图像采集方式
This commit is contained in:
@@ -66,9 +66,11 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
, m_rgbSkipCounter(0)
|
||||
{
|
||||
m_rgbProcessing.storeRelaxed(0); // 初始化RGB处理标志
|
||||
m_leftIREnabled.storeRelaxed(1); // 初始化左红外启用标志(默认启用)
|
||||
m_rightIREnabled.storeRelaxed(1); // 初始化右红外启用标志(默认启用)
|
||||
m_rgbEnabled.storeRelaxed(1); // 初始化RGB启用标志(默认启用)
|
||||
m_leftIRProcessing.storeRelaxed(0); // 初始化左红外处理标志
|
||||
m_rightIRProcessing.storeRelaxed(0); // 初始化右红外处理标志
|
||||
m_leftIREnabled.storeRelaxed(0); // 初始化左红外启用标志(默认禁用)
|
||||
m_rightIREnabled.storeRelaxed(0); // 初始化右红外启用标志(默认禁用)
|
||||
m_rgbEnabled.storeRelaxed(0); // 初始化RGB启用标志(默认禁用)
|
||||
setupUI();
|
||||
setupConnections();
|
||||
loadSettings();
|
||||
@@ -105,7 +107,7 @@ MainWindow::~MainWindow()
|
||||
|
||||
void MainWindow::setupUI()
|
||||
{
|
||||
setWindowTitle("D330Viewer - D330M 相机控制");
|
||||
setWindowTitle("河北省科学院应用数学研究所");
|
||||
resize(1280, 720); // 16:9 比例
|
||||
|
||||
// 设置应用程序图标
|
||||
@@ -187,9 +189,9 @@ void MainWindow::setupUI()
|
||||
m_rightIRToggle->setCheckable(true);
|
||||
m_rgbToggle->setCheckable(true);
|
||||
|
||||
m_leftIRToggle->setChecked(true);
|
||||
m_rightIRToggle->setChecked(true);
|
||||
m_rgbToggle->setChecked(true);
|
||||
m_leftIRToggle->setChecked(false);
|
||||
m_rightIRToggle->setChecked(false);
|
||||
m_rgbToggle->setChecked(false);
|
||||
|
||||
m_leftIRToggle->setFixedHeight(32);
|
||||
m_rightIRToggle->setFixedHeight(32);
|
||||
@@ -219,6 +221,17 @@ void MainWindow::setupUI()
|
||||
toolBarLayout->addWidget(m_rightIRToggle);
|
||||
toolBarLayout->addWidget(m_rgbToggle);
|
||||
|
||||
toolBarLayout->addSpacing(10);
|
||||
|
||||
// 点云颜色开关按钮
|
||||
m_pointCloudColorToggle = new QPushButton("点云着色", topToolBar);
|
||||
m_pointCloudColorToggle->setCheckable(true);
|
||||
m_pointCloudColorToggle->setChecked(false);
|
||||
m_pointCloudColorToggle->setFixedHeight(32);
|
||||
m_pointCloudColorToggle->setToolTip("开启/关闭点云深度着色");
|
||||
m_pointCloudColorToggle->setStyleSheet(toggleStyle);
|
||||
toolBarLayout->addWidget(m_pointCloudColorToggle);
|
||||
|
||||
toolBarLayout->addSpacing(20);
|
||||
|
||||
// 单目/双目模式切换按钮
|
||||
@@ -363,12 +376,12 @@ void MainWindow::setupUI()
|
||||
|
||||
QHBoxLayout *exposureLayout = new QHBoxLayout();
|
||||
m_exposureSlider = new QSlider(Qt::Horizontal, exposureGroup);
|
||||
m_exposureSlider->setRange(1000, 100000);
|
||||
m_exposureSlider->setValue(10000);
|
||||
m_exposureSlider->setRange(100, 100000);
|
||||
m_exposureSlider->setValue(1000);
|
||||
|
||||
m_exposureSpinBox = new QSpinBox(exposureGroup);
|
||||
m_exposureSpinBox->setRange(1000, 100000);
|
||||
m_exposureSpinBox->setValue(10000);
|
||||
m_exposureSpinBox->setRange(100, 100000);
|
||||
m_exposureSpinBox->setValue(1000);
|
||||
m_exposureSpinBox->setMinimumWidth(80);
|
||||
|
||||
exposureLayout->addWidget(m_exposureSlider, 3);
|
||||
@@ -704,6 +717,14 @@ void MainWindow::setupConnections()
|
||||
}
|
||||
});
|
||||
|
||||
// 点云颜色开关连接
|
||||
connect(m_pointCloudColorToggle, &QPushButton::toggled, this, [this](bool checked) {
|
||||
if (m_pointCloudWidget) {
|
||||
m_pointCloudWidget->setColorMode(checked);
|
||||
qDebug() << "点云着色:" << (checked ? "开启" : "关闭");
|
||||
}
|
||||
});
|
||||
|
||||
// 单目/双目模式切换按钮连接
|
||||
connect(m_monocularBtn, &QPushButton::clicked, this, [this]() {
|
||||
m_monocularBtn->setChecked(true);
|
||||
@@ -1002,12 +1023,34 @@ void MainWindow::onLeftImageReceived(const QByteArray &jpegData, uint32_t blockI
|
||||
m_lastLeftFrameTime = currentTime;
|
||||
}
|
||||
|
||||
// 使用后台线程处理16位原始数据,避免阻塞UI
|
||||
// 使用后台线程处理红外数据,避免阻塞UI
|
||||
if (m_leftImageDisplay && jpegData.size() > 0) {
|
||||
// 检查数据大小是否为16位图像
|
||||
size_t expectedSize = 1224 * 1024 * sizeof(uint16_t);
|
||||
if (jpegData.size() == expectedSize) {
|
||||
// 复制数据到局部变量
|
||||
// 检查数据大小:8位下采样(612x512)或16位原始(1224x1024)
|
||||
size_t size8bit = 612 * 512;
|
||||
size_t size16bit = 1224 * 1024 * sizeof(uint16_t);
|
||||
|
||||
if (jpegData.size() == size8bit) {
|
||||
// 8位下采样格式:直接显示
|
||||
QByteArray dataCopy = jpegData;
|
||||
QtConcurrent::run([this, dataCopy]() {
|
||||
try {
|
||||
QImage image(reinterpret_cast<const uchar*>(dataCopy.constData()),
|
||||
612, 512, 612, QImage::Format_Grayscale8);
|
||||
QImage imageCopy = image.copy();
|
||||
|
||||
QMetaObject::invokeMethod(this, [this, imageCopy]() {
|
||||
if (m_leftImageDisplay) {
|
||||
QPixmap pixmap = QPixmap::fromImage(imageCopy);
|
||||
m_leftImageDisplay->setPixmap(pixmap.scaled(
|
||||
m_leftImageDisplay->size(), Qt::KeepAspectRatio, Qt::FastTransformation));
|
||||
}
|
||||
}, Qt::QueuedConnection);
|
||||
} catch (const std::exception &e) {
|
||||
qDebug() << "[MainWindow] ERROR: Left IR 8bit processing exception:" << e.what();
|
||||
}
|
||||
});
|
||||
} else if (jpegData.size() == size16bit) {
|
||||
// 16位原始格式:需要归一化处理
|
||||
QByteArray dataCopy = jpegData;
|
||||
|
||||
// 在后台线程处理
|
||||
@@ -1095,7 +1138,8 @@ void MainWindow::onLeftImageReceived(const QByteArray &jpegData, uint32_t blockI
|
||||
}
|
||||
});
|
||||
} else {
|
||||
qDebug() << "[MainWindow] ERROR: Left IR data size mismatch:" << jpegData.size();
|
||||
qDebug() << "[MainWindow] ERROR: Left IR data size mismatch:" << jpegData.size()
|
||||
<< "(expected 8bit:" << size8bit << "or 16bit:" << size16bit << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1126,12 +1170,34 @@ void MainWindow::onRightImageReceived(const QByteArray &jpegData, uint32_t block
|
||||
m_lastRightFrameTime = currentTime;
|
||||
}
|
||||
|
||||
// 使用后台线程处理16位原始数据,避免阻塞UI
|
||||
// 使用后台线程处理红外数据,避免阻塞UI
|
||||
if (m_rightImageDisplay && jpegData.size() > 0) {
|
||||
// 检查数据大小是否为16位图像
|
||||
size_t expectedSize = 1224 * 1024 * sizeof(uint16_t);
|
||||
if (jpegData.size() == expectedSize) {
|
||||
// 复制数据到局部变量
|
||||
// 检查数据大小:8位下采样(612x512)或16位原始(1224x1024)
|
||||
size_t size8bit = 612 * 512;
|
||||
size_t size16bit = 1224 * 1024 * sizeof(uint16_t);
|
||||
|
||||
if (jpegData.size() == size8bit) {
|
||||
// 8位下采样格式:直接显示
|
||||
QByteArray dataCopy = jpegData;
|
||||
QtConcurrent::run([this, dataCopy]() {
|
||||
try {
|
||||
QImage image(reinterpret_cast<const uchar*>(dataCopy.constData()),
|
||||
612, 512, 612, QImage::Format_Grayscale8);
|
||||
QImage imageCopy = image.copy();
|
||||
|
||||
QMetaObject::invokeMethod(this, [this, imageCopy]() {
|
||||
if (m_rightImageDisplay) {
|
||||
QPixmap pixmap = QPixmap::fromImage(imageCopy);
|
||||
m_rightImageDisplay->setPixmap(pixmap.scaled(
|
||||
m_rightImageDisplay->size(), Qt::KeepAspectRatio, Qt::FastTransformation));
|
||||
}
|
||||
}, Qt::QueuedConnection);
|
||||
} catch (const std::exception &e) {
|
||||
qDebug() << "[MainWindow] ERROR: Right IR 8bit processing exception:" << e.what();
|
||||
}
|
||||
});
|
||||
} else if (jpegData.size() == size16bit) {
|
||||
// 16位原始格式:需要归一化处理
|
||||
QByteArray dataCopy = jpegData;
|
||||
|
||||
// 在后台线程处理
|
||||
@@ -1219,7 +1285,8 @@ void MainWindow::onRightImageReceived(const QByteArray &jpegData, uint32_t block
|
||||
}
|
||||
});
|
||||
} else {
|
||||
qDebug() << "[MainWindow] ERROR: Right IR data size mismatch:" << jpegData.size();
|
||||
qDebug() << "[MainWindow] ERROR: Right IR data size mismatch:" << jpegData.size()
|
||||
<< "(expected 8bit:" << size8bit << "or 16bit:" << size16bit << ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1529,74 +1596,100 @@ void MainWindow::performBackgroundSave(const QString &saveDir, const QString &ba
|
||||
bool rightIRSuccess = false;
|
||||
bool rgbSuccess = false;
|
||||
|
||||
// 保存左红外图像(16位原始数据,1224×1024)
|
||||
// 保存左红外图像(支持16位原始1224×1024或8位下采样612×512)
|
||||
if (!leftIRData.isEmpty()) {
|
||||
try {
|
||||
size_t expectedSize = 1224 * 1024 * sizeof(uint16_t);
|
||||
if (leftIRData.size() == expectedSize) {
|
||||
size_t size16bit = 1224 * 1024 * sizeof(uint16_t);
|
||||
size_t size8bit = 612 * 512;
|
||||
|
||||
if (leftIRData.size() == size16bit) {
|
||||
const uint16_t* src = reinterpret_cast<const uint16_t*>(leftIRData.constData());
|
||||
|
||||
// 创建16位灰度图像
|
||||
cv::Mat leftIR16(1024, 1224, CV_16UC1);
|
||||
memcpy(leftIR16.data, src, expectedSize);
|
||||
memcpy(leftIR16.data, src, size16bit);
|
||||
|
||||
// 根据depthFormat参数保存
|
||||
if (depthFormat == "png" || depthFormat == "both") {
|
||||
// 保存PNG格式(8位)
|
||||
QString pngPath = QString("%1/%2_left_ir.png").arg(saveDir).arg(baseName);
|
||||
cv::Mat leftIR8;
|
||||
leftIR16.convertTo(leftIR8, CV_8UC1, 255.0 / 65535.0);
|
||||
cv::imwrite(pngPath.toStdString(), leftIR8);
|
||||
qDebug() << "保存左红外PNG图像:" << pngPath;
|
||||
qDebug() << "保存左红外PNG图像(16bit):" << pngPath;
|
||||
leftIRSuccess = true;
|
||||
}
|
||||
|
||||
if (depthFormat == "tiff" || depthFormat == "both") {
|
||||
// 保存TIFF格式(保留16位精度)
|
||||
QString tiffPath = QString("%1/%2_left_ir.tiff").arg(saveDir).arg(baseName);
|
||||
cv::imwrite(tiffPath.toStdString(), leftIR16);
|
||||
qDebug() << "保存左红外TIFF图像(16位):" << tiffPath;
|
||||
leftIRSuccess = true;
|
||||
}
|
||||
} else if (leftIRData.size() == size8bit) {
|
||||
cv::Mat leftIR8(512, 612, CV_8UC1, const_cast<char*>(leftIRData.constData()));
|
||||
cv::Mat leftIR8Clone = leftIR8.clone();
|
||||
|
||||
if (depthFormat == "png" || depthFormat == "both") {
|
||||
QString pngPath = QString("%1/%2_left_ir.png").arg(saveDir).arg(baseName);
|
||||
cv::imwrite(pngPath.toStdString(), leftIR8Clone);
|
||||
qDebug() << "保存左红外PNG图像(8bit下采样):" << pngPath;
|
||||
leftIRSuccess = true;
|
||||
}
|
||||
if (depthFormat == "tiff" || depthFormat == "both") {
|
||||
QString tiffPath = QString("%1/%2_left_ir.tiff").arg(saveDir).arg(baseName);
|
||||
cv::imwrite(tiffPath.toStdString(), leftIR8Clone);
|
||||
qDebug() << "保存左红外TIFF图像(8bit下采样):" << tiffPath;
|
||||
leftIRSuccess = true;
|
||||
}
|
||||
} else {
|
||||
qDebug() << "左红外数据大小不匹配:" << leftIRData.size();
|
||||
qDebug() << "左红外数据大小不匹配:" << leftIRData.size()
|
||||
<< "(期望16bit:" << size16bit << "或8bit:" << size8bit << ")";
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
qDebug() << "保存左红外图像失败:" << e.what();
|
||||
}
|
||||
}
|
||||
|
||||
// 保存右红外图像(16位原始数据,1224×1024)
|
||||
// 保存右红外图像(支持16位原始1224×1024或8位下采样612×512)
|
||||
if (!rightIRData.isEmpty()) {
|
||||
try {
|
||||
size_t expectedSize = 1224 * 1024 * sizeof(uint16_t);
|
||||
if (rightIRData.size() == expectedSize) {
|
||||
size_t size16bit = 1224 * 1024 * sizeof(uint16_t);
|
||||
size_t size8bit = 612 * 512;
|
||||
|
||||
if (rightIRData.size() == size16bit) {
|
||||
const uint16_t* src = reinterpret_cast<const uint16_t*>(rightIRData.constData());
|
||||
|
||||
// 创建16位灰度图像
|
||||
cv::Mat rightIR16(1024, 1224, CV_16UC1);
|
||||
memcpy(rightIR16.data, src, expectedSize);
|
||||
memcpy(rightIR16.data, src, size16bit);
|
||||
|
||||
// 根据depthFormat参数保存
|
||||
if (depthFormat == "png" || depthFormat == "both") {
|
||||
// 保存PNG格式(8位)
|
||||
QString pngPath = QString("%1/%2_right_ir.png").arg(saveDir).arg(baseName);
|
||||
cv::Mat rightIR8;
|
||||
rightIR16.convertTo(rightIR8, CV_8UC1, 255.0 / 65535.0);
|
||||
cv::imwrite(pngPath.toStdString(), rightIR8);
|
||||
qDebug() << "保存右红外PNG图像:" << pngPath;
|
||||
qDebug() << "保存右红外PNG图像(16bit):" << pngPath;
|
||||
rightIRSuccess = true;
|
||||
}
|
||||
|
||||
if (depthFormat == "tiff" || depthFormat == "both") {
|
||||
// 保存TIFF格式(保留16位精度)
|
||||
QString tiffPath = QString("%1/%2_right_ir.tiff").arg(saveDir).arg(baseName);
|
||||
cv::imwrite(tiffPath.toStdString(), rightIR16);
|
||||
qDebug() << "保存右红外TIFF图像(16位):" << tiffPath;
|
||||
rightIRSuccess = true;
|
||||
}
|
||||
} else if (rightIRData.size() == size8bit) {
|
||||
cv::Mat rightIR8(512, 612, CV_8UC1, const_cast<char*>(rightIRData.constData()));
|
||||
cv::Mat rightIR8Clone = rightIR8.clone();
|
||||
|
||||
if (depthFormat == "png" || depthFormat == "both") {
|
||||
QString pngPath = QString("%1/%2_right_ir.png").arg(saveDir).arg(baseName);
|
||||
cv::imwrite(pngPath.toStdString(), rightIR8Clone);
|
||||
qDebug() << "保存右红外PNG图像(8bit下采样):" << pngPath;
|
||||
rightIRSuccess = true;
|
||||
}
|
||||
if (depthFormat == "tiff" || depthFormat == "both") {
|
||||
QString tiffPath = QString("%1/%2_right_ir.tiff").arg(saveDir).arg(baseName);
|
||||
cv::imwrite(tiffPath.toStdString(), rightIR8Clone);
|
||||
qDebug() << "保存右红外TIFF图像(8bit下采样):" << tiffPath;
|
||||
rightIRSuccess = true;
|
||||
}
|
||||
} else {
|
||||
qDebug() << "右红外数据大小不匹配:" << rightIRData.size();
|
||||
qDebug() << "右红外数据大小不匹配:" << rightIRData.size()
|
||||
<< "(期望16bit:" << size16bit << "或8bit:" << size8bit << ")";
|
||||
}
|
||||
} catch (const std::exception &e) {
|
||||
qDebug() << "保存右红外图像失败:" << e.what();
|
||||
|
||||
Reference in New Issue
Block a user