// Demo_MFCDlg.cpp : 实现文件 // #include "stdafx.h" #include "Demo_MFC.h" #include "Demo_MFCDlg.h" #include "afxdialogex.h" #include "CWFaceConfig.h" #include "CWFaceDetection.h" #include "CWFaceRecognition.h" #include "CWFaceVersion.h" #define MAX_NUM_FACES 3 // 检测的人脸数 #define MAX_DET_NUM_FACES 10 // 检测线程的人脸数 #define VERIFY_SHRELHOD 70 // 比对阈值 #define CW_LICENCE "" // 云从授权码 #define WM_THREAD_SHOWVIDEO WM_USER + 101 // 自定义消息 //线条颜色,画框的 static cv::Scalar& color = cv::Scalar(0, 0, 255); static cv::Scalar& colorGreen = cv::Scalar(0, 255, 0); #ifdef _DEBUG #define new DEBUG_NEW #endif // CDemo_MFCDlg 对话框 CDemo_MFCDlg::CDemo_MFCDlg(CWnd* pParent /*=NULL*/) : CDialogEx(CDemo_MFCDlg::IDD, pParent) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); m_pDetHandle = nullptr; m_pDetVerify = nullptr; m_pRecogHandle = nullptr; m_bStartThread = false; } void CDemo_MFCDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Control(pDX, IDC_EDIT_SCORE, m_edtVerifyScore); DDX_Control(pDX, IDC_EDIT_RESULT, m_edtVerifyResult); DDX_Control(pDX, IDC_EDIT_TIME, m_edtVerifyTime); DDX_Control(pDX, IDC_STATIC_PIC1, m_staticPic1); DDX_Control(pDX, IDC_STATIC_PIC2, m_staticPic2); DDX_Control(pDX, IDC_EDIT_VERSION, m_edtVersion); DDX_Control(pDX, IDC_STATIC_VIDEO, m_staticVideo); DDX_Control(pDX, IDC_STATIC_PIC3, m_staticPic3); DDX_Control(pDX, IDC_EDIT_FACEBUF, m_edtFaceBuf); } BEGIN_MESSAGE_MAP(CDemo_MFCDlg, CDialogEx) ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BTN_LOAD1, &CDemo_MFCDlg::OnBnClickedBtnLoad1) ON_BN_CLICKED(IDC_BTN_LOAD2, &CDemo_MFCDlg::OnBnClickedBtnLoad2) ON_BN_CLICKED(IDC_BTN_VERIFY, &CDemo_MFCDlg::OnBnClickedBtnVerify) ON_BN_CLICKED(IDC_BTN_INIT, &CDemo_MFCDlg::OnBnClickedBtnInit) ON_BN_CLICKED(IDC_BTN_CAMERA1, &CDemo_MFCDlg::OnBnClickedBtnCamera1) ON_BN_CLICKED(IDC_BTN_CAMERA2, &CDemo_MFCDlg::OnBnClickedBtnCamera2) ON_BN_CLICKED(IDC_BTN_OPENUSB, &CDemo_MFCDlg::OnBnClickedBtnOpenusb) ON_MESSAGE(WM_THREAD_SHOWVIDEO, &CDemo_MFCDlg::OnThreadShowVideo) ON_BN_CLICKED(IDC_BTN_DET, &CDemo_MFCDlg::OnBnClickedBtnDet) ON_BN_CLICKED(IDC_BTN_LOAD3, &CDemo_MFCDlg::OnBnClickedBtnLoad3) END_MESSAGE_MAP() // CDemo_MFCDlg 消息处理程序 BOOL CDemo_MFCDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 m_staticPic1.GetClientRect(&m_rectPic1); m_hDCPic1 = m_staticPic1.GetDC()->GetSafeHdc(); m_staticPic2.GetClientRect(&m_rectPic2); m_hDCPic2 = m_staticPic2.GetDC()->GetSafeHdc(); m_staticPic3.GetClientRect(&m_rectPic3); m_hDCPic3 = m_staticPic3.GetDC()->GetSafeHdc(); m_staticVideo.GetClientRect(&m_rectVideo); m_hDCVideo = m_staticVideo.GetDC()->GetSafeHdc(); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CDemo_MFCDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中 int cxIcon = GetSystemMetrics(SM_CXICON); int cyIcon = GetSystemMetrics(SM_CYICON); CRect rect; GetClientRect(&rect); int x = (rect.Width() - cxIcon + 1) / 2; int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标 dc.DrawIcon(x, y, m_hIcon); } else { CDialogEx::OnPaint(); } } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CDemo_MFCDlg::OnQueryDragIcon() { return static_cast(m_hIcon); } // [3/3/2017 Lit]:导入图片1 void CDemo_MFCDlg::OnBnClickedBtnLoad1() { // TODO: 在此添加控件通知处理程序代码 CFileDialog dlg(TRUE, _T("jpg|bmp|png"), NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("Image Files(*.jpg;*.bmp;*.png)|*.jpg;*.bmp;*.png|All Files(*.*)|*.*||"), this); if (IDOK != dlg.DoModal()) { return; } m_sPic1Path = dlg.GetPathName(); ShowImg(m_sPic1Path, m_hDCPic1, m_rectPic1); } // [3/3/2017 Lit]:导入图片2 void CDemo_MFCDlg::OnBnClickedBtnLoad2() { // TODO: 在此添加控件通知处理程序代码 CFileDialog dlg(TRUE, _T("jpg|bmp|png"), NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("Image Files(*.jpg;*.bmp;*.png)|*.jpg;*.bmp;*.png|All Files(*.*)|*.*||"), this); if (IDOK != dlg.DoModal()) { return; } m_sPic2Path = dlg.GetPathName(); ShowImg(m_sPic2Path, m_hDCPic2, m_rectPic2); } // [3/30/2017 Lit]:给图片1拍照 void CDemo_MFCDlg::OnBnClickedBtnCamera1() { // TODO: 在此添加控件通知处理程序代码 if (!m_bStartThread) { MessageBox(_T("请先打开摄像头")); return; } { std::lock_guard lock(m_mutex); if (!m_matFrame.empty()) { cv::imwrite("./1.jpg", m_matFrame); } else { return; } } m_sPic1Path = "./1.jpg"; ShowImg(m_sPic1Path, m_hDCPic1, m_rectPic1); } // [3/30/2017 Lit]:给图片2拍照 void CDemo_MFCDlg::OnBnClickedBtnCamera2() { // TODO: 在此添加控件通知处理程序代码 if (!m_bStartThread) { MessageBox(_T("请先打开摄像头")); return; } { std::lock_guard lock(m_mutex); if (!m_matFrame.empty()) { cv::imwrite("./2.jpg", m_matFrame); } else { return; } } m_sPic2Path = "./2.jpg"; ShowImg(m_sPic2Path, m_hDCPic2, m_rectPic2); } // [3/14/2017 Lit]:初始化事件 void CDemo_MFCDlg::OnBnClickedBtnInit() { // TODO: 在此添加控件通知处理程序代码 char szVersion[100] = {0}; cw_errcode_t errCode = cwGetSDKVersion(szVersion, 100); m_edtVersion.SetWindowText((CString)szVersion); // [3/3/2017 Lit]:创建句柄 if (m_pDetHandle != nullptr && m_pDetVerify != nullptr && m_pRecogHandle != nullptr) { MessageBox(_T("已初始化过,不再初始化")); return; } if (CreateFaceHandle()) { MessageBox(_T("初始化成功")); } } // [3/30/2017 Lit]:打开摄像头,开启检测线程 void CDemo_MFCDlg::OnBnClickedBtnOpenusb() { // TODO: 在此添加控件通知处理程序代码 if (nullptr == m_pDetHandle) { MessageBox(_T("检测句柄为空,请先初始化创建句柄")); return; } if (m_bStartThread) { MessageBox(_T("摄像头已打开")); return; } if (!m_capture.open(0)) { MessageBox(_T("摄像头打开失败")); return; } m_bStartThread = true; m_threadFaceDet = std::thread(&CDemo_MFCDlg::ThreadFaceDet, this); m_threadFaceDet.detach(); } void CDemo_MFCDlg::ThreadFaceDet() { cv::Mat matImage; cw_face_res_t faceBuffers[MAX_DET_NUM_FACES]; while (m_bStartThread) { { std::lock_guard lock(m_mutex); m_capture >> m_matFrame; if (m_matFrame.empty()) { continue; } matImage = m_matFrame.clone(); } // 给图像结构体赋值 cw_img_t srcImg; srcImg.frameId = 0; srcImg.data = (char*)matImage.data; srcImg.width = matImage.cols; srcImg.height = matImage.rows; srcImg.angle = CW_IMAGE_ANGLE_0; if (matImage.channels() ==1 ) { srcImg.format = CW_IMAGE_GRAY8; } else if (matImage.channels() == 3) { srcImg.format = CW_IMAGE_BGR888; } else if (matImage.channels() == 4) { srcImg.format = CW_IMAGE_BGRA8888; } else { continue; } // 人脸检测 int iFaceNum = 0; cw_errcode_t errCode = cwFaceDetection(m_pDetHandle, &srcImg, faceBuffers, MAX_DET_NUM_FACES, &iFaceNum, CW_OP_DET); for (int i = 0; i < iFaceNum; i++) { cv::Point dst1(faceBuffers[i].faceRect.x, faceBuffers[i].faceRect.y); cv::Point dst2(faceBuffers[i].faceRect.x + faceBuffers[i].faceRect.width, faceBuffers[i].faceRect.y + faceBuffers[i].faceRect.height); //画框 cv::rectangle(matImage, dst1, dst2, color, 3); } SendMessage(WM_THREAD_SHOWVIDEO, 0, (LPARAM)&matImage); } } LRESULT CDemo_MFCDlg::OnThreadShowVideo(WPARAM wPapam, LPARAM lPapam) { cv::Mat matImage = *((cv::Mat*)lPapam); if (!matImage.empty()) { ShowVideo((char*)(matImage.data), matImage.cols, matImage.rows); } return 0; } // [3/3/2017 Lit]:人脸比对 void CDemo_MFCDlg::OnBnClickedBtnVerify() { // TODO: 在此添加控件通知处理程序代码 if (m_sPic1Path.IsEmpty()) { MessageBox(_T("请先导入第一张图")); return; } if (m_sPic2Path.IsEmpty()) { MessageBox(_T("请先导入第二张图")); return; } if (m_pDetVerify == nullptr) { MessageBox(_T("检测句柄为空,请先初始化创建句柄")); return; } if (m_pRecogHandle == nullptr) { MessageBox(_T("识别句柄为空,请先初始化创建句柄")); return; } m_edtVerifyScore.SetWindowText(_T("")); m_edtVerifyResult.SetWindowText(_T("")); m_edtVerifyTime.SetWindowText(_T("")); DWORD tmBegin = GetTickCount(); int iFeaLen = cwGetFeatureLength(m_pRecogHandle); char *pFeaFiled = new char[iFeaLen]; if (0 == GetFeatureFromPath(m_sPic1Path, pFeaFiled)) { char *pFeaProbe = new char[iFeaLen]; if (0 == GetFeatureFromPath(m_sPic2Path, pFeaProbe)) { float scores[1] = {0.0}; cw_errcode_t errCode = cwComputeMatchScore(m_pRecogHandle, pFeaProbe, pFeaFiled, 1, scores); if (CW_SDKLIT_OK == errCode) { CString sScore, sResult, sTime; sScore.Format(_T("%.6f"), scores[0]); sTime.Format(_T("%d ms"), GetTickCount() - tmBegin); if (int(scores[0] * 100) > VERIFY_SHRELHOD) { sResult = _T("比对通过"); } else { sResult = _T("比对不通过"); } m_edtVerifyScore.SetWindowText(sScore); m_edtVerifyResult.SetWindowText(sResult); m_edtVerifyTime.SetWindowText(sTime); } else { CString sTip; sTip.Format(_T("比对错误:%d"), errCode); MessageBox(sTip); } } delete[] pFeaProbe; pFeaProbe = nullptr; } delete[] pFeaFiled; pFeaFiled = nullptr; } void CDemo_MFCDlg::OnBnClickedBtnLoad3() { // TODO: 在此添加控件通知处理程序代码 CFileDialog dlg(TRUE, _T("jpg|bmp|png"), NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, _T("Image Files(*.jpg;*.bmp;*.png)|*.jpg;*.bmp;*.png|All Files(*.*)|*.*||"), this); if (IDOK != dlg.DoModal()) { return; } m_sPic3Path = dlg.GetPathName(); ShowImg(m_sPic3Path, m_hDCPic3, m_rectPic3); } // [7/19/2017 Lit]:人脸检测,关键点,质量分 void CDemo_MFCDlg::OnBnClickedBtnDet() { // TODO: 在此添加控件通知处理程序代码 if (m_pDetVerify == nullptr) { MessageBox(_T("检测句柄为空,请先初始化创建句柄")); return; } if (m_sPic3Path.IsEmpty()) { MessageBox(_T("请先导入人脸图片")); return; } cv::Mat matImage = cv::imread((std::string)(_bstr_t)(LPCWSTR)m_sPic3Path); if (matImage.empty()) { MessageBox(_T("Pic Not Found")); return; } m_edtFaceBuf.SetWindowText(_T("")); // 给图像结构体赋值 cw_img_t srcImg; srcImg.frameId = 0; srcImg.data = (char*)matImage.data; srcImg.width = matImage.cols; srcImg.height = matImage.rows; srcImg.angle = CW_IMAGE_ANGLE_0; if (matImage.channels()==1) { srcImg.format = CW_IMAGE_GRAY8; } else if (matImage.channels()==3) { srcImg.format = CW_IMAGE_BGR888; } else if (matImage.channels()==4) { srcImg.format = CW_IMAGE_BGRA8888; } else { MessageBox(_T("Pic Error")); return; } // 此处最多检测20张人脸 cw_face_res_t faceBuffers[20]; int iFaceNum = 0; DWORD tmBegin = GetTickCount(); // 人脸检测,关键点,质量分 cw_errcode_t errCode = cwFaceDetection(m_pDetVerify, &srcImg, faceBuffers, 20, &iFaceNum, CW_OP_DET | CW_OP_QUALITY); if (errCode != CW_SDKLIT_OK) { CString sTip; sTip.Format(_T("Face detect Error, Code: %d"), errCode); MessageBox(sTip); return; } if (iFaceNum < 1) { MessageBox(_T("未检测到人脸")); return; } CString sFaceRet; sFaceRet.Format(_T("Face Num: %d; Time: %d ms"), iFaceNum, GetTickCount() - tmBegin); // 人脸画框 for (int i = 0; i < iFaceNum; i++) { cv::Point dst1(faceBuffers[i].faceRect.x, faceBuffers[i].faceRect.y); cv::Point dst2(faceBuffers[i].faceRect.x + faceBuffers[i].faceRect.width, faceBuffers[i].faceRect.y + faceBuffers[i].faceRect.height); //画框 cv::rectangle(matImage, dst1, dst2, colorGreen, 3); CString sCurFace; sCurFace.Format(_T("\r\n\r\nFace%d: Rect: %d, %d, %d, %d; Quality: %f"), i + 1, faceBuffers[i].faceRect.x, faceBuffers[i].faceRect.y, faceBuffers[i].faceRect.width, faceBuffers[i].faceRect.height,faceBuffers[i].quality.scores[0]); sFaceRet += sCurFace; } m_edtFaceBuf.SetWindowText(sFaceRet); cv::imwrite("tempDet.jpg", matImage); ShowImg(_T("tempDet.jpg"), m_hDCPic3, m_rectPic3); } // [3/3/2017 Lit]:通过图片路径获取图片特征 int CDemo_MFCDlg::GetFeatureFromPath(const CString &sPath, void* pFeatueData) { cv::Mat matImage = cv::imread((std::string)(_bstr_t)(LPCWSTR)sPath); if (matImage.empty()) { MessageBox(_T("Pic Not Found")); return -1; } // 给图像结构体赋值 cw_img_t srcImg; srcImg.frameId = 0; srcImg.data = (char*)matImage.data; srcImg.width = matImage.cols; srcImg.height = matImage.rows; srcImg.angle = CW_IMAGE_ANGLE_0; if (matImage.channels()==1) { srcImg.format = CW_IMAGE_GRAY8; } else if (matImage.channels()==3) { srcImg.format = CW_IMAGE_BGR888; } else if (matImage.channels()==4) { srcImg.format = CW_IMAGE_BGRA8888; } else { MessageBox(_T("Pic Error")); return -1; } cw_face_res_t faceBuffers[MAX_NUM_FACES]; int iFaceNum = 0; // 人脸检测,获取对齐人脸 cw_errcode_t errCode = cwFaceDetection(m_pDetVerify, &srcImg, faceBuffers, MAX_NUM_FACES, &iFaceNum, CW_OP_DET | CW_OP_ALIGN); if (errCode != CW_SDKLIT_OK) { CString sErrTip; sErrTip.Format(_T("Face detect Error, Code: %d"), errCode); MessageBox(sErrTip); return -1; } if (iFaceNum < 1) { MessageBox(_T("未检测到人脸")); return -1; } errCode = cwGetFaceFeature(m_pRecogHandle, &faceBuffers[0].faceAligned, pFeatueData); if (CW_SDKLIT_OK != errCode) { CString sErrTip; sErrTip.Format(_T("Get Feature Error, Code: %d"), errCode); MessageBox(sErrTip); return -1; } return 0; } bool CDemo_MFCDlg::CreateFaceHandle() { // 32位和64位检测模型不能共用,64位用_configs_frontend.xml,非64位用_configs_frontend_x86_arm.xml #ifdef DEMO_X64 std::string sModelXmlPath = "../../CWModels/_configs_frontend.xml"; #else std::string sModelXmlPath = "../../CWModels/_configs_frontend_x86_arm.xml"; #endif // DEMO_X64 CString sErrorTip; cw_errcode_t errCode = CW_SDKLIT_OK; if (m_pDetHandle != nullptr) { MessageBox(_T("检测句柄1已创建过,不再创建")); } else { m_pDetHandle = cwCreateDetHandle(&errCode, sModelXmlPath.c_str(), CW_LICENCE); if (CW_SDKLIT_OK != errCode || nullptr == m_pDetHandle) { sErrorTip.Format(_T("创建检测句柄1错误,错误码:%d"), errCode); MessageBox(sErrorTip); return false; } cw_det_param_t param; cwGetFaceParam(m_pDetHandle, ¶m); param.minSize = 48; param.maxSize = 600; //摄像头大小 param.pConfigFile = sModelXmlPath.c_str(); // 设置接口功能参数 cwSetFaceParam(m_pDetHandle, ¶m); } if (m_pDetVerify != nullptr) { MessageBox(_T("检测句柄2已创建过,不再创建")); } else { m_pDetVerify = cwCreateDetHandle(&errCode, sModelXmlPath.c_str(), CW_LICENCE); if (CW_SDKLIT_OK != errCode || nullptr == m_pDetVerify) { sErrorTip.Format(_T("创建检测句柄2错误,错误码:%d"), errCode); MessageBox(sErrorTip); return false; } cw_det_param_t param; cwGetFaceParam(m_pDetVerify, ¶m); param.minSize = 30; param.maxSize = 1000; //设置人脸大小 param.pConfigFile = sModelXmlPath.c_str(); // 设置接口功能参数 cwSetFaceParam(m_pDetVerify, ¶m); } if (m_pRecogHandle != nullptr) { MessageBox(_T("识别句柄已创建过,不再创建")); } else { m_pRecogHandle = cwCreateRecogHandle(&errCode, "../../CWModels/CWR_Config_1_1.xml", CW_LICENCE, CW_FEATURE_EXTRACT); if (CW_SDKLIT_OK != errCode || nullptr == m_pRecogHandle) { sErrorTip.Format(_T("创建识别句柄错误,错误码:%d"), errCode); MessageBox(sErrorTip); return false; } } return true; } void CDemo_MFCDlg::ReleaseFaceHandle() { m_bStartThread = false; { std::lock_guard lock(m_mutex); m_capture.release(); } /* if (m_threadFaceDet.joinable()) { m_threadFaceDet.join(); m_capture.release(); }*/ // 程序退出时销毁句柄 if (m_pDetHandle != nullptr) { cwReleaseDetHandle(m_pDetHandle); m_pDetHandle = nullptr; } if (m_pDetVerify != nullptr) { cwReleaseDetHandle(m_pDetVerify); m_pDetVerify = nullptr; } if (m_pRecogHandle != nullptr) { cwReleaseRecogHandle(m_pRecogHandle); m_pRecogHandle = nullptr; } DeleteDC(m_hDCVideo); DeleteDC(m_hDCPic1); DeleteDC(m_hDCPic2); DeleteDC(m_hDCPic3); } void CDemo_MFCDlg::PostNcDestroy() { // TODO: 在此添加专用代码和/或调用基类 // [3/3/2017 Lit]:程序退出时销毁句柄 ReleaseFaceHandle(); CDialogEx::PostNcDestroy(); } /************************************************************************/ /* 显示视频 */ /************************************************************************/ void CDemo_MFCDlg::ShowVideo(char* szFrame, int iImgWidth, int iImgHeight) { BITMAPINFO BmpInfo; BmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); BmpInfo.bmiHeader.biWidth = (LONG)iImgWidth; BmpInfo.bmiHeader.biHeight = (LONG)iImgHeight; BmpInfo.bmiHeader.biPlanes = 1; BmpInfo.bmiHeader.biBitCount = 24; BmpInfo.bmiHeader.biCompression = BI_RGB; BmpInfo.bmiHeader.biSizeImage = 0; BmpInfo.bmiHeader.biXPelsPerMeter = 0; BmpInfo.bmiHeader.biYPelsPerMeter = 0; BmpInfo.bmiHeader.biClrUsed = 0; BmpInfo.bmiHeader.biClrImportant = 0; SetStretchBltMode(m_hDCVideo, COLORONCOLOR); StretchDIBits(m_hDCVideo, 0, (m_rectVideo.bottom - m_rectVideo.top), (m_rectVideo.right - m_rectVideo.left), (m_rectVideo.top - m_rectVideo.bottom), 0, 0, iImgWidth, iImgHeight, szFrame, &BmpInfo, DIB_RGB_COLORS, SRCCOPY); } void CDemo_MFCDlg::ShowImg(CString sPicPath, HDC hDCVideo, RECT rectVideo) { cv::Mat matImage = cv::imread((std::string)(_bstr_t)(LPCWSTR)sPicPath); if (matImage.empty()) { return; } if (matImage.channels() == 4) { cv::Mat matTemp; cv::cvtColor(matImage, matTemp, CV_BGRA2BGR); matImage = matTemp.clone(); } // 要显示宽度必须是4的倍数 int iWidth = matImage.cols; int iHeight = matImage.rows; if (0 != iWidth % 4) { iWidth = iWidth / 4 * 4; int iWidthCut = matImage.cols - iWidth; int iLeft = iWidthCut / 2; int iRight = iWidth + iLeft; matImage = matImage.colRange(iLeft, iRight).clone(); } BITMAPINFO BmpInfo; BmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); BmpInfo.bmiHeader.biWidth = (LONG)iWidth; BmpInfo.bmiHeader.biHeight = (LONG)iHeight; BmpInfo.bmiHeader.biPlanes = 1; BmpInfo.bmiHeader.biBitCount = 24; BmpInfo.bmiHeader.biCompression = BI_RGB; BmpInfo.bmiHeader.biSizeImage = 0; BmpInfo.bmiHeader.biXPelsPerMeter = 0; BmpInfo.bmiHeader.biYPelsPerMeter = 0; BmpInfo.bmiHeader.biClrUsed = 0; BmpInfo.bmiHeader.biClrImportant = 0; SetStretchBltMode(hDCVideo, COLORONCOLOR); StretchDIBits(hDCVideo, 0, (rectVideo.bottom - rectVideo.top), (rectVideo.right - rectVideo.left), (rectVideo.top - rectVideo.bottom), 0, 0, iWidth, iHeight, matImage.data, &BmpInfo, DIB_RGB_COLORS, SRCCOPY); }