修改BUG:保存图像数据,分相机保存

This commit is contained in:
leo 2025-10-24 19:04:46 +08:00
parent c96fc7fb63
commit 92fe7b1345
10 changed files with 149 additions and 203 deletions

View File

@ -4,9 +4,13 @@
// 构造/析构 // 构造/析构
// ---------------------------------------------------------------------------------------------------- // ----------------------------------------------------------------------------------------------------
CamHandler::CamHandler(QObject *parent) CamHandler::CamHandler(const QString &name,QObject *parent)
: QObject(parent), mDevice(nullptr), mStream(nullptr), mDeviceInfo(nullptr) : QObject(parent)
, mDevice(nullptr)
, mStream(nullptr)
, mDeviceInfo(nullptr)
{ {
camName = name; // <<< 增加 camName 的初始化
state = false; state = false;
saveFlag = false; saveFlag = false;
// 连接定时器的超时信号到采集槽 // 连接定时器的超时信号到采集槽
@ -19,16 +23,14 @@ CamHandler::CamHandler(QObject *parent)
CamHandler::~CamHandler() CamHandler::~CamHandler()
{ {
// 确保在销毁对象时清理资源 // 确保在销毁对象时清理资源
if (mStream) if (mStream) {
{
stopAcquisition(); // 确保流和缓冲区已清理 stopAcquisition(); // 确保流和缓冲区已清理
mStream->Close(); mStream->Close();
PvStream::Free(mStream); PvStream::Free(mStream);
mStream = nullptr; mStream = nullptr;
} }
if (mDevice) if (mDevice) {
{
mDevice->Disconnect(); mDevice->Disconnect();
PvDevice::Free(mDevice); PvDevice::Free(mDevice);
mDevice = nullptr; mDevice = nullptr;
@ -53,13 +55,13 @@ QList<QString> CamHandler::listAvailableDevices()
mSystem.Find(); mSystem.Find();
// 遍历发现的设备 // 遍历发现的设备
for (uint32_t i = 0; i < mSystem.GetDeviceCount(); i++) for (uint32_t i = 0; i < mSystem.GetDeviceCount(); i++) {
{
const PvDeviceInfo *lInfo = mSystem.GetDeviceInfo(i); const PvDeviceInfo *lInfo = mSystem.GetDeviceInfo(i);
// 获取设备的显示ID (例如:型号/序列号) // 获取设备的显示ID (例如:型号/序列号)
QString lDisplayID = QString::fromLocal8Bit(lInfo->GetDisplayID().GetAscii()); QString lDisplayID = QString::fromLocal8Bit(lInfo->GetDisplayID().GetAscii());
deviceList.append(lDisplayID + " (ID: " + QString::fromLocal8Bit(lInfo->GetConnectionID().GetAscii()) + ")"); deviceList.append(lDisplayID + " (ID: "
+ QString::fromLocal8Bit(lInfo->GetConnectionID().GetAscii()) + ")");
} }
return deviceList; return deviceList;
@ -68,8 +70,7 @@ QList<QString> CamHandler::listAvailableDevices()
bool CamHandler::connectToDevice(const QString &aConnectionID) bool CamHandler::connectToDevice(const QString &aConnectionID)
{ {
QString errMsg; QString errMsg;
if (mDevice) if (mDevice) {
{
emit logMsg("Already connected. Please disconnect first."); emit logMsg("Already connected. Please disconnect first.");
return false; return false;
} }
@ -78,8 +79,7 @@ bool CamHandler::connectToDevice(const QString &aConnectionID)
// 确保在 selectDevice 前调用 Find() (虽然 listAvailableDevices 可能已经调用,但再次调用更安全) // 确保在 selectDevice 前调用 Find() (虽然 listAvailableDevices 可能已经调用,但再次调用更安全)
mDeviceInfo = selectDevice(aConnectionID); mDeviceInfo = selectDevice(aConnectionID);
if (!mDeviceInfo) if (!mDeviceInfo) {
{
errMsg = "Error: Device not found for ID:" + aConnectionID; errMsg = "Error: Device not found for ID:" + aConnectionID;
emit logMsg(errMsg); emit logMsg(errMsg);
return false; return false;
@ -90,15 +90,14 @@ bool CamHandler::connectToDevice(const QString &aConnectionID)
PvResult lResult; PvResult lResult;
mDevice = PvDevice::CreateAndConnect(mDeviceInfo, &lResult); mDevice = PvDevice::CreateAndConnect(mDeviceInfo, &lResult);
if (mDevice == nullptr) if (mDevice == nullptr) {
{ emit logMsg("Error: Unable to connect to device. Result:"
emit logMsg( "Error: Unable to connect to device. Result:" + QString(lResult.GetCodeString())); + QString(lResult.GetCodeString()));
return false; return false;
} }
// 3. 打开流 // 3. 打开流
if (!openStream()) if (!openStream()) {
{
disconnectDevice(); disconnectDevice();
return false; return false;
} }
@ -118,8 +117,7 @@ void CamHandler::startAcquisition()
{ {
// 5. 创建和队列缓冲区 // 5. 创建和队列缓冲区
createStreamBuffers(); createStreamBuffers();
if (!mDevice || !mStream) if (!mDevice || !mStream) {
{
emit logMsg("Not connected. Cannot start acquisition."); emit logMsg("Not connected. Cannot start acquisition.");
return; return;
} }
@ -128,17 +126,14 @@ void CamHandler::startAcquisition()
PvGenParameterArray *lDeviceParams = mDevice->GetParameters(); PvGenParameterArray *lDeviceParams = mDevice->GetParameters();
PvGenCommand *lStart = dynamic_cast<PvGenCommand *>(lDeviceParams->Get("AcquisitionStart")); PvGenCommand *lStart = dynamic_cast<PvGenCommand *>(lDeviceParams->Get("AcquisitionStart"));
if (lStart != nullptr) if (lStart != nullptr) {
{
emit logMsg("Enabling streaming and sending AcquisitionStart command."); emit logMsg("Enabling streaming and sending AcquisitionStart command.");
mDevice->StreamEnable(); // 启用流 mDevice->StreamEnable(); // 启用流
lStart->Execute(); // 发送命令 lStart->Execute(); // 发送命令
// 3. 启动定时器,驱动采集循环 // 3. 启动定时器,驱动采集循环
mAcquireTimer.start(); mAcquireTimer.start();
} } else {
else
{
emit logMsg("Error: AcquisitionStart command not found on device."); emit logMsg("Error: AcquisitionStart command not found on device.");
} }
} }
@ -149,8 +144,7 @@ void CamHandler::stopAcquisition()
return; return;
// 1. 停止计时器 // 1. 停止计时器
if (mAcquireTimer.isActive()) if (mAcquireTimer.isActive()) {
{
mAcquireTimer.stop(); mAcquireTimer.stop();
emit logMsg("Acquisition timer stopped."); emit logMsg("Acquisition timer stopped.");
} }
@ -160,8 +154,7 @@ void CamHandler::stopAcquisition()
PvGenCommand *lStop = dynamic_cast<PvGenCommand *>(lDeviceParams->Get("AcquisitionStop")); PvGenCommand *lStop = dynamic_cast<PvGenCommand *>(lDeviceParams->Get("AcquisitionStop"));
// 3. 停止采集和禁用流 // 3. 停止采集和禁用流
if (lStop != nullptr) if (lStop != nullptr) {
{
emit logMsg("Sending AcquisitionStop command to the device"); emit logMsg("Sending AcquisitionStop command to the device");
lStop->Execute(); lStop->Execute();
} }
@ -176,8 +169,7 @@ void CamHandler::stopAcquisition()
PvBuffer *lBuffer = NULL; PvBuffer *lBuffer = NULL;
PvResult lOperationResult; PvResult lOperationResult;
// 必须清空队列,防止下次采集时使用错误的旧缓冲区 // 必须清空队列,防止下次采集时使用错误的旧缓冲区
while (mStream->GetQueuedBufferCount() > 0) while (mStream->GetQueuedBufferCount() > 0) {
{
mStream->RetrieveBuffer(&lBuffer, &lOperationResult); mStream->RetrieveBuffer(&lBuffer, &lOperationResult);
// 注意:这里没有释放 lBuffer因为缓冲区资源将在析构或断开时处理 // 注意:这里没有释放 lBuffer因为缓冲区资源将在析构或断开时处理
} }
@ -188,8 +180,7 @@ void CamHandler::stopAcquisition()
void CamHandler::disconnectDevice() void CamHandler::disconnectDevice()
{ {
// 停止采集,清理流资源 // 停止采集,清理流资源
if (mStream) if (mStream) {
{
stopAcquisition(); // 确保流和缓冲区已清理 stopAcquisition(); // 确保流和缓冲区已清理
emit logMsg("Closing stream"); emit logMsg("Closing stream");
mStream->Close(); mStream->Close();
@ -198,8 +189,7 @@ void CamHandler::disconnectDevice()
} }
// 断开设备连接,释放设备资源 // 断开设备连接,释放设备资源
if (mDevice) if (mDevice) {
{
emit logMsg("Disconnecting device"); emit logMsg("Disconnecting device");
mDevice->Disconnect(); mDevice->Disconnect();
PvDevice::Free(mDevice); PvDevice::Free(mDevice);
@ -231,38 +221,29 @@ void CamHandler::onAcquireTimerTimeout()
// 尝试检索下一个缓冲区,使用较短的超时时间 (10ms) // 尝试检索下一个缓冲区,使用较短的超时时间 (10ms)
PvResult lResult = mStream->RetrieveBuffer(&lBuffer, &lOperationResult, 10); PvResult lResult = mStream->RetrieveBuffer(&lBuffer, &lOperationResult, 10);
if (lResult.IsOK()) if (lResult.IsOK()) {
{ if (lOperationResult.IsOK()) {
if (lOperationResult.IsOK())
{
// 成功采集到有效图像 // 成功采集到有效图像
PvPayloadType lType = lBuffer->GetPayloadType(); PvPayloadType lType = lBuffer->GetPayloadType();
if (lType == PvPayloadTypeImage) if (lType == PvPayloadTypeImage) {
{
// 转换为 QImage 并发送信号 // 转换为 QImage 并发送信号
QImage image = convertPvBufferToQImage(lBuffer); QImage image = convertPvBufferToQImage(lBuffer);
if (!image.isNull()) if (!image.isNull()) {
{
emit imageReady(image); emit imageReady(image);
} } else {
else
{
emit logMsg("Image conversion failed."); emit logMsg("Image conversion failed.");
} }
} } else {
else
{
emit logMsg("Buffer retrieved, but does not contain an image payload. Requeuing."); emit logMsg("Buffer retrieved, but does not contain an image payload. Requeuing.");
} }
// 重新排队缓冲区 // 重新排队缓冲区
mStream->QueueBuffer(lBuffer); mStream->QueueBuffer(lBuffer);
} } else {
else
{
// 检索到缓冲区但操作结果不成功(例如:超时、重发过多) // 检索到缓冲区但操作结果不成功(例如:超时、重发过多)
emit logMsg( "RetrieveBuffer operation result is not OK:" + QString(lOperationResult.GetCodeString()) + ". Requeuing."); emit logMsg("RetrieveBuffer operation result is not OK:"
+ QString(lOperationResult.GetCodeString()) + ". Requeuing.");
mStream->QueueBuffer(lBuffer); // 必须重新排队 mStream->QueueBuffer(lBuffer); // 必须重新排队
} }
} }
@ -278,13 +259,11 @@ const PvDeviceInfo *CamHandler::selectDevice(const QString &aConnectionID)
{ {
mSystem.Find(); mSystem.Find();
// mSystem.Find() 已经在 connectToDevice 中调用 // mSystem.Find() 已经在 connectToDevice 中调用
for (uint32_t i = 0; i < mSystem.GetDeviceCount(); i++) for (uint32_t i = 0; i < mSystem.GetDeviceCount(); i++) {
{
const PvDeviceInfo *lInfo = mSystem.GetDeviceInfo(i); // 从成员变量 mSystem 获取 const PvDeviceInfo *lInfo = mSystem.GetDeviceInfo(i); // 从成员变量 mSystem 获取
QString tmp = QString::fromLocal8Bit(lInfo->GetConnectionID().GetAscii()); QString tmp = QString::fromLocal8Bit(lInfo->GetConnectionID().GetAscii());
if (aConnectionID == tmp) if (aConnectionID == tmp) {
{
// 找到匹配的设备,返回的指针由 mSystem 管理,在 CamHandler 生命周期内有效 // 找到匹配的设备,返回的指针由 mSystem 管理,在 CamHandler 生命周期内有效
return lInfo; return lInfo;
} }
@ -300,24 +279,26 @@ bool CamHandler::openStream()
// 使用静态工厂方法 PvStream::CreateAndOpen // 使用静态工厂方法 PvStream::CreateAndOpen
mStream = PvStream::CreateAndOpen(mDeviceInfo->GetConnectionID(), &lResult); mStream = PvStream::CreateAndOpen(mDeviceInfo->GetConnectionID(), &lResult);
if (mStream == nullptr) if (mStream == nullptr) {
{ emit logMsg("Error: Unable to stream from device. Result:"
emit logMsg( "Error: Unable to stream from device. Result:" + QString(lResult.GetCodeString())); + QString(lResult.GetCodeString()));
return false; return false;
} }
return true; return true;
} }
void CamHandler::createStreamBuffers() void CamHandler::createStreamBuffers()
{ {
// 从设备获取 payload size (图像/数据的字节大小) // 从设备获取 payload size (图像/数据的字节大小)
uint32_t lSize = mDevice->GetPayloadSize(); uint32_t lSize = mDevice->GetPayloadSize();
// 确定要创建的缓冲区数量 // 确定要创建的缓冲区数量
uint32_t lBufferCount = (mStream->GetQueuedBufferMaximum() < BUFFER_COUNT) ? mStream->GetQueuedBufferMaximum() : BUFFER_COUNT; uint32_t lBufferCount = (mStream->GetQueuedBufferMaximum() < BUFFER_COUNT)
? mStream->GetQueuedBufferMaximum()
: BUFFER_COUNT;
emit logMsg( "Allocating" + QString::number(lBufferCount) + " buffers of size " + QString::number(lSize) + " bytes."); emit logMsg("Allocating" + QString::number(lBufferCount) + " buffers of size "
+ QString::number(lSize) + " bytes.");
// 分配 PvBuffer 数组 // 分配 PvBuffer 数组
// 注意:在析构函数或 disconnectDevice 中需要释放这个内存! // 注意:在析构函数或 disconnectDevice 中需要释放这个内存!
@ -326,8 +307,7 @@ void CamHandler::createStreamBuffers()
// **重要提示:您的原始代码没有在析构函数中释放 lBuffers 指针!** // 这是一个内存泄漏风险。要解决这个问题,您需要将 lBuffers 存储为一个成员变量 (例如 QList<PvBuffer*>) // **重要提示:您的原始代码没有在析构函数中释放 lBuffers 指针!** // 这是一个内存泄漏风险。要解决这个问题,您需要将 lBuffers 存储为一个成员变量 (例如 QList<PvBuffer*>)
// 或者只在析构函数/disconnectDevice 中确保释放它们。 // 或者只在析构函数/disconnectDevice 中确保释放它们。
for (uint32_t i = 0; i < lBufferCount; i++) for (uint32_t i = 0; i < lBufferCount; i++) {
{
// 为每个缓冲区分配内存 // 为每个缓冲区分配内存
(lBuffers + i)->Alloc(static_cast<uint32_t>(lSize)); (lBuffers + i)->Alloc(static_cast<uint32_t>(lSize));
@ -343,38 +323,28 @@ QImage CamHandler::convertPvBufferToQImage(PvBuffer *aBuffer)
uint32_t lWidth = lImage->GetWidth(); uint32_t lWidth = lImage->GetWidth();
uint32_t lHeight = lImage->GetHeight(); uint32_t lHeight = lImage->GetHeight();
// 使用全局线程池启动任务 (异步执行) // 使用全局线程池启动任务 (异步执行)
// 简化实现:仅支持 Mono8 (8位灰度) 格式 // 简化实现:仅支持 Mono8 (8位灰度) 格式
if (lImage->GetPixelType() == PvPixelMono8) if (lImage->GetPixelType() == PvPixelMono8) {
{
if (saveFlag) { if (saveFlag) {
const void *lDataPointer = lImage->GetDataPointer(); const void *lDataPointer = lImage->GetDataPointer();
quint32 lDataSize = lImage->GetImageSize(); quint32 lDataSize = lImage->GetImageSize();
// 3. 复制原始数据到 QByteArray线程安全的关键 // 3. 复制原始数据到 QByteArray线程安全的关键
QByteArray rawDataCopy( QByteArray rawDataCopy(reinterpret_cast<const char *>(lDataPointer), lDataSize);
reinterpret_cast<const char*>(lDataPointer),
lDataSize
);
// 4. 创建 SaveTask 并提交给全局线程池 // 4. 创建 SaveTask 并提交给全局线程池
SaveTask *task = new SaveTask( SaveTask *task = new SaveTask(rawDataCopy,camName);
rawDataCopy
);
QThreadPool::globalInstance()->start(task); QThreadPool::globalInstance()->start(task);
} }
// 直接使用图像数据创建 QImage // 直接使用图像数据创建 QImage
return QImage( return QImage((uchar *) lImage->GetDataPointer(),
(uchar *)lImage->GetDataPointer(),
lWidth, lWidth,
lHeight, lHeight,
lWidth, // 步长/字节数 lWidth, // 步长/字节数
QImage::Format_Grayscale8 QImage::Format_Grayscale8)
).copy(); // .copy() 确保 QImage 拥有数据,安全地在 Qt 环境中使用 .copy(); // .copy() 确保 QImage 拥有数据,安全地在 Qt 环境中使用
} }
emit logMsg("Unsupported pixel format"); emit logMsg("Unsupported pixel format");

View File

@ -1,25 +1,25 @@
#ifndef CAMHANDLER_H #ifndef CAMHANDLER_H
#define CAMHANDLER_H #define CAMHANDLER_H
#include <QObject>
#include <QString>
#include <QDebug> #include <QDebug>
#include <QImage> // 用于在信号中传输图像数据 #include <QImage> // 用于在信号中传输图像数据
#include <QObject>
#include <QString>
#include <QTimer> // 用于驱动采集循环 #include <QTimer> // 用于驱动采集循环
// eBUS SDK 核心头文件 // eBUS SDK 核心头文件
#include <PvSystem.h> #include <QThreadPool> // 需要包含 QThreadPool
#include "savetask.h"
#include <PvBuffer.h>
#include <PvDevice.h> #include <PvDevice.h>
#include <PvDeviceU3V.h> #include <PvDeviceU3V.h>
#include <PvGenCommand.h>
#include <PvGenParameter.h>
#include <PvGenParameterArray.h>
#include <PvImage.h>
#include <PvStream.h> #include <PvStream.h>
#include <PvStreamU3V.h> #include <PvStreamU3V.h>
#include <PvBuffer.h> #include <PvSystem.h>
#include <PvImage.h>
#include <PvGenParameter.h>
#include <PvGenCommand.h>
#include <PvGenParameterArray.h>
#include "savetask.h"
#include <QThreadPool> // 需要包含 QThreadPool
// 用于流缓冲区数量的定义 (参考例程) // 用于流缓冲区数量的定义 (参考例程)
#define BUFFER_COUNT 16 #define BUFFER_COUNT 16
@ -29,7 +29,7 @@ class CamHandler : public QObject
Q_OBJECT Q_OBJECT
public: public:
explicit CamHandler(QObject *parent = nullptr); explicit CamHandler(const QString &name,QObject *parent = nullptr);
~CamHandler(); ~CamHandler();
// 公有接口:连接/断开/发现 // 公有接口:连接/断开/发现
@ -43,7 +43,7 @@ public:
void stopAcquisition(); void stopAcquisition();
bool state; bool state;
bool saveFlag; bool saveFlag;
QString camName;
// ------------------- 信号 (Signals) ------------------- // ------------------- 信号 (Signals) -------------------
signals: signals:

View File

@ -23,6 +23,4 @@ void DialogCamSet::on_pushButton_2_clicked()
} else { } else {
QMessageBox::information(this, "Success", "Connect " + portName + " Successfully"); QMessageBox::information(this, "Success", "Connect " + portName + " Successfully");
} }
} }

View File

@ -2,8 +2,8 @@
#define DIALOGCAMSET_H #define DIALOGCAMSET_H
#include <QDialog> #include <QDialog>
#include "parameterhandler.h"
#include "QMessageBox" #include "QMessageBox"
#include "parameterhandler.h"
namespace Ui { namespace Ui {
class DialogCamSet; class DialogCamSet;

View File

@ -6,18 +6,16 @@ MainWindow::MainWindow(QWidget *parent)
, ui(new Ui::MainWindow) , ui(new Ui::MainWindow)
{ {
ui->setupUi(this); ui->setupUi(this);
cam1 = new CamHandler(); cam1 = new CamHandler("cam1",this);
cam2 = new CamHandler(); cam2 = new CamHandler("cam2",this);
connect(cam1, &CamHandler::logMsg, this, &MainWindow::onLogPrint1); connect(cam1, &CamHandler::logMsg, this, &MainWindow::onLogPrint1);
connect(cam1, &CamHandler::imageReady, this, &MainWindow::picUpdate1); connect(cam1, &CamHandler::imageReady, this, &MainWindow::picUpdate1);
connect(cam2, &CamHandler::logMsg, this, &MainWindow::onLogPrint2); connect(cam2, &CamHandler::logMsg, this, &MainWindow::onLogPrint2);
m_scene1 = new QGraphicsScene(this); m_scene1 = new QGraphicsScene(this);
ui->graphicsView->setScene(m_scene1); ui->graphicsView->setScene(m_scene1);
m_imageItem1 = nullptr; // 初始化图像项指针 m_imageItem1 = nullptr; // 初始化图像项指针
} }
MainWindow::~MainWindow() MainWindow::~MainWindow()
@ -30,7 +28,6 @@ void MainWindow::onLogPrint1(const QString &msg)
QDateTime currentDateTime = QDateTime::currentDateTime(); QDateTime currentDateTime = QDateTime::currentDateTime();
QString dateTimeString = currentDateTime.toString("yyyy--MM--dd HH-mm-ss"); QString dateTimeString = currentDateTime.toString("yyyy--MM--dd HH-mm-ss");
ui->textBrowser->append(dateTimeString + " [cam1] --> " + msg); ui->textBrowser->append(dateTimeString + " [cam1] --> " + msg);
} }
void MainWindow::onLogPrint2(const QString &msg) void MainWindow::onLogPrint2(const QString &msg)
@ -38,14 +35,12 @@ void MainWindow::onLogPrint2(const QString &msg)
QDateTime currentDateTime = QDateTime::currentDateTime(); QDateTime currentDateTime = QDateTime::currentDateTime();
QString dateTimeString = currentDateTime.toString("yyyy--MM--dd HH-mm-ss"); QString dateTimeString = currentDateTime.toString("yyyy--MM--dd HH-mm-ss");
ui->textBrowser->append(dateTimeString + " [cam2] --> " + msg); ui->textBrowser->append(dateTimeString + " [cam2] --> " + msg);
} }
void MainWindow::picUpdate1(const QImage &image) void MainWindow::picUpdate1(const QImage &image)
{ {
// onLogPrint1("here rev"); // onLogPrint1("here rev");
if (image.isNull()) if (image.isNull()) {
{
qWarning() << "Received null image."; qWarning() << "Received null image.";
return; return;
} }
@ -57,8 +52,7 @@ void MainWindow::picUpdate1(const QImage &image)
QPixmap pixmap = QPixmap::fromImage(image); QPixmap pixmap = QPixmap::fromImage(image);
// 2. 将 QPixmap 放入 QGraphicsPixmapItem 中 // 2. 将 QPixmap 放入 QGraphicsPixmapItem 中
if (m_imageItem1 == nullptr) if (m_imageItem1 == nullptr) {
{
// 第一次显示图像:创建 QGraphicsPixmapItem 并添加到 Scene // 第一次显示图像:创建 QGraphicsPixmapItem 并添加到 Scene
m_imageItem1 = m_scene1->addPixmap(pixmap); m_imageItem1 = m_scene1->addPixmap(pixmap);
@ -68,9 +62,7 @@ void MainWindow::picUpdate1(const QImage &image)
// 可选:调整 QGraphicsView 视口以适应图像 // 可选:调整 QGraphicsView 视口以适应图像
// 如果您希望图像完整显示在 View 中,可以调用 fitInView // 如果您希望图像完整显示在 View 中,可以调用 fitInView
ui->graphicsView->fitInView(m_scene1->sceneRect(), Qt::KeepAspectRatio); ui->graphicsView->fitInView(m_scene1->sceneRect(), Qt::KeepAspectRatio);
} } else {
else
{
// 更新现有图像(更高效):直接更新 QGraphicsPixmapItem 的 QPixmap // 更新现有图像(更高效):直接更新 QGraphicsPixmapItem 的 QPixmap
m_imageItem1->setPixmap(pixmap); m_imageItem1->setPixmap(pixmap);
} }
@ -83,10 +75,8 @@ void MainWindow::on_pushButton_2_clicked()
{ {
dc = new DialogCamSet(this); dc = new DialogCamSet(this);
dc->show(); dc->show();
} }
void MainWindow::on_pushButton_3_clicked() void MainWindow::on_pushButton_3_clicked()
{ {
@ -107,13 +97,9 @@ void MainWindow::on_pushButton_3_clicked()
// return; // return;
// } // }
// cam2->startAcquisition(); // cam2->startAcquisition();
} }
void MainWindow::on_pushButton_4_clicked() void MainWindow::on_pushButton_4_clicked()
{ {
if (cam1->state) { if (cam1->state) {
@ -124,13 +110,11 @@ void MainWindow::on_pushButton_4_clicked()
// cam2->stopAcquisition(); // cam2->stopAcquisition();
} }
void MainWindow::on_pushButton_5_clicked() void MainWindow::on_pushButton_5_clicked()
{ {
ui->textBrowser->clear(); ui->textBrowser->clear();
} }
void MainWindow::on_pushButton_6_clicked() void MainWindow::on_pushButton_6_clicked()
{ {
if (cam1->state) { if (cam1->state) {
@ -140,20 +124,14 @@ void MainWindow::on_pushButton_6_clicked()
} }
} }
void MainWindow::on_pushButton_clicked() void MainWindow::on_pushButton_clicked()
{ {
cam1->saveFlag = true; cam1->saveFlag = true;
onLogPrint1("start saving ..."); onLogPrint1("start saving ...");
} }
void MainWindow::on_pushButton_7_clicked() void MainWindow::on_pushButton_7_clicked()
{ {
cam1->saveFlag = false; cam1->saveFlag = false;
onLogPrint1("stop saving ..."); onLogPrint1("stop saving ...");
} }

View File

@ -1,13 +1,12 @@
#ifndef MAINWINDOW_H #ifndef MAINWINDOW_H
#define MAINWINDOW_H #define MAINWINDOW_H
#include <QMainWindow>
#include "dialogcamset.h"
#include "camhandler.h"
#include "QDateTime"
#include <QGraphicsScene>
#include <QGraphicsPixmapItem> #include <QGraphicsPixmapItem>
#include <QGraphicsScene>
#include <QMainWindow>
#include "QDateTime"
#include "camhandler.h"
#include "dialogcamset.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
namespace Ui { namespace Ui {
@ -28,7 +27,6 @@ public slots:
void onLogPrint2(const QString &msg); void onLogPrint2(const QString &msg);
void picUpdate1(const QImage &image); void picUpdate1(const QImage &image);
private slots: private slots:
void on_pushButton_2_clicked(); void on_pushButton_2_clicked();
@ -52,6 +50,5 @@ private:
QGraphicsScene *m_scene1; QGraphicsScene *m_scene1;
QGraphicsPixmapItem *m_imageItem1; // 用于保存图像项的指针 QGraphicsPixmapItem *m_imageItem1; // 用于保存图像项的指针
}; };
#endif // MAINWINDOW_H #endif // MAINWINDOW_H

View File

@ -1,22 +1,23 @@
#include "ParameterHandler.h" #include "ParameterHandler.h"
#include <QDebug>
#include <QCoreApplication> #include <QCoreApplication>
#include <QDebug>
#include <QThread> #include <QThread>
ParameterHandler::ParameterHandler(QObject *parent) ParameterHandler::ParameterHandler(QObject *parent)
: QObject(parent), m_serialPort(new QSerialPort(this)) : QObject(parent)
, m_serialPort(new QSerialPort(this))
{ {
// 将 QSerialPort 的 readyRead 信号连接到槽函数,用于数据接收 // 将 QSerialPort 的 readyRead 信号连接到槽函数,用于数据接收
connect(m_serialPort, &QSerialPort::readyRead, connect(m_serialPort, &QSerialPort::readyRead, this, &ParameterHandler::handleReadyRead);
this, &ParameterHandler::handleReadyRead);
// 将 QSerialPort 的 errorOccurred 信号连接到槽函数,用于错误处理 // 将 QSerialPort 的 errorOccurred 信号连接到槽函数,用于错误处理
// 使用 QOverload 确保连接到正确的重载函数 // 使用 QOverload 确保连接到正确的重载函数
connect(m_serialPort, QOverload<QSerialPort::SerialPortError>::of(&QSerialPort::errorOccurred), connect(m_serialPort,
this, &ParameterHandler::handleError); QOverload<QSerialPort::SerialPortError>::of(&QSerialPort::errorOccurred),
this,
&ParameterHandler::handleError);
} }
ParameterHandler::~ParameterHandler() ParameterHandler::~ParameterHandler()
{ {
// 析构时确保串口关闭 // 析构时确保串口关闭
@ -51,7 +52,8 @@ bool ParameterHandler::openPort(const QString &portName)
// 1. 尝试打开串口,以读写模式 // 1. 尝试打开串口,以读写模式
if (!m_serialPort->open(QIODevice::ReadWrite)) { if (!m_serialPort->open(QIODevice::ReadWrite)) {
QString errorMsg = QString("无法打开串口 %1: %2").arg(portName).arg(m_serialPort->errorString()); QString errorMsg
= QString("无法打开串口 %1: %2").arg(portName).arg(m_serialPort->errorString());
qWarning() << errorMsg; qWarning() << errorMsg;
emit errorOccurred(errorMsg); emit errorOccurred(errorMsg);
return false; return false;

View File

@ -1,11 +1,11 @@
#ifndef PARAMETERHANDLER_H #ifndef PARAMETERHANDLER_H
#define PARAMETERHANDLER_H #define PARAMETERHANDLER_H
#include <QByteArray>
#include <QObject> #include <QObject>
#include <QSerialPort> #include <QSerialPort>
#include <QByteArray>
#include <QString>
#include <QSerialPortInfo> // <-- 增加此头文件 #include <QSerialPortInfo> // <-- 增加此头文件
#include <QString>
class ParameterHandler : public QObject class ParameterHandler : public QObject
{ {

View File

@ -1,30 +1,35 @@
// SaveTask.cpp 文件中
#include "SaveTask.h" #include "SaveTask.h"
// 实际的 run() 方法在 SaveTask.cpp 中实现
void SaveTask::run() void SaveTask::run()
{ {
if (m_rawData.isEmpty()) if (m_rawData.isEmpty())
{ {
qWarning("SaveTask received empty raw data. Aborting save."); qWarning("SaveTask for camera %s received empty raw data. Aborting save.", qPrintable(m_camName));
return; return;
} }
// --- 耗时的文件 I/O 操作在此处执行,不阻塞主线程 --- // --- 耗时的文件 I/O 操作在此处执行,在线程池中 ---
QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_hhmmsszzz"); QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_hhmmsszzz");
// 构造文件名时间戳_宽度x高度_像素类型.raw // 构造文件名相机名称_时间戳.raw
QString filename = QString("%1.raw") QString filename = QString("%1_%2.raw")
.arg(m_camName)
.arg(timestamp); .arg(timestamp);
// 使用相机名称创建保存路径的子目录
// 设置保存路径 QString savePath = QDir::currentPath() + "/RawSavedImages/" + m_camName + "/"; // <<< 增加目录
QString savePath = QDir::currentPath() + "/RawSavedImages/";
QDir dir(savePath); QDir dir(savePath);
if (!dir.exists()) if (!dir.exists())
{ {
dir.mkpath("."); if (!dir.mkpath("."))
{
qWarning("Error: Failed to create save directory: %s", qPrintable(savePath));
return;
}
} }
QString fullPath = savePath + filename; QString fullPath = savePath + filename;
@ -36,16 +41,12 @@ void SaveTask::run()
qint64 bytesWritten = file.write(m_rawData); qint64 bytesWritten = file.write(m_rawData);
file.close(); file.close();
if (bytesWritten == m_rawData.size()) if (bytesWritten != m_rawData.size())
{
// 保存成功,可以发送日志或简单地使用 qInfo()
// qInfo() << "Raw data saved successfully to:" << fullPath;
}
else
{ {
qWarning() << QString("Error: Only %1 of %2 bytes written to %3") qWarning() << QString("Error: Only %1 of %2 bytes written to %3")
.arg(bytesWritten).arg(m_rawData.size()).arg(fullPath); .arg(bytesWritten).arg(m_rawData.size()).arg(fullPath);
} }
// else { qInfo() << "Raw data saved successfully to:" << fullPath; }
} }
else else
{ {

View File

@ -1,12 +1,12 @@
#ifndef SAVETASK_H #ifndef SAVETASK_H
#define SAVETASK_H #define SAVETASK_H
#include <QRunnable>
#include <QByteArray> #include <QByteArray>
#include <QDebug>
#include <QDateTime> #include <QDateTime>
#include <QDebug>
#include <QDir> #include <QDir>
#include <QFile> #include <QFile>
#include <QRunnable>
/** /**
* @brief SaveTask * @brief SaveTask
@ -22,8 +22,8 @@ public:
* @param height * @param height
* @param pixelType PvPixelMono8 * @param pixelType PvPixelMono8
*/ */
SaveTask(const QByteArray &data) SaveTask(const QByteArray &data, const QString &camName)
: m_rawData(data) : m_rawData(data), m_camName(camName) // <<< 增加 camName 的初始化
{ {
// 设置为 true以便任务执行完成后QThreadPool 自动清理内存 // 设置为 true以便任务执行完成后QThreadPool 自动清理内存
setAutoDelete(true); setAutoDelete(true);
@ -36,7 +36,7 @@ public:
private: private:
QByteArray m_rawData; QByteArray m_rawData;
QString m_camName; // <<< 增加成员变量来存储相机名称
}; };
#endif // SAVETASK_H #endif // SAVETASK_H