dlib人臉對齊程序設計(C++)

VS2017工程代碼鏈接如下:

https://download.csdn.net/download/wzhrsh/12082163

 


// face_mfcDlg.cpp: 實現文件
//

#include "stdafx.h"
#include "face_mfc.h"
#include "face_mfcDlg.h"
#include "afxdialogex.h"
#include <cmath>

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// 用於應用程序“關於”菜單項的 CAboutDlg 對話框

class CAboutDlg : public CDialogEx
{
public:
	CAboutDlg();

// 對話框數據
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_ABOUTBOX };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV 支持

// 實現
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()


// CfacemfcDlg 對話框



CfacemfcDlg::CfacemfcDlg(CWnd* pParent /*=nullptr*/)
	: CDialogEx(IDD_FACE_MFC_DIALOG, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CfacemfcDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CfacemfcDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_open, &CfacemfcDlg::OnBnClickedopen)
	ON_BN_CLICKED(IDC_colse, &CfacemfcDlg::OnBnClickedcolse)
	ON_BN_CLICKED(IDC_BTN_GETIMAGE, &CfacemfcDlg::OnBnClickedBtnGetimage)
	ON_BN_CLICKED(IDC_BTN_DETECT, &CfacemfcDlg::OnBnClickedBtnDetect)
	ON_BN_CLICKED(IDC_BTN_FACEALG, &CfacemfcDlg::OnBnClickedBtnFacealg)
	ON_BN_CLICKED(IDC_BTN_FACEALIGN, &CfacemfcDlg::OnBnClickedBtnFacealign)
END_MESSAGE_MAP()


// CfacemfcDlg 消息處理程序

BOOL CfacemfcDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	// 將“關於...”菜單項添加到系統菜單中。

	// 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: 在此添加額外的初始化代碼
	cv::namedWindow("view", cv::WINDOW_AUTOSIZE);
	//HWND,h 是類型描述,表示句柄(handle), Wnd 是變量對象描述,表示窗口,所以hWnd 表示窗口句柄。hWnd 屬性,返回窗體或控件的句柄
	HWND hWnd = (HWND)cvGetWindowHandle("view");
	HWND hParent = ::GetParent(hWnd);//獲得一個指定子窗口的父窗口句柄
	::SetParent(hWnd, GetDlgItem(IDC_PIC)->m_hWnd);//GetDlgItem返回窗口中指定參數ID的子元素的句柄,可以通過返回的句柄對窗口內的子元素進行操作
	//m_hWnd 指明與這個cwnd對象相關聯的hwnd句柄
	//HWND SetParent(//測試的窗口句柄
//               HWND hWndChild,      // handle to window
//               //新父窗口句柄
//               HWND hWndNewParent   // new parent window
//               );
	::ShowWindow(hParent, SW_HIDE);//SW_HIDE	隱藏窗口並激活其他窗口

	return TRUE;  // 除非將焦點設置到控件,否則返回 TRUE
}

void CfacemfcDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialogEx::OnSysCommand(nID, lParam);
	}
}

// 如果向對話框添加最小化按鈕,則需要下面的代碼
//  來繪製該圖標。  對於使用文檔/視圖模型的 MFC 應用程序,
//  這將由框架自動完成。

void CfacemfcDlg::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 CfacemfcDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}



void CfacemfcDlg::OnBnClickedopen()
{
	// TODO: 在此添加控件通知處理程序代碼
	m_flag = 1;
	CRect rect;
	//GetDlgItem,是根據繼承關係的函數功能,返回窗口中指定參數ID的子元素的句柄,可以通過返回的句柄對窗口內的子元素進行操作
	CWnd *pWnd = GetDlgItem(IDC_PIC);
	pWnd->GetClientRect(&rect);//該函數獲取窗口客戶區的大小。注意一下:窗口的客戶區爲窗口中除標題欄、菜單欄之外的地方。
	int x = rect.Width();
	int y = rect.Height();
	m_capture.release();//釋放鼠標的捕獲狀態
	m_capture = VideoCapture(0);
	if (!m_capture.isOpened())
	{
		fprintf(stderr, "Can not open camera.\n");//stderr --標準錯誤,是不帶緩衝的
		return;
	}
	frontal_face_detector detector = get_frontal_face_detector();//正向人臉檢測器,進行人臉檢測
	shape_predictor pose_model;
	// shape_predictor("shape_predictor_68_face_landmarks.dat") /人臉 68 點特徵檢測器,進行人臉面部輪廓特徵提取: 
	deserialize("E:\\tb\\project\\tb2\\source\\model\\shape_predictor_68_face_landmarks.dat") >> pose_model;
	while (m_flag)
	{
		cv::Mat frame;
		m_capture >> frame;
		//fx、fy是沿x軸和y軸的縮放係數,Size dsize 輸出圖像的大小// m_dst輸出圖像
		//cv::resize(frame, m_dst, cv::Size(x, y), 0, 0, 1);  //CV_INTER_LINEAR
		cv_image<bgr_pixel>cimg(frame);//Mat to something dlib can deal with
		if (m_bdetect)//人臉檢測
		{
			std::vector<dlib::rectangle> faces = detector(cimg);//detector()函數檢測人臉,返回一系列邊界盒子
			std::vector<full_object_detection>shapes;
			for (unsigned long i = 0; i < faces.size(); ++i)
			{//人臉檢測,並繪製矩形框
				if (m_brectangle)
				{
					cv::rectangle(frame, Rect(faces[i].left(), faces[i].top(), faces[i].width(), faces[i].height()), Scalar(0, 0, 255), 1, 1, 0);
				}
				shapes.push_back(pose_model(cimg, faces[i]));
			}
			if (!shapes.empty())
			{
				for (int i = 0; i < 68; i++)
				{
					//cv::rectangle(frame, Rect(100, 300, 20, 200), Scalar(255, 0, 0), 1, 1, 0);
					if (!m_brectangle)
					{//顯示特徵點
						cv::circle(frame, cvPoint(shapes[0].part(i).x(), shapes[0].part(i).y()), 3, cv::Scalar(0, 0, 255), -1);
						//	shapes[0].part(i).x();//68個
						// zhanzl:顯示特徵點的數字
						//putText(frame, to_string(i), cvPoint(shapes[0].part(i).x(), shapes[0].part(i).y()), CV_FONT_HERSHEY_PLAIN, 1, cv::Scalar(255, 0, 0), 1, 4);
					}
				}
			}
		}
		cv::imshow("view", frame);//m_dst
		cv::waitKey(3);
	}
}

void CfacemfcDlg::OnBnClickedcolse()
{
	// TODO: 在此添加控件通知處理程序代碼
	m_flag = 0;
	CDialogEx::OnClose();
}


void CfacemfcDlg::OnBnClickedBtnGetimage()
{
	// TODO: 在此添加控件通知處理程序代碼
	string picpath = "D:\\002.jpg";
	imwrite(picpath, m_dst);
	Mat image = imread(picpath);
	//Mat  imagedst;
	CWnd *pWnd = GetDlgItem(IDC_IMAGE);
	CDC *pDC = NULL;
	//CString strPath;
	((CStatic*)GetDlgItem(IDC_IMAGE))->ModifyStyle(0xF, SS_BITMAP | SS_CENTERIMAGE);//SS_BITMAP這裏把靜態控件弄爲灰白色了,不要它又直接輸出caption
	//GetDC 函數:獲取設備指針,函數功能描述:該函數檢索一指定窗口的客戶區域或整個屏幕的顯示設備上下文的句柄.
	//GetDlgItem(ID) 通過資源ID獲取對話框內控件的指針,//CDC*pDC=GetDlgItem(ID)->GetDC(); 獲取某控件的設備繪圖指針
	pDC = GetDlgItem(IDC_IMAGE)->GetDC();
	ShowImage(pDC, picpath, 0, 0);
	// 方法說明:    顯示JPG和GIF、BMP圖片
	// 參數說明:    CDC * pDC           設備環境對象
	// 參數說明:    CString strPath     要顯示的圖片路徑
	// 參數說明:    int x               要顯示的X位置
	// 參數說明:    int y               要顯示的Y位置
	// 返回值:      BOOL                成功返回TRUE,否則返回FALSE
	ReleaseDC(pDC);//釋放資源
}

//顯示圖片
BOOL CfacemfcDlg::ShowImage(CDC* pDC, string strPath, int x, int y)
{
	IPicture *pPic = NULL;
	OleLoadPicturePath(CComBSTR(strPath.c_str()), (LPUNKNOWN)NULL, 0, 0, IID_IPicture, (LPVOID*)&pPic);
	if (NULL == pPic)
	{
		return FALSE;
	}
	// 寬度+高度
	OLE_XSIZE_HIMETRIC hmWidth;
	OLE_YSIZE_HIMETRIC hmHeight;
	pPic->get_Width(&hmWidth);
	pPic->get_Height(&hmHeight);
	//寬度和高度  
	RECT rtWnd;
	pDC->GetWindow()->GetWindowRect(&rtWnd);
	int iWndWidth = rtWnd.right - rtWnd.left;
	int iWndHeight = rtWnd.bottom - rtWnd.top;
	//pPic->Render(*pDC, x, y, iWndWidth, iWndHeight, 0, hmHeight, hmWidth, -hmHeight, NULL);
	if (FAILED(pPic->Render(*pDC, x, y, iWndWidth, iWndHeight, 0, hmHeight, hmWidth, -hmHeight, NULL)))
	{
		pPic->Release();
		return false;
	}
	//釋放資源
	pPic->Release();
	return true;
}

BOOL CfacemfcDlg::ShowImageRight(string strPath, int x, int y)
{
	//
	//strPath = "d:\\001.jpg";
	CWnd *pWnd = GetDlgItem(IDC_IMAGE);
	//showMatImgToWnd(pWnd,image);
	CDC *pDC = NULL;
	//設置靜態控件的樣式,使其可以使用位圖,並使位圖顯示居中  
	((CStatic*)GetDlgItem(IDC_IMAGE))->ModifyStyle(0xF, SS_BITMAP | SS_CENTERIMAGE);

	pDC = GetDlgItem(IDC_IMAGE)->GetDC();
	ShowImage(pDC, strPath, 0, 0);


	//
	IPicture *pPic = NULL;
	OleLoadPicturePath(CComBSTR(strPath.c_str()), (LPUNKNOWN)NULL, 0, 0, IID_IPicture, (LPVOID*)&pPic);
	if (NULL == pPic)
	{
		return FALSE;
	}
	// 寬度+高度
	OLE_XSIZE_HIMETRIC hmWidth;
	OLE_YSIZE_HIMETRIC hmHeight;
	pPic->get_Width(&hmWidth);
	pPic->get_Height(&hmHeight);
	//寬度和高度  
	RECT rtWnd;
	pDC->GetWindow()->GetWindowRect(&rtWnd);
	int iWndWidth = rtWnd.right - rtWnd.left;
	int iWndHeight = rtWnd.bottom - rtWnd.top;

	if (FAILED(pPic->Render(*pDC, x, y, iWndWidth, iWndHeight, 0, hmHeight, hmWidth, -hmHeight, NULL)))
	{
		pPic->Release();
		return false;
	}
	//釋放資源
	pPic->Release();

	ReleaseDC(pDC); //釋放資源
	return true;

}

//顯示圖片-左側
BOOL CfacemfcDlg::ShowImageLeft(string strPath, int x, int y)
{

	strPath = "D:\\002.jpg";
	CWnd *pWnd = GetDlgItem(IDC_PIC);
	//showMatImgToWnd(pWnd,image);
	CDC *pDC = NULL;
	//設置靜態控件的樣式,使其可以使用位圖,並使位圖顯示居中  
	((CStatic*)GetDlgItem(IDC_PIC))->ModifyStyle(0xF, SS_BITMAP | SS_CENTERIMAGE);

	pDC = GetDlgItem(IDC_PIC)->GetDC();
	ShowImage(pDC, strPath, 0, 0);


	//
	IPicture *pPic = NULL;
	OleLoadPicturePath(CComBSTR(strPath.c_str()), (LPUNKNOWN)NULL, 0, 0, IID_IPicture, (LPVOID*)&pPic);
	if (NULL == pPic)
	{
		return FALSE;
	}
	// 寬度+高度
	OLE_XSIZE_HIMETRIC hmWidth;
	OLE_YSIZE_HIMETRIC hmHeight;
	pPic->get_Width(&hmWidth);
	pPic->get_Height(&hmHeight);
	//寬度和高度  
	RECT rtWnd;
	pDC->GetWindow()->GetWindowRect(&rtWnd);
	int iWndWidth = rtWnd.right - rtWnd.left;
	int iWndHeight = rtWnd.bottom - rtWnd.top;

	if (FAILED(pPic->Render(*pDC, x, y, iWndWidth, iWndHeight, 0, hmHeight, hmWidth, -hmHeight, NULL)))
	{
		pPic->Release();
		return false;
	}
	//釋放資源
	pPic->Release();

	ReleaseDC(pDC); //釋放資源
	return true;


}

//人臉檢測:畫出矩形框,針對照片
void CfacemfcDlg::OnBnClickedBtnDetect()
{
	// TODO: 在此添加控件通知處理程序代碼
	m_bdetect = 1;//人臉檢測
	if (m_brectangle)//繪製矩形框
	{
		m_brectangle = 0;
	}
	else
	{
		m_brectangle = 1;//人臉檢測,並繪製矩形框
	}

}


void CfacemfcDlg::OnBnClickedBtnFacealg()
{
	// TODO: 在此添加控件通知處理程序代碼
	if (m_bdetect)
	{
		m_bdetect = 0;
	}
	else
	{
		m_bdetect = 1;//人臉檢測
	}
}


void CfacemfcDlg::OnBnClickedBtnFacealign()
{
	// TODO: 在此添加控件通知處理程序代碼
	//圖片文件路徑
	string filePath = "d:\\002.jpg";
	//01-導入一張圖片
	ShowImageLeft(filePath, 0, 0);
	//array2d<rgb_pixel> img;   //特別注意:轉換後會失真
	//bgr_pixel
	array2d<bgr_pixel> img;
	load_image(img, filePath);
	pyramid_up(img);// Make the image larger so we can detect small faces.

	//02:初始化環境
	frontal_face_detector detector = get_frontal_face_detector();
	shape_predictor pose_model;
	deserialize("E:\\tb\\project\\tb2\\source\\model\\shape_predictor_68_face_landmarks.dat") >> pose_model;

	//03-人臉檢測
	std::vector<dlib::rectangle> faces = detector(img);

	// Now we will go ask the shape_predictor to tell us the pose of each face we detected
	std::vector<full_object_detection> shapes;
	for (unsigned long i = 0; i < faces.size(); ++i) {
		//人臉檢測,並繪製矩形框 
		// Key1:注意轉換失真問題:bgr_pixel
		cv::Mat img2 = dlib::toMat(img);
		cv::rectangle(img2, Rect(faces[i].left(), faces[i].top(), faces[i].width(), faces[i].height()), Scalar(0, 0, 255), 1, 1, 0);
		shapes.push_back(pose_model(img, faces[i]));//函數將一個新的元素加到vector的最後面,位置爲當前最後一個元素的下一個元素
	}
	//04-特徵點標定:68	
/*	if (!shapes.empty()) {
		for (int i = 0; i < 68; i++) {
			cv::Mat img2 = dlib::toMat(img);
			//cv::rectangle(frame, Rect(100, 300, 20, 200), Scalar(255, 0, 0), 1, 1, 0);
			cv::circle(img2, cvPoint(shapes[0].part(i).x(), shapes[0].part(i).y()), 3, cv::Scalar(0, 0, 255), -1);
			//shapes[0].part(i).x();//68個
			// zhanzl:顯示特徵點的數字
			putText(img2, to_string(i), cvPoint(shapes[0].part(i).x(), shapes[0].part(i).y()), CV_FONT_HERSHEY_PLAIN, 1, cv::Scalar(255, 0, 0), 1, 4);
		}
	}*/

	//05-人臉對齊:face_chips爲對齊後的目標
	dlib::array<array2d<bgr_pixel> > face_chips;
	dlib::extract_image_chips(img, get_face_chip_details(shapes), face_chips);
	for (size_t i = 0; i < face_chips.size(); i++)
	{
		cv::Mat img = dlib::toMat(face_chips[i]);
		string picpath;
		stringstream stream;
		stream << i;
		picpath = stream.str();
		picpath += ".jpg";
		picpath = "d://" + picpath;
		imwrite(picpath, img);
		//顯示在控件上
		ShowImageRight(picpath, 0, 0);
	}
}

 

發佈了158 篇原創文章 · 獲贊 35 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章