diff --git a/CMakeSettings.json b/CMakeSettings.json new file mode 100644 index 0000000..b58599c --- /dev/null +++ b/CMakeSettings.json @@ -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": [] + } + ] +} \ No newline at end of file diff --git a/LLM.md b/LLM.md index 02929c6..7608869 100644 --- a/LLM.md +++ b/LLM.md @@ -1,88 +1,30 @@ -请帮助我生成一个C++编写的Qt UI代码,使用`initUI()`函数实现UI的创建,具体要求如下: -这个类的签名为`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 +请结合手册提供的回调函数注册代码,使用 lambda 函数的方式,实现类 `` 中的注册回调函数功能 ```cpp -// 图像保存GroupBox -QGroupBox *saveGroup = new QGroupBox("图像保存", rightPanel); -QHBoxLayout *saveLayout = new QHBoxLayout(saveGroup); - -m_edit_savePath = new QLineEdit(saveGroup); -m_edit_savePath->setReadOnly(true); -m_edit_savePath->setPlaceholderText("保存路径..."); -m_edit_savePath->setClearButtonEnabled(true); - -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; +/* 相机 SDK 示例代码 */ +void __stdcall ImageCallBackEx(unsigned char * pData, MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser) +{ + if (pFrameInfo) + { + printf("Get One Frame: Width[%d], Height[%d], FrameLen[%I64d] nFrameNum[%d]\n", + pFrameInfo->nExtendWidth, pFrameInfo->nExtendHeight, pFrameInfo->nFrameLenEx,pFrameInfo->nFrameNum); + // pData 是图像指针,pFrameInfo->nFrameLenEx 是图像长度, 可以进行图像处理 } - - // 禁用拷贝和移动 - YourSingleton(const YourSingleton&) = delete; - YourSingleton(YourSingleton&&) = delete; - YourSingleton& operator=(const YourSingleton&) = delete; - YourSingleton& operator=(YourSingleton&&) = delete; +} -private: - YourSingleton() = default; // 或提供参数化构造 - ~YourSingleton() = default; // 或自定义析构 -}; +// 注册抓图回调 +nRet = MV_CC_RegisterImageCallBackEx(handle, ImageCallBackEx, handle); +Check(nRet); + +// 设置缓存节点个数 +nRet = MV_CC_SetImageNodeNum(handle, 5); +Check(nRet); + +// 开始取流 +nRet = MV_CC_StartGrabbing(handle); +Check(nRet); + +/* 类中代码 */ +// 注册图像回调函数 +void registerImageCallback(); ``` \ No newline at end of file diff --git a/include/HikCamera.hpp b/include/HikCamera.hpp index c55aa9d..4033aec 100644 --- a/include/HikCamera.hpp +++ b/include/HikCamera.hpp @@ -1,6 +1,11 @@ #pragma once -class HikCamera { +#include +#include +#include +#include + +class HikCamera{ public: // 获取单例实例 static HikCamera &getInstance() { diff --git a/include/HikWidget.hpp b/include/HikWidget.hpp index d6a3dd0..7ba353a 100644 --- a/include/HikWidget.hpp +++ b/include/HikWidget.hpp @@ -9,8 +9,11 @@ public: private: void initUI(); + void connectAllSignalsAndSlots(); // 左侧视图 + QGraphicsScene *m_scene; + QGraphicsPixmapItem *m_pixmapItem; QGraphicsView *m_gv; // 相机操作按钮 diff --git a/src/HikCamera.cpp b/src/HikCamera.cpp index 2ef766a..016da4e 100644 --- a/src/HikCamera.cpp +++ b/src/HikCamera.cpp @@ -1,10 +1,16 @@ #include "HikCamera.hpp" #include -#include -#include -#include -#include +#include + +// 静态成员函数作为SDK回调函数 +static void __stdcall ImageCallback(unsigned char *pData, MV_FRAME_OUT_INFO_EX *pFrameInfo, void *pUser) { + // 将用户数据转换为HikCamera实例 + /*HikCamera *instance = static_cast(pUser); + if (instance) { + instance->handleFrameData(pData, pFrameInfo); + }*/ +} void HikCamera::init() { // 初始化 SDK @@ -24,17 +30,32 @@ void HikCamera::init() { } void HikCamera::deinit() { - + // 关闭相机 + int nRet = MV_OK; + nRet = MV_CC_CloseDevice(m_handler); + + // 销毁相机实例 + nRet = MV_CC_DestroyHandle(m_handler); + // 去初始化 SDK 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::setGain(double gain) {} -void HikCamera::registerImageCallback() {} +void HikCamera::registerImageCallback() { + int nRet = MV_OK; + nRet = MV_CC_RegisterImageCallBackEx(m_handler, ImageCallback, nullptr); +} diff --git a/src/HikWidget.cpp b/src/HikWidget.cpp index 2a8dd16..4f4e36b 100644 --- a/src/HikWidget.cpp +++ b/src/HikWidget.cpp @@ -1,9 +1,13 @@ #include "HikWidget.hpp" +#include "HikCamera.hpp" + +#include HikWidget::HikWidget(QWidget *parent) : QWidget(parent) { setWindowTitle("HikVision Camera Control"); resize(1280, 720); // 设置初始窗口大小 initUI(); + connectAllSignalsAndSlots(); } void HikWidget::initUI() { @@ -13,7 +17,10 @@ void HikWidget::initUI() { mainLayout->setSpacing(15); // 左侧 - 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->setRenderHint(QPainter::Antialiasing); m_gv->setBackgroundBrush(Qt::darkGray); @@ -104,6 +111,89 @@ void HikWidget::initUI() { mainLayout->addWidget(rightPanel, 1); // 3:1比例中的1份 // 设置按钮初始状态 + m_btn_openCamera->setEnabled(true); m_btn_closeCamera->setEnabled(false); + m_btn_startGrabbing->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::of(&QDoubleSpinBox::valueChanged), + [](double value) { + HikCamera::getInstance().setExposure(value); + }); + + connect(m_spin_gain, QOverload::of(&QDoubleSpinBox::valueChanged), + [](double value) { + HikCamera::getInstance().setGain(value); + }); + +}