思路:
1.定义带UI界面的主函数类
1.1在主函数中包含其它所有类头文件,进行声明和实例化;使用相机时,是用公共相机的接口在某一个具体函数中去实例化具体的海康相机对象。
1.2设计界面:连接相机,单次采集,连续采集,停止采集,关闭相机
1.3在连续采集中,开始启用线程。需要在线程类中采集图像,通过信号与槽在主函数中接收并显示图像。
2.定义公共相机接口类
3.定义海康相机类
4.定义线程类
4.1里面包含:接收海康相机的函数,在主函数中可以直接调用线程里面的这个函数,并通过指针传参。
4.2定义run函数,在函数里面采集图像,并发送信号。
4.3定义if语句判断线程状态,控制线程启停。
4.4定义bool变量去结合if进行判断
5.定义日志类
6.定义加载保存参数,公共结构体类
7.定义其它图像处理功能类
7.1例如:测量,匹配,检测等...............
1.主目录框架
列表中含有:
1.src里面是图像处理的各种模块功能以及公共文件(日志和参数加载)
2.相机的公共接口类
3.Halcon类
4.海康相机类
5.主函数
6.线程类
2.定义公共相机接口(camerainterface)
camerainterface.h
#ifndef CAMERAINTERFACE_H
#define CAMERAINTERFACE_H
#include "HalconCpp.h"
#include "HDevThread.h"
using namespace HalconCpp;
#include"iostream"
class CameraInterface
{
public:
CameraInterface();
~CameraInterface();
//关闭相机采集 // ch:连接设备
virtual int connectCamera(int id)=0;
//设置是否为触发模式
virtual int setTriggerMode(unsigned int TriggerModeNum)=0;
//开启相机采集
virtual int startCamera()=0;
virtual int stopCamera()=0;
//关闭相机
virtual int closeCamera()=0;
//软触发
virtual int softTrigger()=0;
//读取buffer
virtual int ReadBuffer(HObject &image)=0;
//设置图像高度
virtual int setHeight(unsigned int height)=0;
//设置图像ROI宽度
virtual int setWidth(unsigned int width)=0;
//获取图像高度值
virtual int getHeight()=0;
//获取图像宽度值
virtual int getWidth()=0;
//获取相机曝光时间
virtual float getExposureTime()=0;
//设置图像水平偏移OffsetX
virtual int setOffsetX(unsigned int offsetX)=0;
//设置图像竖直偏移OffsetY
virtual int setOffsetY(unsigned int offsetY)=0;
//设置触发源
virtual int setTriggerSource(unsigned int TriggerSourceNum)=0;
//设置帧率控制使能
virtual int setFrameRateEnable(bool comm)=0;
//设置心跳时间
virtual int setHeartBeatTime(unsigned int time)=0;
//设置曝光时间
virtual int setExposureTime(float ExposureTimeNum)=0;
//设置增益
virtual int setGain(float Gain)=0;
//关闭自动曝光
virtual int setExposureAuto(bool exposureAutoFlag)=0;
//关闭自动增益
virtual int setGainAuto(bool gainAutoFlag)=0;
//virtual int setGain(float Gain)=0;
//清理相机缓存
virtual void clearBuffer()=0;
};
#endif // CAMERAINTERFACE_H
3.定义海康相机类(hikvisionsdk)
1.hikvisionsdk.h文件,海康相机功能函数声明(包含公共相机头文件)
#ifndef HIKVISIONSDK_H
#define HIKVISIONSDK_H
#include"camerainterface.h"
#include"MvCameraControl.h"
#include "HalconCpp.h"
#include "HDevThread.h"
#include <QImage>
using namespace HalconCpp;
class HikvisionSDK:public CameraInterface
{
public:
HikvisionSDK();
~HikvisionSDK();
// ch:连接设备
//int connectCamera(std::string id);
int connectCamera(int id);
//设置是否为触发模式
int setTriggerMode(unsigned int TriggerModeNum);
//开启相机采集
int startCamera();
//关闭相机采集
int stopCamera();
//关闭相机
int closeCamera();
//软触发
int softTrigger();
//读取buffer
int ReadBuffer(HObject &image);
//设置图像高度
int setHeight(unsigned int height);
//设置图像ROI宽度
int setWidth(unsigned int width);
//获取图像高度值
int getHeight();
//获取图像宽度值
int getWidth();
//获取相机曝光时间
float getExposureTime();
//设置图像水平偏移OffsetX
int setOffsetX(unsigned int offsetX);
//设置图像竖直偏移OffsetY
int setOffsetY(unsigned int offsetY);
//设置触发源
int setTriggerSource(unsigned int TriggerSourceNum);
//设置帧率控制使能
int setFrameRateEnable(bool comm);
//设置心跳时间
int setHeartBeatTime(unsigned int time);
//设置曝光时间
int setExposureTime(float ExposureTimeNum);
//设置增益
int setGain(float Gain);
//关闭自动曝光
int setExposureAuto(bool exposureAutoFlag);
//关闭自动增益
int setGainAuto(bool gainAutoFlag);
//清理相机缓存
void clearBuffer();
bool QImage2HObject(QImage &qImg, HObject &hImg);
private:
void* m_hDevHandle;
public:
// 用于保存图像的缓存
unsigned int m_nBufSizeForSaveImage;
// 用于从驱动获取图像的缓存
unsigned int m_nBufSizeForDriver;
};
#endif // HIKVISIONSDK_H
2.hikvisionsdk.cpp文件(海康相机各功能实现)
在读图相机中图像函数里面有个事件,此时需要找到自己相机的型号才能执行,要不然程序容易闪退
#include "hikvisionsdk.h"
MV_CC_DEVICE_INFO_LIST m_stDevList; // ch:设备信息列表结构体变量,用来存储设备列表
MV_CC_DEVICE_INFO* m_Device=NULL; //设备对象
#include <QDebug>
#include <QString>
#include <QDebug>
HikvisionSDK::HikvisionSDK()
{
m_hDevHandle = NULL;
}
HikvisionSDK::~HikvisionSDK()
{
if (m_hDevHandle)
{
MV_CC_DestroyHandle(m_hDevHandle);
m_hDevHandle = NULL;
}
}
//连接相机
int HikvisionSDK::connectCamera(int id)
{
// Enum device
MV_CC_DEVICE_INFO_LIST stDeviceList;
memset(&stDeviceList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));
int nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &stDeviceList);
if (nRet!=0)
{
qDebug()<<"nRet:="<<nRet;
return -1;
}
if (stDeviceList.nDeviceNum > 0)
{
for (unsigned int i = 0; i < stDeviceList.nDeviceNum; i++)
{
MV_CC_DEVICE_INFO* pDeviceInfo = stDeviceList.pDeviceInfo[i];
if (NULL == pDeviceInfo)
{
break;
}
}
}
else
{
return -1;
}
unsigned int nIndex = 0;
// Select device and create handle
nRet = MV_CC_CreateHandle(&m_hDevHandle, stDeviceList.pDeviceInfo[nIndex]);
if (nRet!=0)
{
//printf("Create Handle fail! nRet [0x%x]\n", nRet);
return -1;
}
// open device
nRet = MV_CC_OpenDevice(m_hDevHandle);
if (nRet!=0)
{
//printf("Open Device fail! nRet [0x%x]\n", nRet);
return -1;
}
return 0;
}
//启动相机采集
int HikvisionSDK::startCamera()
{
int tempValue=MV_CC_StartGrabbing(m_hDevHandle);
if(tempValue!=0)
{
return -1;
}else
{
return 0;
}
}
//停止相机采集
int HikvisionSDK::stopCamera()
{
int tempValue=MV_CC_StopGrabbing(m_hDevHandle);
if(tempValue!=0)
{
return -1;
}else
{
return 0;
}
}
//关闭相机
int HikvisionSDK::closeCamera()
{
if (NULL == m_hDevHandle)
{
return -1;
}
MV_CC_CloseDevice(m_hDevHandle);
int tempValue = MV_CC_DestroyHandle(m_hDevHandle);
m_hDevHandle = NULL;
if(tempValue!=0)
{
return -1;
}else
{
return 0;
}
}
//发送软触发
int HikvisionSDK::softTrigger()
{
int tempValue= MV_CC_SetCommandValue(m_hDevHandle, "TriggerSoftware");
if(tempValue!=0)
{
return -1;
}else
{
return 0;
}
}
//读取相机中的图像
int HikvisionSDK::ReadBuffer(HObject &halconImage)
{
//Mat* getImage=new Mat();
unsigned int nRecvBufSize = 0;
MVCC_INTVALUE stParam;
qDebug()<<"enter3";
memset(&stParam, 0, sizeof(MVCC_INTVALUE));
int tempValue = MV_CC_GetIntValue(m_hDevHandle, "PayloadSize", &stParam);
qDebug()<<"enter4";
if (tempValue != 0)
{
return -1;
}
//分配一个指针的内存大小 , c语言的库函数 malloc;
nRecvBufSize = stParam.nCurValue;
//指针 图像接收数据的指针
unsigned char* pDate;
pDate=(unsigned char *)malloc(nRecvBufSize);
qDebug()<<"enter41";
//句柄 指针 nRecvBufSize 700 , 输出 (指针和图像信息的结构体)stImageInfo。
MV_FRAME_OUT_INFO_EX stImageInfo = {0};
tempValue= MV_CC_GetOneFrameTimeout(m_hDevHandle, pDate, nRecvBufSize, &stImageInfo, 700);
if(tempValue!=0)
{
return -1;
}
// m_nBufSizeForSaveImage = stImageInfo.nWidth * stImageInfo.nHeight * 3 + 2048;
// unsigned char* m_pBufForSaveImage;
// m_pBufForSaveImage = (unsigned char*)malloc(m_nBufSizeForSaveImage);
qDebug()<<"enter42";
bool isMono;
//HObject halconImage;
//stImageInfo.enPixelType
//像素格式 的 stImageInfo ,switch 调整,
switch (stImageInfo.enPixelType)
{
case PixelType_Gvsp_Mono8:
case PixelType_Gvsp_Mono10:
case PixelType_Gvsp_Mono10_Packed:
case PixelType_Gvsp_Mono12:
case PixelType_Gvsp_Mono12_Packed:
case 17301512:
isMono=true;
break;
default:
isMono=false;
break;
}
if(isMono)
{
//*getImage=Mat(stImageInfo.nHeight,stImageInfo.nWidth,CV_8UC1,pDate);
//imwrite("d:\\测试opencv_Mono.tif", image);
qDebug()<<" stImageInfo.nHeight:"<< stImageInfo.nHeight;
qDebug()<<" stImageInfo.nWidth:"<< stImageInfo.nWidth;
qDebug()<<"pDate:"<<pDate;
GenImage1(&halconImage, "byte", stImageInfo.nWidth,stImageInfo.nHeight,(Hlong)(pDate));//转换为hoject
// GenImage1(&hImg, "byte", tFrameInfo.iWidth, tFrameInfo.iHeight, (Hlong)m_pchImgBuffer[camId]);
// qDebug()<<"pDate11:"<<pDate;
//WriteImage(halconImage, "png", 0, "./picture/halcon_Mono.png");
}
else
{
//转换图像格式为BGR8
MV_CC_PIXEL_CONVERT_PARAM stConvertParam = {0};
memset(&stConvertParam, 0, sizeof(MV_CC_PIXEL_CONVERT_PARAM));
stConvertParam.nWidth = stImageInfo.nWidth; //ch:图像宽 | en:image width
stConvertParam.nHeight = stImageInfo.nHeight; //ch:图像高 | en:image height
//stConvertParam.pSrcData = m_pBufForDriver; //ch:输入数据缓存 | en:input data buffer
stConvertParam.pSrcData = pDate; //ch:输入数据缓存 | en:input data buffer
stConvertParam.nSrcDataLen = stImageInfo.nFrameLen; //ch:输入数据大小 | en:input data size
stConvertParam.enSrcPixelType = stImageInfo.enPixelType; //ch:输入像素格式 | en:input pixel format
stConvertParam.enDstPixelType = PixelType_Gvsp_BGR8_Packed; //ch:输出像素格式 | en:output pixel format 适用于OPENCV的图像格式
//stConvertParam.enDstPixelType = PixelType_Gvsp_RGB8_Packed; //ch:输出像素格式 | en:output pixel format
//stConvertParam.pDstBuffer = m_pBufForSaveImage; //ch:输出数据缓存 | en:output data buffer
stConvertParam.nDstBufferSize = m_nBufSizeForSaveImage; //ch:输出缓存大小 | en:output buffer size
MV_CC_ConvertPixelType(m_hDevHandle, &stConvertParam);
QImage img = QImage((const uchar*)pDate, stImageInfo.nWidth,stImageInfo.nHeight, QImage::Format_RGB888);
QImage2HObject(img, halconImage);
//QImage2HObject(img, hImg);
//halconImage 输出 rgb hobject 格式的图像 。
//因为 这里没有 图片 输出 所以 代码就奔溃了。
//*getImage=Mat(stImageInfo.nHeight,stImageInfo.nWidth,CV_8UC3,m_pBufForSaveImage);
//imwrite("d:\\测试opencv_Color.tif", image);
}
//CopyImage(halconImage, &image);
free(pDate);
//free(m_pBufForSaveImage);
return 0;
}
//Qimage 转换成 hobject image
bool HikvisionSDK::QImage2HObject(QImage &qImg, HObject &hImg)
{
try
{
if (qImg.isNull()) return false;
int width = qImg.width();
int height = qImg.height();
QImage::Format format = qImg.format();
if (format == QImage::Format_RGB32 ||
format == QImage::Format_ARGB32 ||
format == QImage::Format_ARGB32_Premultiplied)
{
GenImageInterleaved(&hImg, Hlong(qImg.bits()), "bgrx", width, height, 0, "byte", width, height, 0, 0, 8, 0);
}
else if (format == QImage::Format_RGB888)
{
GenImageInterleaved(&hImg, Hlong(qImg.bits()), "bgr", width, height, 0, "byte", width, height, 0, 0, 8, 0);
}
else if (format == QImage::Format_Grayscale8 || format == QImage::Format_Indexed8)
{
GenImage1Extern(&hImg, "byte", width, height, Hlong(qImg.bits()), NULL);
}
}
catch (const std::exception&)
{
return false;
}
return true;
}
//获取图像高度值
int HikvisionSDK::getHeight()
{
MVCC_INTVALUE stParam;
memset(&stParam, 0, sizeof(MVCC_INTVALUE));
int tempValue=MV_CC_GetIntValue(m_hDevHandle, "Height", &stParam);
int value= stParam.nCurValue;
if(tempValue!=0)
{
return -1;
}else
{
return value;
}
}
//获取图像宽度值
int HikvisionSDK::getWidth()
{
MVCC_INTVALUE stParam;
memset(&stParam, 0, sizeof(MVCC_INTVALUE));
int tempValue=MV_CC_GetIntValue(m_hDevHandle, "Width", &stParam);
int value= stParam.nCurValue;
if(tempValue!=0)
{
return -1;
}else
{
return value;
}
}
//获取相机曝光时间
float HikvisionSDK::getExposureTime()
{
MVCC_FLOATVALUE stParam;
memset(&stParam, 0, sizeof(MVCC_INTVALUE));
int tempValue=MV_CC_GetFloatValue(m_hDevHandle, "ExposureTime", &stParam);
float value= stParam.fCurValue;
if(tempValue!=0)
{
return -1;
}else
{
return value;
}
}
//设置图像ROI高度
int HikvisionSDK::setHeight(unsigned int height)
{
int tempValue=MV_CC_SetIntValue(m_hDevHandle, "Height", height);
if(tempValue!=0)
{
return -1;
}
else
{
return 0;
}
}
//设置图像ROI宽度
int HikvisionSDK::setWidth(unsigned int width)
{
int tempValue=MV_CC_SetIntValue(m_hDevHandle, "Width", width);
if(tempValue!=0)
{
return -1;
}
else
{
return 0;
}
}
//设置图像水平偏移OffsetX
int HikvisionSDK::setOffsetX(unsigned int offsetX)
{
int tempValue=MV_CC_SetIntValue(m_hDevHandle, "OffsetX", offsetX);
if(tempValue!=0)
{
return -1;
}
else
{
return 0;
}
}
//设置图像竖直偏移OffsetY
int HikvisionSDK::setOffsetY(unsigned int offsetY)
{
int tempValue=MV_CC_SetIntValue(m_hDevHandle, "OffsetY", offsetY);
if(tempValue!=0)
{
return -1;
}
else
{
return 0;
}
}
//设置是否为触发模式
int HikvisionSDK::setTriggerMode(unsigned int TriggerModeNum)
{
//0:Off 1:On
int tempValue= MV_CC_SetEnumValue(m_hDevHandle,"TriggerMode", TriggerModeNum);
if(tempValue!=0)
{
return -1;
}else
{
return 0;
}
}
//设置触发源
int HikvisionSDK::setTriggerSource(unsigned int TriggerSourceNum)
{
//0:Line0 1:Line1 7:Software
int tempValue= MV_CC_SetEnumValue(m_hDevHandle,"TriggerSource", TriggerSourceNum);
if(tempValue!=0)
{
return -1;
}else
{
return 0;
}
}
//设置帧率控制使能
int HikvisionSDK::setFrameRateEnable(bool comm)
{
int tempValue =MV_CC_SetBoolValue(m_hDevHandle, "AcquisitionFrameRateEnable", comm);
if (tempValue != 0)
{
return -1;
}
else
{
return 0;
}
}
//设置心跳时间
int HikvisionSDK::setHeartBeatTime(unsigned int time)
{
//心跳时间最小为500ms
if(time<500)
time=500;
int tempValue=MV_CC_SetIntValue(m_hDevHandle, "GevHeartbeatTimeout", time);
if(tempValue!=0)
{
return -1;
}
else
{
return 0;
}
}
//设置曝光时间
int HikvisionSDK::setExposureTime(float ExposureTimeNum)
{
int tempValue= MV_CC_SetFloatValue(m_hDevHandle, "ExposureTime",ExposureTimeNum );
if(tempValue!=0)
{
return -1;
}
else
{
return 0;
}
}
//设置曝光时间
int HikvisionSDK::setGain(float Gain)
{
int tempValue= MV_CC_SetFloatValue(m_hDevHandle, "Gain",Gain);
if(tempValue!=0)
{
return -1;
}
else
{
return 0;
}
}
//关闭自动曝光
int HikvisionSDK::setExposureAuto(bool exposureAutoFlag)
{
int tempValue= MV_CC_SetEnumValue(m_hDevHandle,"ExposureAuto", exposureAutoFlag);
if (tempValue != 0)
{
return -1;
}
else
{
return 0;
}
}
//关闭自动增益
int HikvisionSDK::setGainAuto(bool gainAutoFlag)
{
int tempValue= MV_CC_SetEnumValue(m_hDevHandle,"GainAuto", gainAutoFlag);
if (tempValue != 0)
{
return -1;
}
else
{
return 0;
}
}
//清理相机缓存
void HikvisionSDK::clearBuffer()
{
//stopCamera();
//startCamera();
}
4.在主程序相机实例化
1.首先包含公共相机和海康相机的头文件
2.用公共相机接口去实例化海康相机
.h主文件
private:
//相机指针
CameraInterface * camera=NULL;
.cpp主文件
camera=new HikvisionSDK();用公共相机接口实例化海康相机类
析构函数中
if(camera!=NULL)
{
delete camera;
camera=NULL;
}
5.连接相机
1.在IU界面下添加连接相机按钮转到槽函数
//连接相机
void MainWindow::on_btn_Connect_clicked()
{
//初始化相机句柄
if(camera!=NULL)
{
delete camera;
camera=NULL;
}
qDebug()<<111;
if(camera==NULL)
{
qDebug()<<112;
InitCam();//连接相机函数
//控制按钮是否可以按下
ui->btn_Close->setEnabled(false);
ui->btn_Connect->setEnabled(false);
ui->btn_Trigger->setEnabled(true);
ui->lxcj->setEnabled(true);
ui->StopAcquisition->setEnabled(true);
}
}
2.连接相机函数实现
注意:次函数是实例化具体的相机(因为在项目中可能用到不同类型的相机,所以在头文件首先用公共相机接口)然后在具体的连接相机下面去实例化具体的相机类型对象。
最后一行程序,是把这个具体的海康相机对象通过传参,传入到线程类中去。
void MainWindow::InitCam()
{
camera=new HikvisionSDK();此时用到了上面提到的海康相机实例化
//连接相机
//std::cout<<"Connect: "<<camera->connectCamera(1)<<std::endl;
int ret=camera->connectCamera(1);
if(ret!=0)
{
//失败
//QMessageBox::warning()
}
//设置为触发模式 打开
std::cout<<"TriggerMode: "<<camera->setTriggerMode(1)<<std::endl;
//设置触发源为软触发
std::cout<<"TriggerSource: "<<camera->setTriggerSource(7)<<std::endl;
//设置曝光时间
std::cout<<"SetExposureTime: "<<camera->setExposureTime(40000)<<std::endl;
//开启相机采集
std::cout<<"StartCamera: "<<camera->startCamera()<<std::endl;
myThread->getCameraPtr(camera);//把实例化后的海康相机类传入到线程中去
//myThread->getImagePtr(myImage);
}
6.定义线程类(mythread)
1.在线程里面需要包含公共相机的头文件
#include "QThread"//线程
#include "camerainterface.h"//公共相机接口
#include <QImage>
2.头文件定义接收海康相机类的函数
void getCameraPtr(CameraInterface* camera);
3..cpp文件具体实现
//析构函数
MyThread::~MyThread()
{
if(cameraPtr==NULL)
{
delete cameraPtr;
}
}
//具体实现
void MyThread::getCameraPtr(CameraInterface *camera)
{
cameraPtr=camera;
}
7.单次采集
1.在IU界面添加单次采集按钮转跳槽函数
2.需要在主头文件中,private: 下面去声明 bool IsRun = false;(目的是为了更好的调节相机采图启停,方便后续操作(在这里可以不用))
3.转到线程中,去执行停止线程工作内容(因为单次采集不需要启动线程)
//单次采集
void MainWindow::on_btn_Trigger_clicked()
{
HObject image;
HTuple hv_Width,hv_Height;
IsRun =true;//单次采图状态
myThread->ChangeCloseStatus();//线程状态启停
std::cout<<"TriggerMode: "<<camera->setTriggerMode(1)<<std::endl;
std::cout<<"SoftTrigger: "<<camera->softTrigger()<<std::endl;
//读取Mat格式的图像
qDebug()<<"enter1";
camera->ReadBuffer(image); //相机类里面的读图函数
CopyImage(image, &halconImage);
if(ui->checkBox_saveImage->isChecked())
{
//保存图像
QString path="./data/"+QString::number(ui->sB_Num->value())+".png";
WriteImage(halconImage, "png", 0, HTuple(path.toLatin1().data()));
}
GetImageSize(image, &hv_Width, &hv_Height);
SetPart(WindowHandle, 0, 0, hv_Height,hv_Width); // 1944 2592
qDebug()<<"enter2";
DispObj(halconImage, WindowHandle);
//其它图像处理功能
//m_pMeasure01->OutMeasure01(halconImage);
}
4.在线程类中,.h的public:下定义 bool Status=false;
同时定义线程状态启停函数
void ChangeCloseStatus();//关闭
void ChangeOpenStatus();//打开
.cpp文件
void MyThread::ChangeCloseStatus()
{
Status=false;
//qDebug()<<"Status:="<<Status;
}
void MyThread::ChangeOpenStatus()
{
Status=true;
//qDebug()<<"Status:="<<Status;
}
8.连续采集
1.此时需要利用线程进行连续图像采集,需要在主程序中实例化线程类(应该在一开始就实例化)
//线程对象
MyThread* myThread=NULL;
// 线程对象实例化
myThread = new MyThread();
if(myThread!=NULL)
{
delete myThread;
myThread=NULL;
}
2.在IU界面上添加连续采集按钮转到槽函数
void MainWindow::on_lxcj_clicked()
{
std::cout<<"TriggerMode: "<<camera->setTriggerMode(0)<<std::endl;
myThread->ChangeOpenStatus();//打开线程工作内容
if(!IsRun)//判断单次采集是否打开
{
IsRun = false;关闭单次采集
myThread->start();//开启连续彩图线程
}
else
{
IsRun = false;//关闭单次采集
myThread->start();//开启连续彩图线程
}
}
3.在线程类里面
.h文件
void run();//定义run函数(线程里的工作内容)
void display( HObject imagePtr);//(用来其它作用显示)
signals:
void CaptureImage(HObject);//定义一个发送图像的信号
.cpp文件
void MyThread::run()
{
if(cameraPtr==NULL)
{
return;
}
while(!isInterruptionRequested())
{
if(Status) //判断是否停止的状态
{
qDebug()<<"thread current" <<currentThread();
std::cout<<"Thread_Trigger:"<<cameraPtr->softTrigger()<<std::endl;
HObject image;
//读取Mat格式的图像
cameraPtr->ReadBuffer(image);
emit CaptureImage(image);//发送图像信号
msleep(100);
}
}
}
void MyThread::display( HObject imagePtr)
{
//qDebug()<<"Enter2";
//std::cout<<"so"<<std::endl;
//判断是黑白、彩色图像
DispObj((imagePtr), WindowHandle);
QString path="./picture/halcon"+QString::number(1)+".png";
//WriteImage((*imagePtr), "png", 0, HTuple(path.toLatin1().data()));
//int num=ui->sB_Num->value();
//ui->sB_Num->setValue(num+1);
}
4.在线程中发送图像信号之后,需要在主函数中去接收这个图像信号
//信号与槽
connect(myThread,SIGNAL(CaptureImage(HObject)),this,SLOT(ImageProcess01(HObject)),\
Qt::BlockingQueuedConnection);//信号槽函数 。必须display 是slot
private slots:
//显示连续图像,接收槽函数
void ImageProcess01(HObject image); //信号槽函数 --收到图像之后的 图像处理槽函数
//槽函数接收显示图像
void MainWindow::ImageProcess01(HObject halconImage)
{
HTuple hv_Width,hv_Height;
qDebug()<<"Enter1";
GetImageSize(halconImage, &hv_Width, &hv_Height);
SetPart(WindowHandle, 0, 0, hv_Height,hv_Width); // 1944 2592
display(halconImage);
m_pMeasure01->OutMeasure01(halconImage); //输出一个宽度
//tuple -length ,length ==1 识别 成功
//TCP 服务器 发给客户端 ,一个字符串。
myThread->ChangeOpenStatus();//采图 收到图像处理完的信号,可以启动继续采图。同步采集!
qDebug()<<"Enter2";
}
9.停止采集
void MainWindow::on_StopAcquisition_clicked()
{
myThread->ChangeCloseStatus();//停止线程状态
ui->btn_Close->setEnabled(true);
if(IsRun)
{
myThread->requestInterruption();
myThread->wait();//线程等待
IsRun =false;//单次采集关闭
// camera->stopCamera();
// camera->closeCamera();
}
}
10.关闭相机
void MainWindow::on_btn_Close_clicked()
{
ui->btn_Trigger->setEnabled(false);
ui->lxcj->setEnabled(false);
ui->StopAcquisition->setEnabled(false);
if(camera!=NULL)
{
myThread->requestInterruption();
camera->closeCamera();
}
//ui->Image_Label->clear();
ui->btn_Connect->setEnabled(true);
}
11.保存图像
void MainWindow::on_saveImage_clicked()
{
QString filePath ="./data/picture/"+ QDateTime::currentDateTime().toString("yyyy-MM-dd");
HTuple file1=HTuple(filePath.toStdString().c_str());
WriteImage(halconImage, "bmp", 0, file1);
//ui->textBrowser_log->append("write image success.");
}
12.设置曝光、增益
//曝光
void MainWindow::on_pB_exposTime_clicked()
{
int exposTime=ui->sB_exposure->value();
int ret=camera->setExposureTime(exposTime);
qDebug()<<"ret:="<<ret;
}
//增益
void MainWindow::on_pB_setGain_clicked()
{
int Gain =ui->sB_Gain->value();
int ret=camera->setGain(Gain);
qDebug()<<"ret:="<<ret;
}
13.保存参数
//把界面的参数 固化 到 本地文件
void Measure01::on_pB_saveParameters_clicked()
{
/*
AmplitudeThreshold = 23;
RoiWidthLen = 67;
Alpha1 = 3.4;
LineRowStart = 879.281;
LineColumnStart = 1436.34;
LineRowEnd = 1769.58;
LineColumnEnd = 3055.55;
*/
//把界面的参数 赋值 给局部作用域的变量
MeasureParam01.AmplitudeThreshold=ui->SpinBox_AmpThre->value();
MeasureParam01.Alpha1=ui->SpinBox_Alpha1->value();
MeasureParam01.RoiWidthLen=ui->SpinBox_RoiWidthLen->value();
MeasureParam01.LineRowStart=ui->SpinBox_LineRowStart->value();
MeasureParam01.LineColumnStart=ui->SpinBox_LineColumnStart->value();
MeasureParam01.LineRowEnd=ui->SpinBox_LineRowEnd->value();
MeasureParam01.LineColumnEnd=ui->SpinBox_LineColumnEnd->value();
//再通过qsetting的方法 把参数保存到qt 本地的 文件中去
SaveSetting(CONFIG_FILEPATH,"Measure01","AmplitudeThreshold",\
QVariant(MeasureParam01.AmplitudeThreshold));//AmpThre
SaveSetting(CONFIG_FILEPATH,"Measure01","Alpha1",\
QVariant(MeasureParam01.Alpha1));//AmpThre
SaveSetting(CONFIG_FILEPATH,"Measure01","RoiWidthLen",\
QVariant(MeasureParam01.RoiWidthLen));//AmpThre
SaveSetting(CONFIG_FILEPATH,"Measure01","LineRowStart",\
QVariant(MeasureParam01.LineRowStart));//AmpThre
SaveSetting(CONFIG_FILEPATH,"Measure01","LineColumnStart",\
QVariant(MeasureParam01.LineColumnStart));//AmpThre
SaveSetting(CONFIG_FILEPATH,"Measure01","LineRowEnd",\
QVariant(MeasureParam01.LineRowEnd));//AmpThre
SaveSetting(CONFIG_FILEPATH,"Measure01","LineColumnEnd",\
QVariant(MeasureParam01.LineColumnEnd));//AmpThre
}
14.加载参数
构造函数里面
// //把界面的参数 赋值 给局部作用域的变量
//double AmpThre=ui->SpinBox_AmpThre->value();
//再通过qsetting的方法 把参数保存到qt 本地的 文件中去
//SaveSetting(CONFIG_FILEPATH,"Measure01","AmplitudeThreshold",QVariant(AmpThre));//AmpThre
QVariant ValueAmpThre;
QVariant ValueAlpha1;
QVariant ValueRoiWidthLen;
QVariant ValueRowStart;
QVariant ValueColumnStart;
QVariant ValueRowEnd;
QVariant ValueColumnEnd;
LoadSetting(CONFIG_FILEPATH,"Measure01","AmplitudeThreshold",ValueAmpThre);
LoadSetting(CONFIG_FILEPATH,"Measure01","Alpha1",ValueAlpha1);//AmpThre
LoadSetting(CONFIG_FILEPATH,"Measure01","RoiWidthLen",ValueRoiWidthLen);//AmpThre
LoadSetting(CONFIG_FILEPATH,"Measure01","LineRowStart",ValueRowStart);//AmpThre
LoadSetting(CONFIG_FILEPATH,"Measure01","LineColumnStart",ValueColumnStart);//AmpThre
LoadSetting(CONFIG_FILEPATH,"Measure01","LineRowEnd",ValueRowEnd);//AmpThre
LoadSetting(CONFIG_FILEPATH,"Measure01","LineColumnEnd",ValueColumnEnd);//AmpThre
//把QVariant 类型 转换 double 类型
MeasureParam01.AmplitudeThreshold=ValueAmpThre.toDouble();
MeasureParam01.Alpha1=ValueAlpha1.toDouble();
MeasureParam01.RoiWidthLen=ValueRoiWidthLen.toDouble();
MeasureParam01.LineRowStart=ValueRowStart.toDouble();
MeasureParam01.LineColumnStart=ValueColumnStart.toDouble();
MeasureParam01.LineRowEnd=ValueRowEnd.toDouble();
MeasureParam01.LineColumnEnd=ValueColumnEnd.toDouble();
ui->SpinBox_AmpThre->setValue(MeasureParam01.AmplitudeThreshold);
ui->SpinBox_Alpha1->setValue(MeasureParam01.Alpha1);
ui->SpinBox_RoiWidthLen->setValue(MeasureParam01.RoiWidthLen);
ui->SpinBox_LineRowStart->setValue(MeasureParam01.LineRowStart);
ui->SpinBox_LineColumnStart->setValue(MeasureParam01.LineColumnStart);
ui->SpinBox_LineRowEnd->setValue(MeasureParam01.LineRowEnd);
ui->SpinBox_LineColumnEnd->setValue(MeasureParam01.LineColumnEnd);
ui->SpinBox_AmpThre->setStyleSheet("background-color: green");
15.日志类(lxlog)
.h
#ifndef __LX_LOG_H__
#define __LX_LOG_H__
#include<QString>
#include <QTextBrowser>
void WriteLog(QString LogType, QString str);
void MessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg);
#endif
.cpp
#include "lxlog.h"
#include "paramsconfig.h"
#include <QFile>
#include <QTextStream>
#include <QDateTime>
#include <QTextBrowser>
extern QTextBrowser * g_pTb;
void WriteLog(QString LogType, QString str)
{
//文件名
QString filePath = QString(LOG_PATH) + '/'+ QDateTime::currentDateTime().toString("yyyy-MM-dd")+".log";
//时间
QString strToWrite = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
//类型
strToWrite.append(QString(" %1 ").arg(LogType));
//信息
strToWrite.append(QString("%1").arg(str));
QFile file(filePath);
file.open(QIODevice::WriteOnly | QIODevice::Append);
QTextStream text_stream(&file);
text_stream << strToWrite << "\r\n";
file.flush();
file.close();
g_pTb->append(strToWrite);
}
void MessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
QString txtMessage = "";
QString messageType = "";
switch (type) {
case QtDebugMsg: //调试信息提示
messageType = "Debug";
txtMessage = QString("Debug: %1 (%2:%3, %4)\n").arg(msg).arg(context.file).arg(QString::number(context.line)).arg(context.function);
break;
case QtInfoMsg:
messageType = "Info";
txtMessage = QString("Warning: %1 (%2:%3, %4)\n").arg(msg).arg(context.file).arg(QString::number(context.line)).arg(context.function);
break;
case QtWarningMsg: //一般的warning提示
messageType = "Waring";
txtMessage = QString("Warning: %1 (%2:%3, %4)\n").arg(msg).arg(context.file).arg(QString::number(context.line)).arg(context.function);
break;
case QtCriticalMsg: //严重错误提示
messageType = "Critical";
txtMessage = QString("Critical: %1 (%2:%3, %4)\n").arg(msg).arg(context.file).arg(QString::number(context.line)).arg(context.function);
//PostErrorMessage(txtMessage, messageType);
break;
case QtFatalMsg: //致命错误提示
messageType = "Fatal";
txtMessage = QString("Fatal: %1 (%2:%3, %4)\n").arg(msg).arg(context.file).arg(QString::number(context.line)).arg(context.function);
abort();
}
WriteLog(txtMessage, messageType);
}
16.公共参数、结构体类(paramsconfig)
.h
#ifndef PARAMSCONFIG_H
#define PARAMSCONFIG_H
#include <QString>
#include <QVariant>
#define SYS_CONFIG_FILE "./data/sysConfig/params.ini"
#define USER_CONFIG_PATH "./data/userConfig"
#define LOG_PATH "./data/log"
#define TRAIN_FILEPATH "./data/train"
#define CALIB_DATA_PATH "data/calib"
#define IMG_DEPETH_FILEPATH "data/imageDepth"
#define IMG_RAW_FILEPATH "data/imageRaw"
#define MODEL_FILEPATH "data/model"
#define SENCE_FILEPATH "data/sence"
#define CONFIG_FILEPATH "data/config/params.ini"
#define CONFIG_Main_FILEPAT "data/config/my.ini"
#define CONFIG_Face_FILEPAT "data/config/Face.ini"
#define CONFIG_Box_FILEPAT "data/config/Box.ini"
#define CONFIG_CreatModel_FILEPAT "data/config/CreatModel.ini"
#define POSE_TO_HTUPLE(pose, hTuple) {hTuple[0] = pose.x; hTuple[1] = pose.y; hTuple[2] = pose.z; hTuple[3] = pose.rx; hTuple[4] = pose.ry; hTuple[5] = pose.rz; hTuple[6] = 0.0;}
#define HTUPLE_TO_POSE(hTuple, pose) {pose.x = hTuple[0]; pose.y = hTuple[1]; pose.z = hTuple[2]; pose.rx = hTuple[3]; pose.ry = hTuple[4]; pose.rz = hTuple[5];}
#define KD_PI 3.141592653
#define LENGTH_UNIT "mm"
#define LX_STATIONS_NUM 3 // 相机数量
#include "HalconCpp.h"
using namespace HalconCpp;
/**
* measure
*/
typedef struct
{
double AmplitudeThreshold;
double RoiWidthLen;
double Alpha1;
double LineRowStart;
double LineColumnStart;
double LineRowEnd;
double LineColumnEnd;
}MeasureParam;
/**
* pose
*/
typedef struct {
double x; ///X偏移
double y; ///Y偏移
double z; ///Z偏移
double rx; ///X旋转
double ry; ///Y旋转
double rz; ///Z旋转
int type; ///姿态类型
} KD_POSE;
/**
* point select
*/
typedef struct {
double xMin; ///X范围
double xMax; ///X范围
double yMin; ///Y范围
double yMax; ///Y范围
double zMin; ///Z范围
double zMax; ///Z范围
int type; ///备用
} KD_POINT_SELECT;
/**
* 机械臂工具类型
*/
typedef enum {
ROT_TOOL_SUCKER = 0, ///吸盘
ROT_POSE_GRIPPER_PNEUMATIC, ///夹具气动
ROT_POSE_GRIPPER_ELECTRIC, ///夹具电动
}ROT_TOOL_TYPE;
/**
* 三维点云控制参数
*/
typedef struct {
KD_POSE calibPose; ///校正Pose
KD_POINT_SELECT potSelc; ///范围限定
} KD_3D_CTRL; ///三维控制参数
/**
* 三维物体参数
*/
typedef struct {
KD_POSE * pObjChangePose; ///偏移pose
unsigned int surfaceNum; ///面数
double objGuideHigh; ///物体抓取引导高度
} KD_OBJECT_CTRL; ///三维控制参数
/**
* 3d匹配参数
*/
typedef struct {
double objectMaxLength; ///物体最大长度
double sampleDis; ///采样距离
double keyPotFraction; ///特征点最小得分
double minScore; ///最小得分
QString * modelFileName; ///模型文件名
KD_POSE toolInFlangeCenter; ///工具在法兰盘中心(由机械臂标定得出)
KD_POSE camInBase; ///相机在基础 (由halcon手眼标定得出)
KD_POSE toolInObj; ///工具在物体 (由halcon手眼标定得出)
KD_3D_CTRL bgInfo; ///背景抽取参数
} KD_SURFACE_MATCH_CTRL;
/**
* 机械臂参数
*/
typedef struct {
int speed; ///速度(测试用)
double jointVelc; ///角速度
double jointAcc; ///角加速度
double lineVelc; ///线速度
double lineAcc; ///线加速度
int colliClass; ///防撞等级
KD_POSE toolInFlangeCenter; ///工具在法兰盘中心
} KD_ROBOT_CTRL;
/**
* 机械臂码垛参数
*/
typedef struct {
KD_POSE oriPose; ///起始码垛姿态
KD_POSE offsetPose; ///偏移码垛姿态
int palletNum; ///码垛数量
double palletSize; ///工件尺寸
} KD_ROBOT_PALLET_CTRL;
/**
* 机械臂运动参数
*/
typedef struct {
double doorHigh; ///门型高度
int ioId; ///吸盘、夹具IO口
int moveTime; ///机械臂从抓取到放置位置延时时间
int doorUpDownTime; ///门型上下移动延时时间
int suctionTime; ///吸盘、夹具延时时间
KD_POSE halfWayPose; ///中途路点
KD_ROBOT_PALLET_CTRL pallet; ///码垛参数
ROT_TOOL_TYPE toolType; ///工具类型
} KD_ROBOT_MOVE_CTRL;
typedef enum {
UNINIT, //还未初始化
RUNNING, //运行
STOP //停止
}PROGRAM_STATUS;
/**
* DO输出0
*/
typedef enum {
KEY_RELEASE = 0,
KEY1 = 1,
KEY2 = 2,
KEY3 = 4,
KEYS = 8,
KEYU = 16,
KEYD = 32
}HC_KEY_TYPE;
/**
* DO输出1
*/
typedef enum {
DO_NONE = 0,
DO_GUIDE1 = 1, // 推进
DO_GUIDE2 = 2, // 推出
DO_BUZZER = 4,
DO_LIGHT = 8,
DO_BACKUP1 = 16,
DO_BACKUP2 = 32
}HC_DO_TYPE;
/**
* DI输入
*/
typedef enum {
DI_GUIDE1 = 1, // 推进状态
DI_GUIDE2 = 2, // 推出状态
DI_START = 4,
DI_RESET = 8,
DI_STOP = 16,
DI_BACKUP = 32
}HC_DI_TYPE;
/**
* 矩形
*/
typedef struct {
int x;
int y;
int w;
int h;
} LX_RECT;
/**
* 识别参数
*/
typedef struct {
LX_RECT roiRect; ///ROI区域
int erosionVal; ///腐蚀参数
int dilationVal; ///膨胀参数
int noiseArea; ///噪声面积(小于该面积都被认为是噪声)
int decimalPointArea; ///小数点面积
double confidence; ///最低置信率
QString trainFile; ///训练文件
QString usrconfigFile; ///测试项目配置文件
} LX_RECOGNISE_CTRL;
//LX_RECOGNISE_CTRL LX_RECOGNISE_CTRL1;
//LX_RECOGNISE_CTRL LX_RECOGNISE_CTRL2;
/**
* 相机参数
*/
typedef struct {
int exposureTime;
int exposureTimeMin;
int exposureTimeMax;
int gain;
int gainMin;
int gainMax;
// bool bMiroH;
// bool bMiroV;
} LX_CAMERA_CTRL;
/**
* io
*/
typedef struct {
QString key1Do; //io口ID
QString key2Do; //io口ID
QString key3Do; //io口ID
QString keySDo; //io口ID
QString keyUpDo; //io口ID
QString keyDownDo; //io口ID
QString keyBuzzerDo; //io口ID
QString keyStartDi; //io口ID
QString keyResetDi; //io口ID
QString keyStopDi; //io口ID
} LX_IO_CTRL;
/**
* 初始化参数
*/
typedef struct {
int pressTime; ///按下时间
QString defaultVal; ///初始值
} HC_INIT_CTRL;
/**
* 公英制参数
*/
typedef struct {
int unit; ///0为公制值, 1为英制
} HC_METRIC_IMPERIAL_CTRL;
/**
* 数字缺失
*/
typedef struct {
QString defaultVal; ///预设值
} HC_NUM_MISS_CTRL;
/**
* 记忆位
*/
typedef struct {
int pressTime; ///单次上升时间
} HC_MEMORY_POS_CTRL;
/**
* 陀螺仪
*/
typedef struct {
QString defaultVal; ///陀螺仪预设等级
} HC_GYRO_CTRL;
/**
* 上升下降锁
*/
typedef struct {
int pressTime; ///按下时间
} HC_LOCK_CTRL;
/**
* 异常码
*/
//typedef struct {
// int pressTimeE05; ///E05按下时间
//}HC_EXCEPTION_CTRL;
/**
* 手控器检测和预设参数
*/
typedef struct {
HC_INIT_CTRL initCtrl;
HC_METRIC_IMPERIAL_CTRL metricImperialCtrl;
HC_NUM_MISS_CTRL numMisCtrl;
HC_MEMORY_POS_CTRL memoryPosCtrl;
HC_GYRO_CTRL gyroCtrl;
HC_LOCK_CTRL lockCtrl;
int testItem; //测试项
int workStationId;
} LX_HC_CTRL;
/**
*2d模板匹配的预设参数
*/
typedef struct {
double OffsetRow;
double OffsetColumn;
double TPhi;
double TLength1;
double TLength2;
int m_nModecase; // =1
HTuple ModelID;
HObject ShapeModel;
} LX_MATCH_CTRL;
//保存加载配置
void SaveSetting(QString fileName, QString group, QString key, QVariant value);
void LoadSetting(QString fileName, QString group, QString key, QVariant &value);
//保存加载识别配置
void SaveRecogniseCtrl(QString fileName, QString group, LX_RECOGNISE_CTRL recCtrl);
void LoadRecogniseCtrl(QString fileName, QString group, LX_RECOGNISE_CTRL &recCtrl);
//保存加载IO配置
void SaveIoCtrl(QString fileName, QString group, LX_IO_CTRL ioCtrl);
void LoadIoCtrl(QString fileName, QString group, LX_IO_CTRL &ioCtrl);
//保存加载相机配置
void SaveCameraCtrl(QString fileName, QString group, LX_CAMERA_CTRL camCtrl);
void LoadCameraCtrl(QString fileName, QString group, LX_CAMERA_CTRL &camCtrl);
//保存加载手控器配置
void SaveHandCtrlerCtrl(QString fileName, QString group, LX_HC_CTRL hcCtrl);
void LoadHandCtrlerCtrl(QString fileName, QString group, LX_HC_CTRL &hcCtrl);
//保存相机的 产品唯一序列号和工位
void SaveCameraAscn(QString fileName, QString Key,QString CameraNumber );
void LoadCameraAscn(QString fileName, QString Key,QString &CameraNumber );
double AngleToRad(double angle);
double RadToAngle(double rad);
//保存pose
void SavePose(QString group, KD_POSE pose);
//加载pose
void LoadPose(QString group, KD_POSE &pose);
class paramsConfig
{
public:
paramsConfig();
};
#endif // PARAMSCONFIG_H
.cpp
#include "paramsconfig.h"
#include <QSettings>
#include <QDebug>
paramsConfig::paramsConfig()
{
}
void SaveRecogniseCtrl(QString fileName, QString group, LX_RECOGNISE_CTRL recCtrl)
{
}
void SaveCameraCtrl(QString fileName, QString group, LX_CAMERA_CTRL camCtrl)
{ // 淇濆瓨鍔犺浇鐩告満閰嶇疆
SaveSetting(fileName, group, "exposureTime", QVariant(camCtrl.exposureTime));
SaveSetting(fileName, group, "gain", QVariant(camCtrl.gain));
SaveSetting(fileName, group, "gainMin", QVariant(camCtrl.gainMin));
SaveSetting(fileName, group, "gainMax", QVariant(camCtrl.gainMax));
SaveSetting(fileName, group, "exposureTimeMin", QVariant(camCtrl.exposureTimeMin));
SaveSetting(fileName, group, "exposureTimeMax", QVariant(camCtrl.exposureTimeMax));
}
void LoadCameraCtrl(QString fileName, QString group, LX_CAMERA_CTRL &camCtrl)
{ // 鍔犺浇鐩告満閰嶇疆
QVariant qexposureTime;
QVariant qexposureTimeMin;
QVariant qexposureTimeMax;
QVariant qGain;
QVariant qGainMin;
QVariant qGainMax;
LoadSetting(fileName, group, "exposureTime", qexposureTime);
LoadSetting(fileName, group, "exposureTimeMin", qexposureTimeMin);
LoadSetting(fileName, group, "exposureTimeMax", qexposureTimeMax);
LoadSetting(fileName, group, "gain", qGain);
LoadSetting(fileName, group, "gainMin", qGainMin);
LoadSetting(fileName, group, "gainMax", qGainMax);
camCtrl.exposureTime = qexposureTime.toInt();
camCtrl.exposureTimeMin = qexposureTimeMin.toInt();
camCtrl.exposureTimeMax = qexposureTimeMax.toInt();
camCtrl.gain = qGain.toInt();
camCtrl.gainMin = qGainMin.toInt();
camCtrl.gainMax = qGainMax.toInt();
// qDebug()<<"camCtrl.gain"<<camCtrl.gain;
// qDebug()<<"camCtrl.qexposureTime:+"<<camCtrl.exposureTime;
}
void SaveHandCtrlerCtrl(QString fileName, QString group, LX_HC_CTRL hcCtrl)
{
}
void LoadCameraAscn(QString fileName, QString Key, QString &CameraNumber)
{
QString group = "CameraManage";
QVariant ValueCameraNumber;
LoadSetting(fileName,group,Key,ValueCameraNumber);
CameraNumber = ValueCameraNumber.toString();
qDebug() << "CameraName:= " << CameraNumber;
}
void LoadSetting(QString fileName, QString group, QString key, QVariant &value)
{
QSettings settings(fileName,QSettings::IniFormat);
if(group.size() != 0)
{
settings.beginGroup(group);
}
value = settings.value(key);
if(group.size() != 0)
{
settings.endGroup();
}
}
void SaveSetting(QString fileName, QString group, QString key, QVariant value)
{
QSettings settings(fileName, QSettings::IniFormat);
if (group.size() != 0) {
settings.beginGroup(group);
}
settings.setValue(key, value);
if (group.size() != 0) {
settings.endGroup();
}
}
void SavePose(QString group, KD_POSE pose)
{
}
已经看到这里了,点个赞和关注吧!
刚开始写文章,如有不足请多多包含;之后会持续更新关于(halcon学习,VS联合编程,QT联合编程,C++,C#,Opencv图像处理库,三维点云库pcl,相机以及机器人的二次开发)等系统化学习文章。