add callback imaging

This commit is contained in:
kaiza_hikaru 2025-06-07 16:14:00 +08:00
parent e89cf3b359
commit ed0895405a
6 changed files with 181 additions and 93 deletions

27
CMakeSettings.json Normal file
View File

@ -0,0 +1,27 @@
{
"configurations": [
{
"name": "x64-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": ""
},
{
"name": "x64-Release",
"generator": "Ninja",
"configurationType": "Release",
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": "",
"inheritEnvironments": [ "msvc_x64_x64" ],
"variables": []
}
]
}

106
LLM.md
View File

@ -1,88 +1,30 @@
请帮助我生成一个C++编写的Qt UI代码使用`initUI()`函数实现UI的创建具体要求如下 请结合手册提供的回调函数注册代码,使用 lambda 函数的方式,实现类 `` 中的注册回调函数功能
这个类的签名为`class HikWidget`继承自QWidget
整个UI分为左右两部分水平分布比例为3:1开始时设置窗口大小为1280x720
左侧为一个QGraphicsView控件为类成员变量`QGraphicsView *m_gv`,后面如无特殊说明类内成员变量都应当以`m_`开头
右侧为三个groupbox这三个groupbox垂直分布这里可以使用局部变量从上到下分别显示文字为“相机操作”、“图像保存”、“相机参数”
“相机操作”groupbox中为一个2x2表格布局里面有四个pushButton控件从左到右从上倒下分别显示“打开相机”、“关闭相机”、“开始取流”、“结束取流”
这几个pushButton声明为成员变量并根据控件属性和提示文字含义帮我取变量名例如“打开相机”对应`QPushBotton *m_btn_opencamera`
“图像保存”groupbox中为一个水平布局包括一个只读的lineEditor、一个comboBox、两个pushBotton这四个控件都应该是成员变量
lineEditor中显示保存文件路径comboBox选择保存图像格式至少有`.jpg`, `.png`, `.tif`, `.bmp`几个选项
两个pushButton显示文字为“打开...”和“保存”一个负责选择保存路径一个实际执行保存行为initUI时不考虑信号与槽
最后“相机参数”groupbox中为一个2x2的表格布局每一行都是一个label和一个doubelSpinBox其中两个spin应当为成员变量
第一行的label显示文字“曝光时间对应第一行的spin设置的是曝光时间
第二行的label显示文字“增益设置对应第二行的spin设置的是增益
---
我希望将图像保存GroupBox修改一下设计将这个GroupBox修改为2x3表格布局
第一行3列合并显示m_edit_savePath第二行分别显示m_cmb_imgFormat、m_btn_openDir、m_btn_saveImage
```cpp ```cpp
// 图像保存GroupBox /* 相机 SDK 示例代码 */
QGroupBox *saveGroup = new QGroupBox("图像保存", rightPanel); void __stdcall ImageCallBackEx(unsigned char * pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser)
QHBoxLayout *saveLayout = new QHBoxLayout(saveGroup); {
if (pFrameInfo)
m_edit_savePath = new QLineEdit(saveGroup); {
m_edit_savePath->setReadOnly(true); printf("Get One Frame: Width[%d], Height[%d], FrameLen[%I64d] nFrameNum[%d]\n",
m_edit_savePath->setPlaceholderText("保存路径..."); pFrameInfo->nExtendWidth, pFrameInfo->nExtendHeight, pFrameInfo->nFrameLenEx,pFrameInfo->nFrameNum);
m_edit_savePath->setClearButtonEnabled(true); // pData 是图像指针pFrameInfo->nFrameLenEx 是图像长度, 可以进行图像处理
m_cmb_imgFormat = new QComboBox(saveGroup);
QStringList formats = { ".jpg", ".png", ".tif", ".bmp" };
m_cmb_imgFormat->addItems(formats);
m_btn_openDir = new QPushButton("打开...", saveGroup);
m_btn_openDir->setFixedWidth(80);
m_btn_saveImage = new QPushButton("保存", saveGroup);
m_btn_saveImage->setFixedWidth(80);
saveLayout->addWidget(m_edit_savePath);
saveLayout->addWidget(m_cmb_imgFormat);
saveLayout->addWidget(m_btn_openDir);
saveLayout->addWidget(m_btn_saveImage);
saveGroup->setLayout(saveLayout);
```
---
请使用单例模式帮助我设计一个海康相机的类,类签名为`class HikCamera`
根据手册,类成员应当有一个句柄指针`void *handler`
并参考一下我对FLIR相机的时间仿照着设计海康相机类先仅需要生成头文件`HikCamera.hpp`相关代码即可
```cpp
// FLIRCamera.hpp
// 初始化/去初始化相机
void init();
void deinit();
// 开始/停止图像采集
void startGrabing();
void stopGrabing();
// 设置参数
void setExposure(double exposure);
void setGain(double gain);
// 注册图像回调
void registerImageCallback();
// 线程安全的单例示意代码
class YourSingleton {
public:
static YourSingleton& getInstance() {
static YourSingleton instance;
return instance;
} }
}
// 禁用拷贝和移动 // 注册抓图回调
YourSingleton(const YourSingleton&) = delete; nRet = MV_CC_RegisterImageCallBackEx(handle, ImageCallBackEx, handle);
YourSingleton(YourSingleton&&) = delete; Check(nRet);
YourSingleton& operator=(const YourSingleton&) = delete;
YourSingleton& operator=(YourSingleton&&) = delete;
private: // 设置缓存节点个数
YourSingleton() = default; // 或提供参数化构造 nRet = MV_CC_SetImageNodeNum(handle, 5);
~YourSingleton() = default; // 或自定义析构 Check(nRet);
};
// 开始取流
nRet = MV_CC_StartGrabbing(handle);
Check(nRet);
/* 类中代码 */
// 注册图像回调函数
void registerImageCallback();
``` ```

View File

@ -1,6 +1,11 @@
#pragma once #pragma once
class HikCamera { #include <CameraParams.h>
#include <MvCameraControl.h>
#include <MvErrorDefine.h>
#include <PixelType.h>
class HikCamera{
public: public:
// 获取单例实例 // 获取单例实例
static HikCamera &getInstance() { static HikCamera &getInstance() {

View File

@ -9,8 +9,11 @@ public:
private: private:
void initUI(); void initUI();
void connectAllSignalsAndSlots();
// 左侧视图 // 左侧视图
QGraphicsScene *m_scene;
QGraphicsPixmapItem *m_pixmapItem;
QGraphicsView *m_gv; QGraphicsView *m_gv;
// 相机操作按钮 // 相机操作按钮

View File

@ -1,10 +1,16 @@
#include "HikCamera.hpp" #include "HikCamera.hpp"
#include <memory> #include <memory>
#include <CameraParams.h> #include <iostream>
#include <MvCameraControl.h>
#include <MvErrorDefine.h> // 静态成员函数作为SDK回调函数
#include <PixelType.h> static void __stdcall ImageCallback(unsigned char *pData, MV_FRAME_OUT_INFO_EX *pFrameInfo, void *pUser) {
// 将用户数据转换为HikCamera实例
/*HikCamera *instance = static_cast<HikCamera *>(pUser);
if (instance) {
instance->handleFrameData(pData, pFrameInfo);
}*/
}
void HikCamera::init() { void HikCamera::init() {
// 初始化 SDK // 初始化 SDK
@ -24,17 +30,32 @@ void HikCamera::init() {
} }
void HikCamera::deinit() { void HikCamera::deinit() {
// 关闭相机
int nRet = MV_OK;
nRet = MV_CC_CloseDevice(m_handler);
// 销毁相机实例
nRet = MV_CC_DestroyHandle(m_handler);
// 去初始化 SDK // 去初始化 SDK
MV_CC_Finalize(); MV_CC_Finalize();
} }
void HikCamera::startGrabbing() {} void HikCamera::startGrabbing() {
int nRet = MV_OK;
nRet = MV_CC_StartGrabbing(m_handler);
}
void HikCamera::stopGrabbing() {} void HikCamera::stopGrabbing() {
int nRet = MV_OK;
nRet = MV_CC_StopGrabbing(m_handler);
}
void HikCamera::setExposure(double exposure) {} void HikCamera::setExposure(double exposure) {}
void HikCamera::setGain(double gain) {} void HikCamera::setGain(double gain) {}
void HikCamera::registerImageCallback() {} void HikCamera::registerImageCallback() {
int nRet = MV_OK;
nRet = MV_CC_RegisterImageCallBackEx(m_handler, ImageCallback, nullptr);
}

View File

@ -1,9 +1,13 @@
#include "HikWidget.hpp" #include "HikWidget.hpp"
#include "HikCamera.hpp"
#include <QDebug>
HikWidget::HikWidget(QWidget *parent) : QWidget(parent) { HikWidget::HikWidget(QWidget *parent) : QWidget(parent) {
setWindowTitle("HikVision Camera Control"); setWindowTitle("HikVision Camera Control");
resize(1280, 720); // 设置初始窗口大小 resize(1280, 720); // 设置初始窗口大小
initUI(); initUI();
connectAllSignalsAndSlots();
} }
void HikWidget::initUI() { void HikWidget::initUI() {
@ -13,7 +17,10 @@ void HikWidget::initUI() {
mainLayout->setSpacing(15); mainLayout->setSpacing(15);
// 左侧 - QGraphicsView // 左侧 - QGraphicsView
m_gv = new QGraphicsView(this); m_pixmapItem = new QGraphicsPixmapItem();
m_scene = new QGraphicsScene(this);
m_scene->addItem(m_pixmapItem);
m_gv = new QGraphicsView(m_scene, this);
m_gv->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); m_gv->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
m_gv->setRenderHint(QPainter::Antialiasing); m_gv->setRenderHint(QPainter::Antialiasing);
m_gv->setBackgroundBrush(Qt::darkGray); m_gv->setBackgroundBrush(Qt::darkGray);
@ -104,6 +111,89 @@ void HikWidget::initUI() {
mainLayout->addWidget(rightPanel, 1); // 3:1比例中的1份 mainLayout->addWidget(rightPanel, 1); // 3:1比例中的1份
// 设置按钮初始状态 // 设置按钮初始状态
m_btn_openCamera->setEnabled(true);
m_btn_closeCamera->setEnabled(false); m_btn_closeCamera->setEnabled(false);
m_btn_startGrabbing->setEnabled(false);
m_btn_stopGrabbing->setEnabled(false); m_btn_stopGrabbing->setEnabled(false);
} }
void HikWidget::connectAllSignalsAndSlots() {
// 相机操作按钮连接
connect(m_btn_openCamera, &QPushButton::clicked, this, [this]() {
HikCamera::getInstance().init();
HikCamera::getInstance().registerImageCallback();
m_btn_openCamera->setEnabled(false);
m_btn_closeCamera->setEnabled(true);
m_btn_startGrabbing->setEnabled(true);
m_btn_stopGrabbing->setEnabled(false);
});
connect(m_btn_closeCamera, &QPushButton::clicked, this, [this]() {
HikCamera::getInstance().deinit();
m_btn_openCamera->setEnabled(true);
m_btn_closeCamera->setEnabled(false);
m_btn_startGrabbing->setEnabled(false);
m_btn_stopGrabbing->setEnabled(false);
});
connect(m_btn_startGrabbing, &QPushButton::clicked, this, [this]() {
HikCamera::getInstance().startGrabbing();
m_btn_startGrabbing->setEnabled(false);
m_btn_stopGrabbing->setEnabled(true);
});
connect(m_btn_stopGrabbing, &QPushButton::clicked, this, [this]() {
HikCamera::getInstance().stopGrabbing();
m_btn_stopGrabbing->setEnabled(false);
m_btn_startGrabbing->setEnabled(true);
});
// 图像保存按钮连接
connect(m_btn_openDir, &QPushButton::clicked, this, [this]() {
QString dir = QFileDialog::getExistingDirectory(
this, "选择保存目录", QDir::homePath(),
QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
if (!dir.isEmpty()) {
m_edit_savePath->setText(QDir::toNativeSeparators(dir));
}
});
connect(m_btn_saveImage, &QPushButton::clicked, this, [this]() {
QString path = m_edit_savePath->text();
if (path.isEmpty()) {
QMessageBox::warning(this, "警告", "请先选择保存路径");
return;
}
QDir dir(path);
if (!dir.exists()) {
if (!dir.mkpath(".")) {
QMessageBox::critical(this, "错误", "无法创建保存目录");
return;
}
}
// 生成时间戳文件名 yyyy-MM-dd-HH-mm-ss-zzz
QDateTime now = QDateTime::currentDateTime();
QString timestamp = now.toString("yyyy-MM-dd-HH-mm-ss-zzz");
QString format = m_cmb_imgFormat->currentText();
QString filePath = QDir::toNativeSeparators(
dir.filePath(timestamp + format));
qDebug() << "图片保存路径:" << filePath;
});
// 相机参数连接
connect(m_spin_exposureTime, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
[](double value) {
HikCamera::getInstance().setExposure(value);
});
connect(m_spin_gain, QOverload<double>::of(&QDoubleSpinBox::valueChanged),
[](double value) {
HikCamera::getInstance().setGain(value);
});
}