696 lines
26 KiB
C++
Raw Normal View History

2026-06-26 17:55:15 +08:00
#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();
}
}