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

View File

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

View File

@ -18,11 +18,9 @@ DialogCamSet::~DialogCamSet()
void DialogCamSet::on_pushButton_2_clicked()
{
QString portName = ui->comboBox->currentText();
if(!ph->openPort(portName)){
QMessageBox::critical(this,"Error","Connect "+portName +" Failed");
}else{
QMessageBox::information(this,"Success","Connect "+portName +" Successfully");
if (!ph->openPort(portName)) {
QMessageBox::critical(this, "Error", "Connect " + portName + " Failed");
} else {
QMessageBox::information(this, "Success", "Connect " + portName + " Successfully");
}
}

View File

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

View File

@ -6,18 +6,16 @@ MainWindow::MainWindow(QWidget *parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
cam1 = new CamHandler();
cam2 = new CamHandler();
connect(cam1,&CamHandler::logMsg,this,&MainWindow::onLogPrint1);
connect(cam1,&CamHandler::imageReady,this,&MainWindow::picUpdate1);
cam1 = new CamHandler("cam1",this);
cam2 = new CamHandler("cam2",this);
connect(cam1, &CamHandler::logMsg, this, &MainWindow::onLogPrint1);
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);
ui->graphicsView->setScene(m_scene1);
m_imageItem1 = nullptr; // 初始化图像项指针
}
MainWindow::~MainWindow()
@ -29,23 +27,20 @@ void MainWindow::onLogPrint1(const QString &msg)
{
QDateTime currentDateTime = QDateTime::currentDateTime();
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)
{
QDateTime currentDateTime = QDateTime::currentDateTime();
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)
{
// onLogPrint1("here rev");
if (image.isNull())
{
if (image.isNull()) {
qWarning() << "Received null image.";
return;
}
@ -57,8 +52,7 @@ void MainWindow::picUpdate1(const QImage &image)
QPixmap pixmap = QPixmap::fromImage(image);
// 2. 将 QPixmap 放入 QGraphicsPixmapItem 中
if (m_imageItem1 == nullptr)
{
if (m_imageItem1 == nullptr) {
// 第一次显示图像:创建 QGraphicsPixmapItem 并添加到 Scene
m_imageItem1 = m_scene1->addPixmap(pixmap);
@ -68,9 +62,7 @@ void MainWindow::picUpdate1(const QImage &image)
// 可选:调整 QGraphicsView 视口以适应图像
// 如果您希望图像完整显示在 View 中,可以调用 fitInView
ui->graphicsView->fitInView(m_scene1->sceneRect(), Qt::KeepAspectRatio);
}
else
{
} else {
// 更新现有图像(更高效):直接更新 QGraphicsPixmapItem 的 QPixmap
m_imageItem1->setPixmap(pixmap);
}
@ -83,10 +75,8 @@ void MainWindow::on_pushButton_2_clicked()
{
dc = new DialogCamSet(this);
dc->show();
}
void MainWindow::on_pushButton_3_clicked()
{
@ -97,7 +87,7 @@ void MainWindow::on_pushButton_3_clicked()
// }
// cam1->connectToDevice("28B702523408");
if(!cam1->connectToDevice("28B702523408")){
if (!cam1->connectToDevice("28B702523408")) {
onLogPrint1("open failed");
return;
}
@ -107,53 +97,41 @@ void MainWindow::on_pushButton_3_clicked()
// return;
// }
// cam2->startAcquisition();
}
void MainWindow::on_pushButton_4_clicked()
{
if(cam1->state){
if (cam1->state) {
cam1->stopAcquisition();
}else{
} else {
onLogPrint1("Please connect firstly");
}
// cam2->stopAcquisition();
}
void MainWindow::on_pushButton_5_clicked()
{
ui->textBrowser->clear();
}
void MainWindow::on_pushButton_6_clicked()
{
if(cam1->state){
if (cam1->state) {
cam1->startAcquisition();
}else{
} else {
onLogPrint1("Please connect firstly");
}
}
void MainWindow::on_pushButton_clicked()
{
cam1->saveFlag=true;
cam1->saveFlag = true;
onLogPrint1("start saving ...");
}
void MainWindow::on_pushButton_7_clicked()
{
cam1->saveFlag=false;
cam1->saveFlag = false;
onLogPrint1("stop saving ...");
}

View File

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

View File

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

View File

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

View File

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

View File

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