feat: 添加点云着色按钮 适配调整后的下位机图像采集方式

This commit is contained in:
2026-02-02 14:08:30 +08:00
parent de8ce7c4a6
commit b1871aa9e7
11 changed files with 298 additions and 125 deletions

View File

@@ -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();