Qt环境下调用OpenCV和海康摄像头数据实现目标检测

项目目的

目前实验室在做一个项目,需要将深度学习模块嵌入到上位机中,实现检测螺栓目的,并在上位机界面中实时显示。

Step1 运行环境和准备

系统:Windows10
Qt版本:5.14
OpenCV版本:4.3(搭载Dnn模块)
海康网络摄像头
深度网络模型:YoloV3 Kers
可选装加速模块:
CUDA/OpenVino
加速模块挺重要的,对于实际项目来说,实时性是很重要的指标,因此对于这两个模块在Qt上的使用我会接下来继续写博客!

运行环境配置:
Qt和OpenCV环境配置可参考这些链接:QT+opencv的环境配置1
QT+opencv的环境配置2
海康SDK:海康摄像头SDK下载
海康sdk也是一个小坑,目前用的是32位版本的,用64位的时候会报错,欢迎大家一起交流一下!
模型的封装与训练可以看这个博主的很多文章,挺有参考价值的模型训练
海康视频流取流是一个坑,由于海康的视频流是YV12格式,Qt无法直接读取,需要转成RGB,这时候就需要OpenCV对采集到的视频进行处理。可以参考以下文章:海康威视摄像头+OpenCV+VS2017 图像处理小结
OpenCV+海康威视摄像头的实时读取
废话不多说勒直接看代码

Step2 代码整体结构

Ui界面设置
UI界面
Pro文件

#-------------------------------------------------
#
# Project created by QtCreator 2019-07-26T10:07:17
#
#-------------------------------------------------QT       += core gui sql
QT       += network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgetsTARGET = Camera
TEMPLATE = app# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0CONFIG += c++11SOURCES += \HK_camera.cpp \main.cppHEADERS += \HK_camera.h \robot.h \comfunction.hFORMS += \HK_camera.uiINCLUDEPATH += D:\SDK\CH-HCNetSDK_32\includes\INCLUDEPATH += D:\SDK\CH-HCNetSDK_32\libs\INCLUDEPATH +=  D:\SDK\CH-HCNetSDK_32\libs\HCNetSDKCom\INCLUDEPATH += D:\SDK\CH-HCNetSDK_32\libs\ClientDemoDll\
INCLUDEPATH += D:\Software\opencv4.3\build\includeLIBS +=D:\SDK\CH-HCNetSDK_32\libs\HCNetSDK.lib\
D:\SDK\CH-HCNetSDK_32\libs\PlayCtrl.lib\
D:\SDK\CH-HCNetSDK_32\libs\HCCore.lib\
D:\SDK\CH-HCNetSDK_32\libs\GdiPlus.libLIBS += D:\Software\opencv4.3\opencv-build\bin\libopencv_calib3d430.dll
LIBS += D:\Software\opencv4.3\opencv-build\bin\libopencv_core430.dll
LIBS += D:\Software\opencv4.3\opencv-build\bin\libopencv_dnn430.dll
LIBS += D:\Software\opencv4.3\opencv-build\bin\libopencv_features2d430.dll
LIBS += D:\Software\opencv4.3\opencv-build\bin\libopencv_flann430.dll
LIBS += D:\Software\opencv4.3\opencv-build\bin\libopencv_highgui430.dll
LIBS += D:\Software\opencv4.3\opencv-build\bin\libopencv_imgcodecs430.dll
LIBS += D:\Software\opencv4.3\opencv-build\bin\libopencv_imgproc430.dll
LIBS += D:\Software\opencv4.3\opencv-build\bin\libopencv_ml430.dll
LIBS += D:\Software\opencv4.3\opencv-build\bin\libopencv_objdetect430.dll
LIBS += D:\Software\opencv4.3\opencv-build\bin\libopencv_photo430.dll
LIBS += D:\Software\opencv4.3\opencv-build\bin\libopencv_stitching430.dll
LIBS += D:\Software\opencv4.3\opencv-build\bin\libopencv_video430.dll
LIBS += D:\Software\opencv4.3\opencv-build\bin\libopencv_videoio430.dll# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += targetRESOURCES += \image.qrc

海康回传视频流代码

void CALLBACK DecCBFun(long nPort, char * pBuf, long nSize, FRAME_INFO * pFrameInfo, long nReserved1, long nReserved2)
#else
void MyWidget::DecCBFun(long nPort, char *pBuf, long nSize, FRAME_INFO *pFrameInfo, long nReserved1, long nReserved2)
#endif
{long lFrameType = pFrameInfo->nType;if (lFrameType == T_YV12){qDebug()<<"8888";VideoCapture capture;Mat dst(pFrameInfo->nHeight, pFrameInfo->nWidth, CV_8UC3);//这里nHeight为720,nWidth为1280,8UC3表示8bit uchar 无符号类型,3通道值,输出Mat src(pFrameInfo->nHeight + pFrameInfo->nHeight / 2, pFrameInfo->nWidth, CV_8UC1, (uchar*)pBuf);//输入cvtColor(src,dst,CV_YUV2BGR_YV12);MyWidget::Detection(dst);//目标检测/******opencv直接显示****/
//          imshow("bgr",dst);
//          waitKey(1);//此时是YV12格式的视频数据,保存在pBuf中,可以fwrite(pBuf,nSize,1,Videofile);//fwrite(pBuf,nSize,1,fp);}/***************else if (lFrameType ==T_AUDIO16){//此时是音频数据,数据保存在pBuf中,可以fwrite(pBuf,nSize,1,Audiofile);}else{}*******************/}
void MyWidget::fRealDataCallBack(LONG lRealPlayHandle, DWORD dwDataType, BYTE *pBuffer, DWORD dwBufSize, void *pUser)
{DWORD dRet = 0;BOOL inData = FALSE;switch (dwDataType){case NET_DVR_SYSHEAD:    //系统头if (nPort >= 0){break; //同一路码流不需要多次调用开流接口}if (!PlayM4_GetPort(&nPort)) //获取播放库未使用的通道号{break;}if (dwBufSize > 0){if (!PlayM4_SetStreamOpenMode(nPort, STREAME_REALTIME))  //设置实时流播放模式{cout << "PlayM4_SetStreamOpenMode failed " << endl;break;}if (!PlayM4_OpenStream(nPort, pBuffer, dwBufSize, 1024*100000))   //查询{cout << "PlayM4_OpenStream failed " << endl;dRet = PlayM4_GetLastError(nPort);break;}//设置解码回调函数 只解码不显示if (!PlayM4_SetDecCallBack(nPort, DecCBFun))                    //查询{dRet = PlayM4_GetLastError(nPort);break;}//设置解码回调函数 解码且显示//if (!PlayM4_SetDecCallBackEx(nPort,DecCBFun,NULL,NULL))//{//  dRet=PlayM4_GetLastError(nPort);//  break;//}//打开视频解码if (!PlayM4_Play(nPort, hWnd)){dRet = PlayM4_GetLastError(nPort);break;}//打开音频解码, 需要码流是复合流/*if (!PlayM4_PlaySound(nPort)){dRet = PlayM4_GetLastError(nPort);break;}*/}break;case NET_DVR_STREAMDATA:   //码流数据inData = PlayM4_InputData(nPort, pBuffer, dwBufSize);while (!inData){Sleep(10);inData = PlayM4_InputData(nPort, pBuffer, dwBufSize);cout << "PlayM4_InputData failed 11111" << endl;qDebug()<<"error"<<PlayM4_GetLastError(nPort);break;}break;default:inData = PlayM4_InputData(nPort, pBuffer, dwBufSize);while (!inData){Sleep(10);inData = PlayM4_InputData(nPort, pBuffer, dwBufSize);cout << "PlayM4_InputData failed 22222" << endl;break;}break;}
}void CALLBACK g_ExceptionCallBack(DWORD dwType, LONG lUserID, LONG lHandle, void *pUser)
{char tempbuf[256] = { 0 };switch (dwType){case EXCEPTION_RECONNECT:    //预览时重连cout << "----------reconnect--------" << endl;break;default:break;}
}void MyWidget::camera_login()
{//---------------------------------------// 初始化NET_DVR_Init();//设置连接时间与重连时间NET_DVR_SetConnectTime(2000, 1);NET_DVR_SetReconnect(10000, true);//设置异常消息回调函数NET_DVR_SetExceptionCallBack_V30(0,NULL,g_ExceptionCallBack,NULL);//注册设备LONG lUserID = -1;NET_DVR_USER_LOGIN_INFO struLoginInfo = {0};struLoginInfo.bUseAsynLogin = 0; //同步登录方式strcpy(struLoginInfo.sDeviceAddress, "192.168.0.118"); //设备IP地址struLoginInfo.wPort = 8000; //设备服务端口strcpy(struLoginInfo.sUserName, "admin"); //设备登录用户名strcpy(struLoginInfo.sPassword, "admin12345"); //设备登录密码//设备信息, 输出参数NET_DVR_DEVICEINFO_V40 struDeviceInfoV40 = {0};lUserID = NET_DVR_Login_V40(&struLoginInfo, &struDeviceInfoV40);qDebug()<<lUserID<<endl;if(lUserID < 0){qDebug()<<"login Err="<<NET_DVR_GetLastError();return;//NET_DVR_Cleanup();}NET_DVR_PREVIEWINFO struPlayInfo={0};//启动预览struPlayInfo.hPlayWnd = NULL;struPlayInfo.lChannel = 1;                //预览通道struPlayInfo.dwStreamType = 0;      //0主码流struPlayInfo.dwLinkMode = 0;        //TCP方式struPlayInfo.bBlocked = 1; //0- 非阻塞取流,1- 阻塞取流LONG lRealPlayHandle;qDebug()<<"6666";lRealPlayHandle  = NET_DVR_RealPlay_V40(lUserID, &struPlayInfo, fRealDataCallBack, NULL);if ( lRealPlayHandle < 0){qDebug()<<"error"<<NET_DVR_GetLastError();qDebug()<<NET_DVR_GetLastError()<<NET_DVR_GetErrorMsg();return;}}//Mat转成QImage
QImage MyWidget::MatImageToQt(const Mat &src)
{//CV_8UC1 8位无符号的单通道---灰度图片if(src.type() == CV_8UC1){//使用给定的大小和格式构造图像//QImage(int width, int height, Format format)QImage qImage(src.cols,src.rows,QImage::Format_Indexed8);//扩展颜色表的颜色数目qImage.setColorCount(256);//在给定的索引设置颜色for(int i = 0; i < 256; i ++){//得到一个黑白图qImage.setColor(i,qRgb(i,i,i));}//复制输入图像,data数据段的首地址uchar *pSrc = src.data;//for(int row = 0; row < src.rows; row ++){//遍历像素指针uchar *pDest = qImage.scanLine(row);//从源src所指的内存地址的起始位置开始拷贝n个//字节到目标dest所指的内存地址的起始位置中memcmp(pDest,pSrc,src.cols);//图像层像素地址pSrc += src.step;}return qImage;}//为3通道的彩色图片else if(src.type() == CV_8UC3){//得到图像的的首地址const uchar *pSrc = (const uchar*)src.data;//以src构造图片QImage qImage(pSrc,src.cols,src.rows,src.step,QImage::Format_RGB888);//在不改变实际图像数据的条件下,交换红蓝通道return qImage.rgbSwapped();}//四通道图片,带Alpha通道的RGB彩色图像else if(src.type() == CV_8UC4){const uchar *pSrc = (const uchar*)src.data;QImage qImage(pSrc, src.cols, src.rows, src.step, QImage::Format_ARGB32);//返回图像的子区域作为一个新图像return qImage.copy();}else{return QImage();}
}

结果展示

在这里插入图片描述

后期展望

接下来会着重写一个如何在Qt中使用Opencv进行深度学习推理,把一些最新加速工具用进来

项目代码

源程序


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部