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
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, ¶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<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);
|
|
}
|
|
|
|
|