基于Qt+VS的高德红外相机开发

红外标定图

一、开发原因

项目需要调用高德红外相机拍图,需要有一个采图软件,为了方便操作并且有可视化见面,我选择了基于**“Qt + Opencv + 高德SDK”的组合,使用“VS + QT”** 实现相机的采图。

QQ交流(记得备注哦):2514251475
代码:GitHub

原始的想法:

  1. 点击按钮/按键拍图功能
  2. 按F键或者点击“拍摄",存图
  3. 模仿高德的例程写一个就行

二、Qt学习笔记

2.1 信号与槽

信号是动作开关,是执行函数;信号和槽函数之间用 connect 函数连接。个人理解应该是类似于中断机制,当触发中断后,进入中断函数执行相关操作。

添加槽函数的方式:
方法一
使用VS插件中的Qt Designer,转到槽函数;步骤如下:

  • 在VS中需要 “VS解决方案中选中方案,右键->Qt->Refresh intelliSense进行刷新”;
  • 然后在对应的.h和.cpp文件中分别添加 信号类函数声明 和 槽函数具体功能;
  • 该方法在会自动在 ui_xxxxx.h 文件中定义connect函数

方法二
构造函数里写connect函数,(纯手动添加connect函数)
connect函数两种写法:

// 连接信号与槽 谁发出信号 发出什么信号 谁处理信号 怎么处理信号
// 方法一:用宏定义
connect(ui.cmd_Edit, SIGNAL(returnPressed()), this, SLOT(commit_BtnClicked()));
// 方法二:取地址
connect(ui.exit_Btn, &QPushButton::clicked, this, &QCamera::on_exit_BtnClicked);

然后在对应的.h和.cpp文件中分别添加 信号类函数声明 和 槽函数具体功能(一般先声明好槽函数);

当槽函数的功能比较少时,可以用QMessageBox的方法

connect(ui.browse_Btn, &QPushButton::clicked, [this]()
{
	QMessageBox::information(this, "信息", "点击浏览");
});

2.2 定时器

两种方式开启定时器
方式一:使用QObject类

// 相关函数
// startTimer   开启
// timerEvent   事件
// killTimer    关闭

// 槽函数里打开计时器
myTimerId = this->startTimer(TIMEOUT); //TIMEOUT
// 然后重写虚函数(类继承)
virtual void timerEvent(QTimerEvent *event);

timerEvent(QTimerEvent *event){
	if(event->timerId() != myTimerId)
	return;
	// 实现定时功能
}

// 槽函数关闭定时器
this->killTimer(myTimerId);

方式二:使用QTimer类

// 头文件定义
QTimer *timer;

// 构造函数中
timer = new QTimer;
// 定时器槽函数
connect(timer,&QTimer::timerout,this,&Widget::timeoutSlot)

// 开启定时器
timer->start(TIMEOUT);

void Widget::timeoutSlot(){
	//定时器操作
}

// 结束定时器
timer->stop();

// 只执行单次定时
QTimer::singleShot(1000, this, SLOT(timerout));

三、高德红外SDK梳理

这里可以跳过,我自己梳理手册记录的。

数据类型说明:
enum guide_usb_code_e

typedef enum
{
	ERROR_NO = 1,
	//1:无错误
	ERROR_DEVICE_NOT_FOUND = -1,
	//-1:找不到设备
	ERROR_POINT_NULL = -2,
	//-2:数据指针为空
	ERROR_POINTS_TOO_LARGE = -3,
	//-3:数据指针过大
	ERROR_POINTS_TOO_SMALL = -4,
	//-4:数据指针过小
	ERROR_MALLOC_FAILED = -5,
	//-5:申请缓存失败
	ERROR_RESOLUTION = -6,
	//-6:分辨率设置错误
	ERROR_UNKNOW = -999
	//-999:未知错误
} guide_usb_code_e;

struct guide_usb_device_info_t 高德设备信息,打开设备时需要的信息

typedef struct
{
	int width;							//图像宽度
	int height;							//图像高度
	guide_usb_video_mode_e video_mode;	//视频模式
} guide_usb_device_info_t;

enum guide_usb_video_mode_e 根据机芯配置好的视频模式,传入对应的类型

typedef enum
{
	X16 = 0,						//X16
	X16_PARAM = 1,					//X16+参数行
	Y16 = 2,						//Y16
	Y16_PARAM = 3,					//Y16+参数行
	YUV = 4,						//YUV
	YUV_PARAM = 5,					//YUV+参数行
	Y16_YUV = 6,					//Y16+YUV
	Y16_PARAM_YUV = 7				//Y16+参数行+YUV
} guide_usb_video_mode_e;

struct guide_usb_frame_data_t 图像数据X16/Y16 模式从 frame_src_data 传出数据 YUV 模式从 frame_yuv_data 传出数据

typedef struct
{
	int frame_width;							//图像宽度
	int frame_height;							//图像高度
	unsigned char *frame_rgb_data;				//rgb 数据
	int frame_rgb_data_length;					//rgb 数据长度
	short *frame_src_data;						//原始数据,X16/Y16
	int frame_src_data_length;					//原始数据长度
	short *frame_yuv_data;						//yuv 数据
	int frame_yuv_data_length;					//yuv 数据长度
	short *paraLine;							//参数行
	int paraLine_length;						//参数行长度
} guide_usb_frame_data_t;

OnFrameDataReceivedCB 这段代码定义了一个函数指针类型 OnFrameDataReceivedCB,该函数指向一个没有返回值的函数,该函数接受一个 guide_usb_frame_data_t 类型的常量参数 frame_data。

typedef void(__stdcall *OnFrameDataReceivedCB)(const guide_usb_frame_data_t frame_data);

enum guide_usb_device_status_e 机芯连接状态

typedef enum
{
	DEVICE_CONNECT_OK = 1,
	//连接正常
	DEVICE_DISCONNECT_OK = -1,
	//断开连接
} guide_usb_device_status_e;

OnDeviceConnectStatusCB 连接状态回调方法,自动读取相机连接状态

typedef void(__stdcall *OnDeviceConnectStatusCB)(const guide_usb_device_status_e device_status);

struct device_info

typedef struct
{
	int devID;							//设备 ID
	char devName[128];					//设备名称
} device_info;

struct device_info_list

typedef struct
{
	int devCount;						//设备数量
	device_info devs[32];				//设备信息
} device_info_list;

四、问题、小技巧

问题(数据类型需要对应,指针也是一样)

报错:在Qt的类中申明了OnFrameDataReceivedCB pFrameProc;
并且在主函数中将pFrameProc = FrameData_callback;
不能将"void (CameraControl:😗)(quide usb frame data tframe data)“类型的值分配到"OnFrameDataReceivedCB” 类型的实体。

解决方法
问题出在函数指针类型的匹配上。
OnFrameDataReceivedCB 定义的函数指针类型不兼容 void (CameraControl::)(guide_usb_frame_data_t) 这种成员函数指针类型。
原因是 CameraControl::
部分表示成员函数指针,而OnFrameDataReceivedCB 是一个全局函数指针类型。

想要使用成员函数指针,需要修改 OnFrameDataReceivedCB 的定义来匹配成员函数指针的类型。
可以将 OnFrameDataReceivedCB 定义为一个成员函数指针类型,例如:
typedef void (CameraControl::OnFrameDataReceivedCB)(guide_usb_frame_data_t frame_data);
这样,OnFrameDataReceivedCB 就可以匹配 void (CameraControl::
)(guide_usb_frame_data_t) 这种成员函数指针类型了。

代码规范:

命名:驼峰命名
类名,结构体名,函数名:大驼峰	class Student
类对象,变量:		小驼峰	int countNum
{ 前面加空格
;  , 后面加空格

Qt出现中文乱码

在头文件中添加 #pragma execution_character_set(“UTF-8”)

关于Qt图像处理

问题一:

QImage((const unsigned char*)(myImg.data), myImg.cols, myImg.rows, QImage::Format_RGB888).copy()

QImage((const unsigned char*)(myImg.data), myImg.cols, myImg.rows, QImage::Format_RGB888)

为什么用后者会有程序卡退和报错:(Qt5Gui.dll)处(位于 xxx.exe 中)引发的异常: 0xC0000005: 读取位置 XXXXXXXX 时发生访问冲突。这里copy()作用是啥?

解释:

QImage((const unsigned char*)(myImg.data), myImg.cols, myImg.rows, QImage::Format_RGB888).copy():

这行代码创建了一个 QImage 对象,并使用给定的参数构造了这个对象。然后调用了 copy() 方法,该方法返回了一个 QImage 对象的深拷贝,也就是说,它会复制原始图像的像素数据,而不仅仅是共享相同的数据。因此,这个操作会在内存中复制一份图像数据。

QImage((const unsigned char*)(myImg.data), myImg.cols, myImg.rows, QImage::Format_RGB888);

这行代码创建了一个 QImage 对象,但没有调用 copy() 方法。这意味着它只是使用了给定的参数直接构造了一个 QImage 对象,但没有额外的深拷贝操作。

因此,它与原始图像共享相同的像素数据,而不是创建了一个完全独立的副本。所以,主要区别在于第一行代码通过 copy() 方法创建了一个图像数据的深拷贝,而第二行代码则没有进行额外的拷贝操作,只是直接使用了原始图像数据。当你使用 QImage 构造函数直接传递 myImg.data 时,并且没有使用 copy() 方法,QImage 对象会尝试直接访问 myImg.data 指向的内存。如果 myImg 对象在 QImage 对象使用之后被释放或者销毁,那么 QImage 对象就会尝试访问无效的内存地址,从而导致程序崩溃或异常。

这种报错通常是由于内存访问错误引起的。在这种情况下,可能是因为 myImg 对象的生命周期问题导致了内存访问错误。

解决这个问题的一种方法是确保在 QImage 对象的生命周期内保持 myImg 对象有效(保证图像处理完之前不会无效)。
另一种方法是使用 copy() 方法创建 QImage 对象的深拷贝,以避免与原始图像数据的共享,从而减少潜在的生命周期问题(先缓存下来)。

  • 23
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值