思路:
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;//讀取buffervirtual 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;//設置圖像水平偏移OffsetXvirtual int setOffsetX(unsigned int offsetX)=0;//設置圖像豎直偏移OffsetYvirtual 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();//讀取bufferint ReadBuffer(HObject &image);//設置圖像高度int setHeight(unsigned int height);//設置圖像ROI寬度int setWidth(unsigned int width);//獲取圖像高度值int getHeight();//獲取圖像寬度值int getWidth();//獲取相機曝光時間float getExposureTime();//設置圖像水平偏移OffsetXint setOffsetX(unsigned int offsetX);//設置圖像豎直偏移OffsetYint 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 deviceMV_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 handlenRet = MV_CC_CreateHandle(&m_hDevHandle, stDeviceList.pDeviceInfo[nIndex]);if (nRet!=0){//printf("Create Handle fail! nRet [0x%x]\n", nRet);return -1;}// open devicenRet = 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{//轉換圖像格式為BGR8MV_CC_PIXEL_CONVERT_PARAM stConvertParam = {0};memset(&stConvertParam, 0, sizeof(MV_CC_PIXEL_CONVERT_PARAM));stConvertParam.nWidth = stImageInfo.nWidth; //ch:圖像寬 | en:image widthstConvertParam.nHeight = stImageInfo.nHeight; //ch:圖像高 | en:image height//stConvertParam.pSrcData = m_pBufForDriver; //ch:輸入數據緩存 | en:input data bufferstConvertParam.pSrcData = pDate; //ch:輸入數據緩存 | en:input data bufferstConvertParam.nSrcDataLen = stImageInfo.nFrameLen; //ch:輸入數據大小 | en:input data sizestConvertParam.enSrcPixelType = stImageInfo.enPixelType; //ch:輸入像素格式 | en:input pixel formatstConvertParam.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 bufferstConvertParam.nDstBufferSize = m_nBufSizeForSaveImage; //ch:輸出緩存大小 | en:output buffer sizeMV_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:Onint 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:Softwareint 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)
{//心跳時間最小為500msif(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 2592qDebug()<<"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 2592display(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));//AmpThreSaveSetting(CONFIG_FILEPATH,"Measure01","Alpha1",\QVariant(MeasureParam01.Alpha1));//AmpThreSaveSetting(CONFIG_FILEPATH,"Measure01","RoiWidthLen",\QVariant(MeasureParam01.RoiWidthLen));//AmpThreSaveSetting(CONFIG_FILEPATH,"Measure01","LineRowStart",\QVariant(MeasureParam01.LineRowStart));//AmpThreSaveSetting(CONFIG_FILEPATH,"Measure01","LineColumnStart",\QVariant(MeasureParam01.LineColumnStart));//AmpThreSaveSetting(CONFIG_FILEPATH,"Measure01","LineRowEnd",\QVariant(MeasureParam01.LineRowEnd));//AmpThreSaveSetting(CONFIG_FILEPATH,"Measure01","LineColumnEnd",\QVariant(MeasureParam01.LineColumnEnd));//AmpThre}
14.加載參數
構造函數里面
// //把界面的參數 賦值 給局部作用域的變量//double AmpThre=ui->SpinBox_AmpThre->value();//再通過qsetting的方法 把參數保存到qt 本地的 文件中去//SaveSetting(CONFIG_FILEPATH,"Measure01","AmplitudeThreshold",QVariant(AmpThre));//AmpThreQVariant 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);//AmpThreLoadSetting(CONFIG_FILEPATH,"Measure01","RoiWidthLen",ValueRoiWidthLen);//AmpThreLoadSetting(CONFIG_FILEPATH,"Measure01","LineRowStart",ValueRowStart);//AmpThreLoadSetting(CONFIG_FILEPATH,"Measure01","LineColumnStart",ValueColumnStart);//AmpThreLoadSetting(CONFIG_FILEPATH,"Measure01","LineRowEnd",ValueRowEnd);//AmpThreLoadSetting(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; ///校正PoseKD_POINT_SELECT potSelc; ///范圍限定
} KD_3D_CTRL; ///三維控制參數/*** 三維物體參數*/
typedef struct {KD_POSE * pObjChangePose; ///偏移poseunsigned 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口IDQString key2Do; //io口IDQString key3Do; //io口IDQString keySDo; //io口IDQString keyUpDo; //io口IDQString keyDownDo; //io口IDQString keyBuzzerDo; //io口IDQString keyStartDi; //io口IDQString keyResetDi; //io口IDQString 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; // =1HTuple 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,相機以及機器人的二次開發)等系統化學習文章。