1、MVS下载
2、安装后找到opencv4的例程:
3、在vs2019工程文件中配置opencv
(1)项目>>>属性>>>VC++目录,分别在包含目录和库目录中添加自己opencv的include文件路径和lib文件路径。
(2)项目>>>属性>>>链接器>>>输入,在附加依赖项中添加需要的库文件名称,如果觉得太麻烦,那么可以把库目录中的以.lib为后缀名的文件名全部添加上去。
4、VS2019配置海康SDK
(1)添加附加包含目录
项目 — 属性 — 属性页 —C/C++ — 常规— 附加包含目录,添加如下路径:
(2)添加附加库目录
项目 — 属性 — 属性页 — 链接器 — 常规— 附加库目录,添加如下路径
(3)添加附加依赖项
项目 — 属性 — 属性页 — 链接器— 输入—附加依赖项,添加
MvCameraControl.lib
5、添加代码在mfc工程中:
(1)在cpp文件中添加函数代码:
注意添加头文件:#include “MvCameraControl.h”
#include <stdio.h>
#include <string.h>
#include "opencv2/core/core_c.h"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include "MvCameraControl.h"
enum CONVERT_TYPE
{
OpenCV_Mat = 0, // ch:Mat图像格式 | en:Mat format
OpenCV_IplImage = 1, // ch:IplImage图像格式 | en:IplImage format
};
// ch:显示枚举到的设备信息 | en:Print the discovered devices' information
void PrintDeviceInfo(MV_CC_DEVICE_INFO* pstMVDevInfo)
{
if (NULL == pstMVDevInfo)
{
printf(" NULL info.\n\n");
return;
}
// 获取图像数据帧仅支持GigE和U3V设备
if (MV_GIGE_DEVICE == pstMVDevInfo->nTLayerType)
{
int nIp1 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24);
int nIp2 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16);
int nIp3 = ((pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8);
int nIp4 = (pstMVDevInfo->SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff);
// ch:显示IP和设备名 | en:Print current ip and user defined name
printf(" IP: %d.%d.%d.%d\n" , nIp1, nIp2, nIp3, nIp4);
printf(" UserDefinedName: %s\n" , pstMVDevInfo->SpecialInfo.stGigEInfo.chUserDefinedName);
printf(" Device Model Name: %s\n\n", pstMVDevInfo->SpecialInfo.stGigEInfo.chModelName);
}
else if (MV_USB_DEVICE == pstMVDevInfo->nTLayerType)
{
printf(" UserDefinedName: %s\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.chUserDefinedName);
printf(" Device Model Name: %s\n\n", pstMVDevInfo->SpecialInfo.stUsb3VInfo.chModelName);
}
else
{
printf(" Not support.\n\n");
}
}
// ch:像素排列由RGB转为BGR | en:Convert pixel arrangement from RGB to BGR
void RGB2BGR( unsigned char* pRgbData, unsigned int nWidth, unsigned int nHeight )
{
if ( NULL == pRgbData )
{
return;
}
// red和blue数据互换
for (unsigned int j = 0; j < nHeight; j++)
{
for (unsigned int i = 0; i < nWidth; i++)
{
unsigned char red = pRgbData[j * (nWidth * 3) + i * 3];
pRgbData[j * (nWidth * 3) + i * 3] = pRgbData[j * (nWidth * 3) + i * 3 + 2];
pRgbData[j * (nWidth * 3) + i * 3 + 2] = red;
}
}
}
// ch:帧数据转换为Mat格式图片并保存 | en:Convert data stream to Mat format then save image
bool Convert2Mat(MV_FRAME_OUT_INFO_EX* pstImageInfo, unsigned char * pData)
{
if (NULL == pstImageInfo || NULL == pData)
{
printf("NULL info or data.\n");
return false;
}
cv::Mat srcImage;
if ( PixelType_Gvsp_Mono8 == pstImageInfo->enPixelType ) // Mono8类型
{
srcImage = cv::Mat(pstImageInfo->nHeight, pstImageInfo->nWidth, CV_8UC1, pData);
}
else if ( PixelType_Gvsp_RGB8_Packed == pstImageInfo->enPixelType ) // RGB8类型
{
// Mat像素排列格式为BGR,需要转换
RGB2BGR(pData, pstImageInfo->nWidth, pstImageInfo->nHeight);
srcImage = cv::Mat(pstImageInfo->nHeight, pstImageInfo->nWidth, CV_8UC3, pData);
}
else
{
printf("Unsupported pixel format\n");
return false;
}
if ( NULL == srcImage.data )
{
printf("Creat Mat failed.\n");
return false;
}
try
{
// ch:保存Mat图片 | en:Save converted image in a local file
cv::imwrite("Image_Mat.bmp", srcImage);
}
catch (cv::Exception& ex)
{
fprintf(stderr, "Exception in saving mat image: %s\n", ex.what());
}
srcImage.release();
return true;
}
// ch:帧数据转换为IplImage格式图片并保存 | en:Convert data stream in Ipl format then save image
bool Convert2Ipl(MV_FRAME_OUT_INFO_EX* pstImageInfo, unsigned char * pData)
{
if (NULL == pstImageInfo || NULL == pData)
{
printf("NULL info or data.\n");
return false;
}
IplImage* srcImage = NULL;
if ( PixelType_Gvsp_Mono8 == pstImageInfo->enPixelType ) // Mono8类型
{
srcImage = cvCreateImage(cvSize(pstImageInfo->nWidth, pstImageInfo->nHeight), IPL_DEPTH_8U, 1);
}
else if ( PixelType_Gvsp_RGB8_Packed == pstImageInfo->enPixelType ) // RGB8类型
{
// IplImage像素排列格式为BGR,需要转换
RGB2BGR(pData, pstImageInfo->nWidth, pstImageInfo->nHeight);
srcImage = cvCreateImage(cvSize(pstImageInfo->nWidth, pstImageInfo->nHeight), IPL_DEPTH_8U, 3);
}
else
{
printf("Unsupported pixel format\n");
return false;
}
if ( NULL == srcImage )
{
printf("Creat IplImage failed.\n");
return false;
}
srcImage->imageData = (char *)pData;
try
{
// ch:保存IplImage图片 | en:Save converted image in a local file
cv::Mat cConvertImage = cv::cvarrToMat(srcImage);
cv::imwrite("Image_Ipl.bmp", cConvertImage);
cConvertImage.release();
}
catch (cv::Exception& ex)
{
fprintf(stderr, "Exception in saving IplImage: %s\n", ex.what());
}
cvReleaseImage(&srcImage);
return true;
}
(2)在按钮响应中复制main函数代码:
代码如下:
int nRet = MV_OK;
void* handle = NULL;
unsigned char * pData = NULL;
do
{
MV_CC_DEVICE_INFO_LIST stDeviceList;
memset(&stDeviceList, 0, sizeof(MV_CC_DEVICE_INFO_LIST));
// ch:设备枚举 | en:Enum device
nRet = MV_CC_EnumDevices(MV_GIGE_DEVICE | MV_USB_DEVICE, &stDeviceList);
if (MV_OK != nRet)
{
printf("Enum Devices fail! nRet [0x%x]\n", nRet);
break;
}
// ch:显示设备信息 | en:Show devices
if (stDeviceList.nDeviceNum > 0)
{
for (unsigned int i = 0; i < stDeviceList.nDeviceNum; i++)
{
printf("[device %d]:\n", i);
MV_CC_DEVICE_INFO* pDeviceInfo = stDeviceList.pDeviceInfo[i];
if (NULL == pDeviceInfo)
{
break;
}
PrintDeviceInfo(pDeviceInfo);
}
}
else
{
printf("Find No Devices!\n");
break;
}
// ch:选择相机 | en:Select device
unsigned int nIndex = 0;
while (1)
{
printf("Please Input camera index(0-%d): ", stDeviceList.nDeviceNum - 1);
if (1 == scanf_s("%d", &nIndex))
{
while (getchar() != '\n')
{
;
}
// 合法输入
if (nIndex >= 0 && nIndex < stDeviceList.nDeviceNum)
{
// 设备不可连接,重新输入
if (false == MV_CC_IsDeviceAccessible(stDeviceList.pDeviceInfo[nIndex], MV_ACCESS_Exclusive))
{
printf("Can't connect! ");
continue;
}
break;
}
}
else
{
while (getchar() != '\n')
{
;
}
}
}
// ch:创建设备句柄 | en:Create handle
nRet = MV_CC_CreateHandle(&handle, stDeviceList.pDeviceInfo[nIndex]);
if (MV_OK != nRet)
{
printf("Create Handle fail! nRet [0x%x]\n", nRet);
break;
}
// ch:打开设备 | en:Open device
nRet = MV_CC_OpenDevice(handle);
if (MV_OK != nRet)
{
printf("Open Device fail! nRet [0x%x]\n", nRet);
break;
}
// ch:探测最佳Packet大小(只支持GigE相机) | en:Detection network optimal package size(It only works for the GigE camera)
if (MV_GIGE_DEVICE == stDeviceList.pDeviceInfo[nIndex]->nTLayerType)
{
int nPacketSize = MV_CC_GetOptimalPacketSize(handle);
if (nPacketSize > 0)
{
// 设置Packet大小
nRet = MV_CC_SetIntValue(handle, "GevSCPSPacketSize", nPacketSize);
if (MV_OK != nRet)
{
printf("Warning: Set Packet Size fail! nRet [0x%x]!", nRet);
}
}
else
{
printf("Warning: Get Packet Size fail! nRet [0x%x]!", nPacketSize);
}
}
// ch:关闭触发模式 | en:Set trigger mode as off
nRet = MV_CC_SetEnumValue(handle, "TriggerMode", 0);
if (MV_OK != nRet)
{
printf("Set Trigger Mode fail! nRet [0x%x]\n", nRet);
break;
}
// ch:获取图像大小 | en:Get payload size
MVCC_INTVALUE stParam;
memset(&stParam, 0, sizeof(MVCC_INTVALUE));
nRet = MV_CC_GetIntValue(handle, "PayloadSize", &stParam);
if (MV_OK != nRet)
{
printf("Get PayloadSize fail! nRet [0x%x]\n", nRet);
break;
}
unsigned int nPayloadSize = stParam.nCurValue;
// ch:初始化图像信息 | en:Init image info
MV_FRAME_OUT_INFO_EX stImageInfo = { 0 };
memset(&stImageInfo, 0, sizeof(MV_FRAME_OUT_INFO_EX));
pData = (unsigned char *)malloc(sizeof(unsigned char)* (nPayloadSize));
if (NULL == pData)
{
printf("Allocate memory failed.\n");
break;
}
memset(pData, 0, sizeof(pData));
// ch:开始取流 | en:Start grab image
nRet = MV_CC_StartGrabbing(handle);
if (MV_OK != nRet)
{
printf("Start Grabbing fail! nRet [0x%x]\n", nRet);
break;
}
// ch:获取一帧图像,超时时间1000ms | en:Get one frame from camera with timeout=1000ms
nRet = MV_CC_GetOneFrameTimeout(handle, pData, nPayloadSize, &stImageInfo, 1000);
if (MV_OK == nRet)
{
printf("Get One Frame: Width[%d], Height[%d], FrameNum[%d]\n",
stImageInfo.nWidth, stImageInfo.nHeight, stImageInfo.nFrameNum);
}
else
{
printf("Get Frame fail! nRet [0x%x]\n", nRet);
break;
}
// ch:停止取流 | en:Stop grab image
nRet = MV_CC_StopGrabbing(handle);
if (MV_OK != nRet)
{
printf("Stop Grabbing fail! nRet [0x%x]\n", nRet);
break;
}
// ch:关闭设备 | en:Close device
nRet = MV_CC_CloseDevice(handle);
if (MV_OK != nRet)
{
printf("ClosDevice fail! nRet [0x%x]\n", nRet);
break;
}
// ch:输入要转换的格式 | en:Input the format to convert
printf("\n[0] OpenCV_Mat\n");
printf("[1] OpenCV_IplImage\n");
int nFormat = 0;
while (1)
{
printf("Please Input Format to convert: ");
if (1 == scanf_s("%d", &nFormat))
{
// 合法输入
if (0 == nFormat || 1 == nFormat)
{
break;
}
}
while (getchar() != '\n')
{
;
}
}
// ch:数据转换 | en:Convert image data
bool bConvertRet = false;
if (OpenCV_Mat == nFormat)
{
bConvertRet = Convert2Mat(&stImageInfo, pData);
}
else if (OpenCV_IplImage == nFormat)
{
bConvertRet = Convert2Ipl(&stImageInfo, pData);
}
// ch:显示转换结果 | en:Print result
if (bConvertRet)
{
printf("OpenCV format convert finished.\n");
}
else
{
printf("OpenCV format convert failed.\n");
}
} while (0);
// ch:销毁句柄 | en:Destroy handle
if (handle)
{
MV_CC_DestroyHandle(handle);
handle = NULL;
}
// ch:释放内存 | en:Free memery
if (pData)
{
free(pData);
pData = NULL;
}
system("pause");
return 0;
6、添加万代码后由于在mfc无法调用cmd控制台直接printf例程中的信息,参考:https://blog.csdn.net/qq_41899087/article/details/115164833
进行更改:(1)添加函数:
//在cmd控制台中输出信息
void InitConsoleWindows()
{
/*为调用进程分配一个新的控制台*/
AllocConsole();
#if _MSC_VER <= 1200 //这个是vc6.0
freopen("CONOUT$", "w+t", stdout);
#else //这个是vc2003以上
FILE* stream;
freopen_s(&stream, "CONOUT$", "wt", stdout);
#endif // _MSC_VER > 1000
}
(2)在初始化函数中初始化次函数:
BOOL CMFCdetectDlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
//在cmd控制台中输出信息
**InitConsoleWindows();**
// 将“关于...”菜单项添加到系统菜单中。
// IDM_ABOUTBOX 必须在系统命令范围内。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != nullptr)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标
// TODO: 在此添加额外的初始化代码
GetDlgItem(IDC_SHOW)->GetClientRect(&rect);
cv::Rect dst(rect.left, rect.top, rect.right, rect.bottom);
cv::namedWindow("image", cv::WINDOW_AUTOSIZE);//设置窗口名
HWND hPictureWindow = (HWND)cvGetWindowHandle("image");//hWnd 表示窗口句柄,获取窗口句柄
HWND hParentWindow = ::GetParent(hPictureWindow);//GetParent函数一个指定子窗口的父窗口句柄
::SetParent(hPictureWindow, GetDlgItem(IDC_SHOW)->m_hWnd);
::ShowWindow(hParentWindow, SW_HIDE);
return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
}
添加后运行程序便能弹出控制台并输出printf函数的内容: