2026-06-26 17:55:15 +08:00

696 lines
26 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QComboBox>
#include <QDir>
#include <QFileDialog>
#include <QInputDialog>
#include <QLineEdit>
#include <QListWidget>
#include <QMessageBox>
#include <QMutexLocker>
#include <QPushButton>
#include <QStandardPaths>
#include <QStringList>
#include <QTimer>
namespace
{
QString matrixFirstRowText(const WDRemoteMatrix& matrix)
{
if (matrix.empty())
return QStringLiteral("N/A");
int count = matrix.cols;
if (count > static_cast<int>(matrix.data.size()))
count = static_cast<int>(matrix.data.size());
QStringList values;
for (int i = 0; i < count; ++i)
values << QString::number(matrix.data[static_cast<size_t>(i)], 'f', 3);
return values.join(QStringLiteral(", "));
}
}
MainWindow::MainWindow(QWidget* parent)
: QMainWindow(parent), ui(new Ui::MainWindow)
{
ui->setupUi(this);
setWindowTitle(QStringLiteral("WDRemoteReceiver 测试(单目/双目图像)"));
connect(ui->btnSearch, &QPushButton::clicked, this, &MainWindow::onSearchClicked);
connect(ui->listDevices, &QListWidget::currentRowChanged,
this, &MainWindow::onDeviceSelected);
connect(ui->btnConnect, &QPushButton::clicked, this, &MainWindow::onConnectClicked);
connect(ui->btnDisconnect, &QPushButton::clicked, this, &MainWindow::onDisconnectClicked);
connect(ui->btnLiveStream, &QPushButton::clicked, this, &MainWindow::onLiveStreamClicked);
connect(ui->btnStart, &QPushButton::clicked, this, &MainWindow::onStartWorkClicked);
connect(ui->btnStop, &QPushButton::clicked, this, &MainWindow::onStopWorkClicked);
connect(ui->btnSingle, &QPushButton::clicked, this, &MainWindow::onSingleClicked);
connect(ui->btnSetExposure, &QPushButton::clicked, this, &MainWindow::onSetExposureClicked);
connect(ui->btnSetGain, &QPushButton::clicked, this, &MainWindow::onSetGainClicked);
connect(ui->btnSwapCameras, &QPushButton::clicked, this, &MainWindow::onSwapCamerasClicked);
connect(ui->btnSetAlgo, &QPushButton::clicked, this, &MainWindow::onSetAlgoParamsClicked);
connect(ui->btnGetInfo, &QPushButton::clicked, this, &MainWindow::onGetInfoClicked);
connect(ui->btnCustom, &QPushButton::clicked, this, &MainWindow::onCustomCmdClicked);
connect(ui->btnChooseSaveDir, &QPushButton::clicked, this, &MainWindow::onChooseSaveDirClicked);
connect(ui->btnSaveImages, &QPushButton::clicked, this, &MainWindow::onSaveImagesClicked);
QString baseSaveDir = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation);
if (baseSaveDir.isEmpty())
baseSaveDir = QDir::currentPath();
m_saveImageDir = QDir(baseSaveDir).filePath(QStringLiteral("WDRemoteReceiverImages"));
ui->editSaveDir->setText(m_saveImageDir);
// 图像传输模式选择(单目/双目)
m_pDetectModeCombo = new QComboBox(this);
m_pDetectModeCombo->addItem(QStringLiteral("双目图像 (binocular)"), QString("binocular"));
m_pDetectModeCombo->addItem(QStringLiteral("单目图像 (mono)"), QString("mono"));
m_pDetectModeCombo->setCurrentIndex(0); // 默认双目
m_pDetectModeCombo->setToolTip(QStringLiteral("选择检测模式下的图像传输方式\n"
"mono: 仅发送左目图像\n"
"binocular: 发送左右目两张图像"));
// 把 combo 插入到 grpControl 布局中
QVBoxLayout* ctrlLayout = qobject_cast<QVBoxLayout*>(ui->grpControl->layout());
if (ctrlLayout)
{
// 在第一个 spacer 之前插入
ctrlLayout->insertWidget(1, m_pDetectModeCombo);
}
connect(m_pDetectModeCombo, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &MainWindow::onDetectModeChanged);
// 跨线程:库回调(任意线程) → 主线程 UI
connect(this, &MainWindow::uiAppendLog, this, &MainWindow::onAppendLog, Qt::QueuedConnection);
connect(this, &MainWindow::uiShowDetection, this, &MainWindow::onShowDetection, Qt::QueuedConnection);
connect(this, &MainWindow::uiShowLeftImage, this, &MainWindow::onShowLeftImage, Qt::QueuedConnection);
connect(this, &MainWindow::uiShowRightImage, this, &MainWindow::onShowRightImage, Qt::QueuedConnection);
connect(this, &MainWindow::uiUpdateConnectState, this, &MainWindow::onUpdateConnectState, Qt::QueuedConnection);
setupReceiver();
ui->listDevices->addItem(QStringLiteral("未搜索到设备"));
ui->btnConnect->setEnabled(false);
QTimer::singleShot(100, this, &MainWindow::onSearchClicked);
}
MainWindow::~MainWindow()
{
releaseReceiver();
delete ui;
}
void MainWindow::setupReceiver()
{
IWDRemoteReceiver::CreateInstance(&m_pReceiver);
if (!m_pReceiver)
{
QMessageBox::critical(this, "Error",
"CreateInstance(IWDRemoteReceiver) failed");
return;
}
// 默认使用界面当前选择,避免初始化时把用户选择覆盖回双目。
const QString initialMode = m_pDetectModeCombo
? m_pDetectModeCombo->currentData().toString()
: QStringLiteral("binocular");
m_monoImageMode.store(initialMode == "mono");
m_pReceiver->SetDetectMode(initialMode.toStdString());
if (initialMode == "mono")
{
QMutexLocker locker(&m_latestImageMutex);
m_latestRightImage = QImage();
emit uiShowRightImage(QImage());
}
m_pReceiver->SetEventCallback([this](WDRemoteEventType ev, const std::string& msg) {
QString s;
switch (ev)
{
case WDRemoteEventType::CONNECTED: s = "已连接"; emit uiUpdateConnectState(true); break;
case WDRemoteEventType::DISCONNECTED: s = "已断开"; emit uiUpdateConnectState(false); break;
case WDRemoteEventType::CONNECTION_ERROR: s = "连接错误"; emit uiUpdateConnectState(false); break;
case WDRemoteEventType::REQUEST_TIMEOUT: s = "请求超时"; break;
default: s = "未知事件"; break;
}
emit uiAppendLog(QString("[事件] %1 %2").arg(s, QString::fromStdString(msg)));
});
m_pReceiver->SetDetectionCallback([this](const WDRemoteDetectionFrame& f) {
QString s = QString("success=%1 code=%2 frame=%3 ts=%4 boxes=%5 wh=%6x%7 msg=%8")
.arg(f.success ? 1 : 0)
.arg(f.errorCode)
.arg(f.frameId).arg(f.timestampUs)
.arg(static_cast<int>(f.boxes.size()))
.arg(f.imageWidth).arg(f.imageHeight)
.arg(QString::fromStdString(f.message));
emit uiShowDetection(s);
});
// 原始图像回调mono 模式下右目为空,只刷新左图并清空右图。
m_pReceiver->SetRawImageCallback([this](const WDRemoteBinocularRawImage& img) {
// 左目
WDRemoteRawImage leftImg;
leftImg.frameId = img.frameId;
leftImg.timestampUs = img.timestampUs;
leftImg.width = img.leftWidth;
leftImg.height = img.leftHeight;
leftImg.stride = img.leftStride;
leftImg.pixelFormat = img.leftPixelFormat;
leftImg.data = img.leftData;
leftImg.dataSize = img.leftDataSize;
QImage qLeft = rawImageToQImage(leftImg);
if (!qLeft.isNull())
{
{
QMutexLocker locker(&m_latestImageMutex);
m_latestLeftImage = qLeft;
}
emit uiShowLeftImage(qLeft);
}
// 右目(单目模式下右眼为空)
if (!m_monoImageMode.load() && img.rightData && img.rightDataSize > 0)
{
WDRemoteRawImage rightImg;
rightImg.frameId = img.frameId;
rightImg.timestampUs = img.timestampUs;
rightImg.width = img.rightWidth;
rightImg.height = img.rightHeight;
rightImg.stride = img.rightStride;
rightImg.pixelFormat = img.rightPixelFormat;
rightImg.data = img.rightData;
rightImg.dataSize = img.rightDataSize;
QImage qRight = rawImageToQImage(rightImg);
if (!qRight.isNull())
{
{
QMutexLocker locker(&m_latestImageMutex);
m_latestRightImage = qRight;
}
emit uiShowRightImage(qRight);
}
}
else
{
{
QMutexLocker locker(&m_latestImageMutex);
m_latestRightImage = QImage();
}
if (!m_monoImageMode.load())
emit uiShowRightImage(QImage());
}
});
}
void MainWindow::releaseReceiver()
{
if (m_pReceiver)
{
m_pReceiver->Disconnect();
delete m_pReceiver;
m_pReceiver = nullptr;
}
}
// ====================== UI 槽 ======================
void MainWindow::onSearchClicked()
{
if (!m_pReceiver) return;
m_devices.clear();
ui->listDevices->clear();
ui->btnConnect->setEnabled(false);
int r = m_pReceiver->SearchDevices(m_devices, 500);
emit uiAppendLog(QString("SearchDevices ret=%1 count=%2")
.arg(r)
.arg(static_cast<int>(m_devices.size())));
if (r != 0 || m_devices.empty())
{
ui->listDevices->addItem(QStringLiteral("未搜索到设备"));
return;
}
for (size_t i = 0; i < m_devices.size(); ++i)
{
const WDRemoteDeviceInfo& dev = m_devices[i];
const QString text = QString("%1 | %2 | %3 | ctrl:%4 result:%5 raw:%6 | det:%7fps stream:%8fps streamCam:%9 image:%10")
.arg(QString::fromStdString(dev.deviceName))
.arg(QString::fromStdString(dev.machineCode))
.arg(QString::fromStdString(dev.serverIp))
.arg(dev.controlPort)
.arg(dev.resultPort)
.arg(dev.rawImagePort)
.arg(dev.detectFps, 0, 'f', 1)
.arg(dev.streamFps, 0, 'f', 1)
.arg(QString::fromStdString(dev.streamCamera))
.arg(QString::fromStdString(dev.detectMode));
ui->listDevices->addItem(text);
}
ui->btnConnect->setEnabled(true);
ui->listDevices->setCurrentRow(0);
}
void MainWindow::onDeviceSelected(int index)
{
if (index < 0 || index >= static_cast<int>(m_devices.size()))
{
ui->btnConnect->setEnabled(false);
return;
}
ui->btnConnect->setEnabled(true);
const WDRemoteDeviceInfo& dev = m_devices[static_cast<size_t>(index)];
emit uiAppendLog(QString("Selected device machine=%1 name=%2 ip=%3 ctrl=%4 result=%5 raw=%6")
.arg(QString::fromStdString(dev.machineCode))
.arg(QString::fromStdString(dev.deviceName))
.arg(QString::fromStdString(dev.serverIp))
.arg(dev.controlPort)
.arg(dev.resultPort)
.arg(dev.rawImagePort));
}
void MainWindow::onConnectClicked()
{
if (!m_pReceiver) return;
if (m_devices.empty())
{
emit uiAppendLog(QStringLiteral("Open skipped: search device first"));
return;
}
int index = ui->listDevices->currentRow();
if (index < 0 || index >= static_cast<int>(m_devices.size()))
{
emit uiAppendLog(QStringLiteral("Open skipped: select a device first"));
return;
}
const WDRemoteDeviceInfo dev = m_devices[static_cast<size_t>(index)];
int r = m_pReceiver->Open(dev.machineCode, 3000);
emit uiAppendLog(QString("Open(machine=%1) ret=%2")
.arg(QString::fromStdString(dev.machineCode))
.arg(r));
if (r == 0 && m_pDetectModeCombo)
{
const QString mode = m_pDetectModeCombo->currentData().toString();
m_monoImageMode.store(mode == "mono");
m_pReceiver->SetDetectMode(mode.toStdString());
if (mode == "mono")
{
QMutexLocker locker(&m_latestImageMutex);
m_latestRightImage = QImage();
emit uiShowRightImage(QImage());
}
emit uiAppendLog(QString("SetDetectMode after open=%1").arg(mode));
}
}
void MainWindow::onDisconnectClicked()
{
if (!m_pReceiver) return;
int r = m_pReceiver->Disconnect();
emit uiAppendLog(QString("Disconnect ret=%1").arg(r));
}
void MainWindow::onLiveStreamClicked()
{
if (!m_pReceiver) return;
int r = m_pReceiver->StartWork(WDRemoteWorkMode::LiveStream);
emit uiAppendLog(QString("StartWork(LiveStream) ret=%1").arg(r));
}
void MainWindow::onStartWorkClicked()
{
if (!m_pReceiver) return;
// 应用当前选择的检测模式
if (m_pDetectModeCombo)
{
QString mode = m_pDetectModeCombo->currentData().toString();
m_monoImageMode.store(mode == "mono");
m_pReceiver->SetDetectMode(mode.toStdString());
if (mode == "mono")
{
QMutexLocker locker(&m_latestImageMutex);
m_latestRightImage = QImage();
emit uiShowRightImage(QImage());
}
emit uiAppendLog(QString("SetDetectMode=%1").arg(mode));
}
int r = m_pReceiver->StartWork(WDRemoteWorkMode::Detection);
emit uiAppendLog(QString("StartWork(Detection) ret=%1").arg(r));
}
void MainWindow::onStopWorkClicked()
{
if (!m_pReceiver) return;
int r = m_pReceiver->StopWork();
emit uiAppendLog(QString("StopWork ret=%1 (已自动停止订阅)").arg(r));
}
void MainWindow::onSingleClicked()
{
if (!m_pReceiver) return;
if (m_singleInProgress)
{
emit uiAppendLog(QStringLiteral("Single ignored: request already running"));
return;
}
m_singleInProgress = true;
ui->btnSingle->setEnabled(false);
int r = m_pReceiver->RequestSingleDetection(15000);
emit uiAppendLog(QString("Single ret=%1").arg(r));
ui->btnSingle->setEnabled(true);
m_singleInProgress = false;
}
void MainWindow::onSetExposureClicked()
{
if (!m_pReceiver) return;
const WDRemoteServerInfo info = m_pReceiver->GetServerInfo();
const double current = info.ok
? (info.leftExposure > 0.0
? info.leftExposure
: (info.rightExposure > 0.0 ? info.rightExposure : 10000.0))
: 10000.0;
const QString label = info.ok
? QStringLiteral("曝光时间(us),当前 L/R=%1/%2:")
.arg(info.leftExposure, 0, 'f', 1)
.arg(info.rightExposure, 0, 'f', 1)
: QStringLiteral("曝光时间(us):");
if (!info.ok)
emit uiAppendLog(QStringLiteral("GetServerInfo failed before SetExposure, use default value"));
bool ok = false;
double v = QInputDialog::getDouble(this, QStringLiteral("曝光时间(us)"),
label, current,
0.0, 1e9, 3, &ok);
if (!ok) return;
int r = m_pReceiver->SetExposure(v);
emit uiAppendLog(QString("SetExposure(%1) ret=%2").arg(v).arg(r));
}
void MainWindow::onSetGainClicked()
{
if (!m_pReceiver) return;
const WDRemoteServerInfo info = m_pReceiver->GetServerInfo();
const double current = info.ok
? (info.leftGain > 0.0
? info.leftGain
: (info.rightGain > 0.0 ? info.rightGain : 1.0))
: 1.0;
const QString label = info.ok
? QStringLiteral("增益,当前 L/R=%1/%2:")
.arg(info.leftGain, 0, 'f', 2)
.arg(info.rightGain, 0, 'f', 2)
: QStringLiteral("增益:");
if (!info.ok)
emit uiAppendLog(QStringLiteral("GetServerInfo failed before SetGain, use default value"));
bool ok = false;
double v = QInputDialog::getDouble(this, QStringLiteral("增益"),
label, current,
0.0, 1000.0, 3, &ok);
if (!ok) return;
int r = m_pReceiver->SetGain(v);
emit uiAppendLog(QString("SetGain(%1) ret=%2").arg(v).arg(r));
}
void MainWindow::onSetAlgoParamsClicked()
{
if (!m_pReceiver) return;
WDRemoteAlgoParams p;
p.scoreThreshold = 0.5f;
p.nmsThreshold = 0.45f;
p.inputWidth = 640;
p.inputHeight = 640;
p.modelType = 0;
int r = m_pReceiver->SetAlgoParams(p);
emit uiAppendLog(QString("SetAlgoParams ret=%1").arg(r));
}
void MainWindow::onGetInfoClicked()
{
if (!m_pReceiver) return;
WDRemoteServerInfo info = m_pReceiver->GetServerInfo();
QString s = QString("GetInfo ok=%1 mode=%2 imageMode=%3 streamCam=%4 rtsp=%5 raw=%6 result=%7 ctrl=%8 detFps=%9 streamFps=%10 stream=%11x%12 exp(L/R)=%13/%14 gain(L/R)=%15/%16")
.arg(info.ok)
.arg(QString::fromStdString(info.mode))
.arg(QString::fromStdString(info.detectMode))
.arg(QString::fromStdString(info.streamCamera))
.arg(QString::fromStdString(info.rtspUrl))
.arg(info.rawImagePort)
.arg(info.resultPort)
.arg(info.controlPort)
.arg(info.detectFps, 0, 'f', 1)
.arg(info.streamFps, 0, 'f', 1)
.arg(info.streamWidth)
.arg(info.streamHeight)
.arg(info.leftExposure, 0, 'f', 1)
.arg(info.rightExposure, 0, 'f', 1)
.arg(info.leftGain, 0, 'f', 2)
.arg(info.rightGain, 0, 'f', 2);
emit uiAppendLog(s);
emit uiAppendLog(QString("Camera L index=%1 serial=%2 | R index=%3 serial=%4")
.arg(info.leftCameraIndex)
.arg(QString::fromStdString(info.leftCameraSerial))
.arg(info.rightCameraIndex)
.arg(QString::fromStdString(info.rightCameraSerial)));
const WDRemoteCalibrationInfo& calib = info.calibration;
emit uiAppendLog(QString("Calibration valid=%1 source=%2 msg=%3")
.arg(calib.valid ? 1 : 0)
.arg(QString::fromStdString(calib.sourcePath))
.arg(QString::fromStdString(calib.message)));
emit uiAppendLog(QString("Calibration L valid=%1 image=%2x%3 rms=%4 K[0]=[%5]")
.arg(calib.left.valid ? 1 : 0)
.arg(calib.left.imageWidth)
.arg(calib.left.imageHeight)
.arg(calib.left.rms, 0, 'f', 6)
.arg(matrixFirstRowText(calib.left.cameraMatrix)));
emit uiAppendLog(QString("Calibration R valid=%1 image=%2x%3 rms=%4 K[0]=[%5]")
.arg(calib.right.valid ? 1 : 0)
.arg(calib.right.imageWidth)
.arg(calib.right.imageHeight)
.arg(calib.right.rms, 0, 'f', 6)
.arg(matrixFirstRowText(calib.right.cameraMatrix)));
emit uiAppendLog(QString("Calibration stereo valid=%1 baselineMm=%2 R=%3x%4 Q=%5x%6")
.arg(calib.stereo.valid ? 1 : 0)
.arg(calib.stereo.baselineMm, 0, 'f', 3)
.arg(calib.stereo.R.rows)
.arg(calib.stereo.R.cols)
.arg(calib.stereo.Q.rows)
.arg(calib.stereo.Q.cols));
}
void MainWindow::onCustomCmdClicked()
{
if (!m_pReceiver) return;
bool ok = false;
QString req = QInputDialog::getText(this, QStringLiteral("自定义 JSON 命令"),
QStringLiteral("JSON:"),
QLineEdit::Normal,
R"({"cmd":"get_info"})", &ok);
if (!ok || req.isEmpty()) return;
std::string resp;
int r = m_pReceiver->SendCustomCommand(req.toStdString(), resp);
emit uiAppendLog(QString("Custom ret=%1 resp=%2").arg(r).arg(QString::fromStdString(resp)));
}
void MainWindow::onSwapCamerasClicked()
{
if (!m_pReceiver) return;
const auto ret = QMessageBox::question(
this,
QStringLiteral("交换左右目"),
QStringLiteral("请先停止检测和实时传图。\n确认交换服务端逻辑 left/right 相机配置并重连相机?"),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::No);
if (ret != QMessageBox::Yes)
return;
std::string resp;
const int r = m_pReceiver->SendCustomCommand(R"({"cmd":"swap_cameras"})", resp, 10000);
emit uiAppendLog(QString("SwapCameras ret=%1 resp=%2")
.arg(r)
.arg(QString::fromStdString(resp)));
if (r == 0)
onGetInfoClicked();
}
void MainWindow::onChooseSaveDirClicked()
{
QString current = ui->editSaveDir->text().trimmed();
if (current.isEmpty())
current = m_saveImageDir.isEmpty() ? QDir::currentPath() : m_saveImageDir;
const QString dir = QFileDialog::getExistingDirectory(
this, QStringLiteral("选择图像保存路径"), current);
if (dir.isEmpty())
return;
m_saveImageDir = dir;
ui->editSaveDir->setText(dir);
emit uiAppendLog(QString("Save image dir=%1").arg(dir));
}
void MainWindow::onSaveImagesClicked()
{
QString dirPath = ui->editSaveDir->text().trimmed();
if (dirPath.isEmpty())
dirPath = m_saveImageDir.isEmpty() ? QDir::currentPath() : m_saveImageDir;
QDir dir(dirPath);
if (!dir.exists() && !QDir().mkpath(dirPath))
{
emit uiAppendLog(QString("Save images failed: create dir %1").arg(dirPath));
return;
}
m_saveImageDir = dirPath;
QImage left;
QImage right;
{
QMutexLocker locker(&m_latestImageMutex);
left = m_latestLeftImage;
right = m_latestRightImage;
}
if (left.isNull() && right.isNull())
{
emit uiAppendLog(QStringLiteral("Save images skipped: no image received"));
return;
}
int seq = m_saveImageSeq;
QString seqText;
do
{
seqText = QString::number(seq);
++seq;
} while (dir.exists(QString("LeftImage_%1.png").arg(seqText)) ||
dir.exists(QString("RightImage_%1.png").arg(seqText)));
m_saveImageSeq = seq;
bool ok = true;
QStringList saved;
if (!left.isNull())
{
const QString path = dir.filePath(QString("LeftImage_%1.png").arg(seqText));
ok = left.save(path, "PNG") && ok;
saved << path;
}
if (!right.isNull())
{
const QString path = dir.filePath(QString("RightImage_%1.png").arg(seqText));
ok = right.save(path, "PNG") && ok;
saved << path;
}
emit uiAppendLog(QString("Save images %1: %2")
.arg(ok ? QStringLiteral("ok") : QStringLiteral("failed"))
.arg(saved.join(QStringLiteral(", "))));
}
void MainWindow::onDetectModeChanged(int index)
{
if (!m_pReceiver || !m_pDetectModeCombo) return;
QString mode = m_pDetectModeCombo->itemData(index).toString();
m_monoImageMode.store(mode == "mono");
m_pReceiver->SetDetectMode(mode.toStdString());
if (mode == "mono")
{
QMutexLocker locker(&m_latestImageMutex);
m_latestRightImage = QImage();
emit uiShowRightImage(QImage());
}
emit uiAppendLog(QString("DetectMode changed to: %1 (image=%2)")
.arg(mode, mode == "mono"
? QStringLiteral("仅左目")
: QStringLiteral("左右目")));
}
// ====================== UI 显示 ======================
void MainWindow::onAppendLog(const QString& line)
{
if (ui->textLog)
{
ui->textLog->append(line);
}
}
void MainWindow::onShowDetection(const QString& summary)
{
emit uiAppendLog(QString("[结果] %1").arg(summary));
}
void MainWindow::onShowLeftImage(const QImage& img)
{
if (img.isNull()) return;
QPixmap pm = QPixmap::fromImage(img);
if (pm.size() != ui->labelLeftImage->size())
pm = pm.scaled(ui->labelLeftImage->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
ui->labelLeftImage->setPixmap(pm);
}
void MainWindow::onShowRightImage(const QImage& img)
{
if (m_monoImageMode.load() || img.isNull())
{
ui->labelRightImage->clear();
ui->labelRightImage->setText(QStringLiteral("单目图像模式:未传输右图像"));
return;
}
QPixmap pm = QPixmap::fromImage(img);
if (pm.size() != ui->labelRightImage->size())
pm = pm.scaled(ui->labelRightImage->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
ui->labelRightImage->setPixmap(pm);
}
void MainWindow::onUpdateConnectState(bool connected)
{
ui->lblConnState->setText(connected ? QStringLiteral("已连接") : QStringLiteral("已断开"));
ui->lblConnState->setStyleSheet(connected ? "color: green;" : "color: red;");
}
// ====================== 工具 ======================
QImage MainWindow::rawImageToQImage(const WDRemoteRawImage& img)
{
if (!img.data || img.width <= 0 || img.height <= 0) return QImage();
// 这里仅处理常见三种格式BayerRG8 / NV12 留给上层后续按需扩展
switch (img.pixelFormat)
{
case WDRemotePixelFormat::MONO8:
{
QImage q(img.data, img.width, img.height, img.stride,
QImage::Format_Grayscale8);
return q.copy();
}
case WDRemotePixelFormat::RGB8:
{
QImage q(img.data, img.width, img.height, img.stride,
QImage::Format_RGB888);
return q.copy();
}
case WDRemotePixelFormat::BGR8:
{
QImage q(img.data, img.width, img.height, img.stride,
QImage::Format_RGB888);
return q.rgbSwapped();
}
default:
return QImage();
}
}