You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

772 lines
18 KiB

// 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<WPARAM>(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<HCURSOR>(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<std::mutex> 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<std::mutex> 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<std::mutex> 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, &param);
param.minSize = 48;
param.maxSize = 600; //摄像头大小
param.pConfigFile = sModelXmlPath.c_str(); // 设置接口功能参数
cwSetFaceParam(m_pDetHandle, &param);
}
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, &param);
param.minSize = 30;
param.maxSize = 1000; //设置人脸大小
param.pConfigFile = sModelXmlPath.c_str(); // 设置接口功能参数
cwSetFaceParam(m_pDetVerify, &param);
}
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<std::mutex> 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);
}