开发环境:
VS2012+MFC+Opencv2.4.9
实验目的:
利用VC++实现人脸美化软件,要求:
1、具有人脸美化界面;
2、具有磨皮功能,参数可调;
3、具有美白功能,参数可调;
实验原理:
磨皮:滤波(均值滤波、高斯滤波、双边滤波)
融合:使用高反差保留进行图像融合
美白:使用图像增强—非掩蔽锐化
界面展示:
界面功能说明
控件类型:
MFCbutton:用于实现美颜软件的对应功能,该类型控件相比普通Button,可添加自定义背景图片。
Slider Ctrl:滑动条控件,用于控制美颜功能的参数效果。
Picture Ctrl:用于显示图像处理结果,本实验中添加了部分代码以实现自适应控件大小的效果。
程序流程图:
界面设计效果:
这里介绍一下如何给MFC Button添加背景图片
1.在资源管理器下的资源文件文件夹下找到“xxxx.rc”文件,双击打开。
2.右键Bitmap文件夹,选择“添加资源”,再选择“导入”,添加自定义的图片文件。
3.添加完成后,返回设计界面,在MFC Button控件属性下,指定上一步导入图片的标识符。
部分关键代码:
调用OpenCv库文件(这里我放在了"stdafx.h"文件下,也可以直接在xxxDlg.cpp文件下声明):
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include<opencv2\opencv.hpp>
声明命名空间(如果不声明,在代码中使用OpenCv库函数时,需在前面添加"cv::")
using namespace cv;
using namespace std;
美白算法函数(由于时间关系,所以使用的这个算法效果比较一般,后续会尝试重写一下)
void light(Mat& srcImg,int alpha, int beta)
{
for (int y = 0; y < srcImg.rows; y++)
{
for (int x = 0; x < srcImg.cols; x++)
{
for (int c = 0; c < 3; c++)
{
srcImg.at<Vec3b>(y, x)[c] = saturate_cast<uchar>(alpha*(srcImg.at<Vec3b>(y, x)[c]) + beta-50);
}
}
}
}
在xxxDlg.cpp文件自动生成的OnInitDialog()函数下,添加以下代码以实现图片自适应控件大小的效果
其中IDC_ShowImg指向Picture Ctrl控件名称。
namedWindow("view",WINDOW_AUTOSIZE);
HWND hWnd = (HWND) cvGetWindowHandle("view");
HWND hParent = ::GetParent(hWnd);
::SetParent(hWnd, GetDlgItem(IDC_ShowImg1)->m_hWnd);
::ShowWindow(hParent, SW_HIDE);
同样在OnInitDialog()函数下添加以下代码,实现设定滑动条控件范围和初始位置的效果。
m_slider.SetRange(0,100);
m_slider.SetPos(50);
在OnInitDialog()函数下添加以下代码,实现修改控件颜色和字体的效果
m_font.CreatePointFont(120,"黑体");
m_brush.CreateSolidBrush(RGB(0,255,0));
number.SetFont(&m_font);
m_btn1.SetFaceColor(RGB(0,0,0));
m_btn2.SetFaceColor(RGB(0,0,0));
m_btn3.SetFaceColor(RGB(0,0,0));
m_btn4.SetFaceColor(RGB(0,0,0));
m_btn5.SetFaceColor(RGB(0,0,0));
m_btn6.SetFaceColor(RGB(0,0,0));
磨皮算法关键代码
void C人脸美颜软件Dlg::OnBnClickedButton3()
{
/***********************声明变量**********************/
Mat imagedst1;
Mat imagedst2;
/***********************磨皮处理**********************/
int scale1 = m_slider.GetPos();
input_image.copyTo(src);
blur(src,imagedst1, Size(3, 3)); //均值滤波
GaussianBlur(imagedst1, imagedst2, Size(3, 3), 0); //高斯滤波
bilateralFilter(imagedst2, dst1, (int)scale1*0.3, scale1, scale1); //双边滤波
/***********************显示结果**********************/
CRect rect;
GetDlgItem(IDC_ShowImg1)->GetClientRect(&rect);
Rect dst(rect.left,rect.top,rect.right,rect.bottom);
resize(dst1,output_image,cv::Size(rect.Width(),rect.Height()));
index = 1;
imshow("view", output_image);
}
融合算法关键代码
void C人脸美颜软件Dlg::OnBnClickedButton4()
{
/***********************磨皮处理**********************/
int scale1 = m_slider.GetPos();
input_image.copyTo(dstI);
dst1.copyTo(dstF);
bilateralFilter(dstI, dstF, 10, 80, 80); //双边滤波
dstH=dstF-dstI+128;
GaussianBlur(dstH, dstY, Size(5,5),0,0,0); //高斯滤波得到Y
float OP=(float)(scale1*0.01);
dstZ=dstI+(2*dstY-256)*OP;
/***********************显示结果**********************/
CRect rect;
GetDlgItem(IDC_ShowImg1)->GetClientRect(&rect);
Rect dst(rect.left,rect.top,rect.right,rect.bottom);
resize(dstZ,output_image,cv::Size(rect.Width(),rect.Height()));
imshow("view", output_image);
index = 2;
}
美白算法关键代码
void C人脸美颜软件Dlg::OnBnClickedButton5()
{
/***********************美白处理**********************/
int scale1 = m_slider.GetPos();
dstZ.copyTo(matResult);
light(matResult, 1, scale1); // 调整对比度与亮度,参数3为对比度,参数4为亮度
// 图像增强,使用非锐化掩蔽(Unsharpening Mask)方案。
GaussianBlur(matResult, matFinal, cv::Size(0, 0), 9);
addWeighted(matResult, 1.5, matFinal, -0.5, 0, matFinal);
/***********************显示结果**********************/
CRect rect;
GetDlgItem(IDC_ShowImg1)->GetClientRect(&rect);
Rect dst(rect.left,rect.top,rect.right,rect.bottom);
resize(matFinal,output_image,cv::Size(rect.Width(),rect.Height()));
imshow("view", output_image);
index =3;
// TODO: 在此添加控件通知处理程序代码
}
读取图片关键代码
void C人脸美颜软件Dlg::OnBnClickedMfcbutton8()
{
// TODO: 在此添加控件通知处理程序代码
CFileDialog dlg(TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT|OFN_ALLOWMULTISELECT,
NULL, this);
if(dlg.DoModal() == IDOK)
{
picPath= dlg.GetPathName();
}
picpath=picPath.GetBuffer(0);
input_image = imread(picpath);
Mat imagedst;
CRect rect;
GetDlgItem(IDC_ShowImg1)->GetClientRect(&rect);
Rect dst(rect.left,rect.top,rect.right,rect.bottom);
resize(input_image,imagedst,cv::Size(rect.Width(),rect.Height()));
imshow("view",imagedst);
}
保存图片关键代码
void C人脸美颜软件Dlg::OnBnClickedMfcbutton4()
{
// TODO: 在此添加控件通知处理程序代码
TCHAR szFilter[] = _T("JPG图片(*.jpg)|*.jpg|BMP图片(*.bmp)|*.bmp|PNG图片(*.png)|*.png|JPEG图片(*.jpeg)|*.jpeg|DIB图片(*dib)|*.dib|PBM图片(*.pbm)|*.pbm||");
CFileDialog fileDlg(FALSE, _T("jpg"), _T("New"), OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, szFilter, this);
CString strFilePath;
if (IDOK == fileDlg.DoModal())
{
strFilePath = fileDlg.GetPathName();
}
vector<int> compression_params;
string STDStr(CT2A(strFilePath.GetString()));
imwrite(STDStr, output_image, compression_params);
}
滑动条处理事件关键代码(将滑动条位置的具体参数显示在界面中)
void C人脸美颜软件Dlg::OnNMCustomdrawSlider1(NMHDR *pNMHDR, LRESULT *pResult) //滑动条处理事件
{
LPNMCUSTOMDRAW pNMCD = reinterpret_cast<LPNMCUSTOMDRAW>(pNMHDR);
//@TN
CString str;
str.Format("%d",m_slider.GetPos());
GetDlgItem(IDC_ShowNum)->SetWindowTextA(str);
//*pResult = 0;
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
}
界面优化部分代码(在MFC自动生成的OnCtlColor函数下编写,主要功能是修改部分控件的字体颜色和背景色,如静态文本和滑动条)
HBRUSH C人脸美颜软件Dlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);
if(pWnd->GetDlgCtrlID() == IDC_ShowNum)
{
pDC->SetTextColor(RGB(255,255,255));
pDC->SetBkColor(RGB(0,0,0));
}
if(pWnd->GetDlgCtrlID() == IDC_mopi)
{
pDC->SetTextColor(RGB(255,255,255));
pDC->SetBkColor(RGB(0,0,0));
}
if(pWnd->GetDlgCtrlID() == IDC_rh)
{
pDC->SetTextColor(RGB(255,255,255));
pDC->SetBkColor(RGB(0,0,0));
}
if(pWnd->GetDlgCtrlID() == IDC_mb)
{
pDC->SetTextColor(RGB(255,255,255));
pDC->SetBkColor(RGB(0,0,0));
}
CRect ctrlRect;
pWnd->GetClientRect(&ctrlRect);
switch (pWnd->GetDlgCtrlID())
{
case IDC_SLIDER1:
CBrush mybrush(RGB(0,0,0));
pDC->FillRect(ctrlRect,&mybrush);
mybrush.DeleteObject();
pDC->SetBkMode(TRANSPARENT);
hbr=(HBRUSH)GetStockObject(NULL_BRUSH);
break;
}
return hbr;
// TODO: 在此更改 DC 的任何特性
// TODO: 如果默认的不是所需画笔,则返回另一个画笔
}
部分全局变量声明(因为不是重点,所以放在最后)
String picpath;
CString picPath; //定义图片路径变量
int index=0;
CBrush m_brush;
CFont m_font;
Mat input_image;
Mat output_image;
Mat mopi_image;
Mat src;
Mat imagedst1;
Mat imagedst2;
Mat dst1,dst2,dst1src;
Mat dst3(mopi_image.size(),CV_8UC3); //融合后的RGB三通道
Mat dstI,dstF,dstH,dstY,dstZ;
Mat matResult;
Mat matFinal;
心得体会:
这次大作业大概花了两周时间完成,在此之前并没有接触过MFC编程,所以很多代码都是参考上一届学长的博客,博客地址如下所示,在他的基础上改进了融合算法的效果,并对界面进行了优化。起初是想做一个类似美颜相机的效果,能够通过摄像头采集图像,但是对于OpenCv这方面知识的了解太少,所以只能作罢。
【图像处理】基于VC++的人脸美化的实现实践篇(含代码)
个人感觉本次大作业的难点在于OpenCV环境的配置,还有美白算法的编写。因为那段时间我在公司实习,用的是VS2019,在配置环境的时候遇到不少麻烦,所以最后改用旧电脑完成,具体配置方式可以参考我之前的博客。
OpenCV环境配置
至于美白算法,其实起初老师的PPT给出了一套实现方案,具体流程如下图所示,但是自己写到最后发现难度有点大,所以临时找了网上一套现成的方案,如果有空的话再去完善一下。
总体来说,用MFC开发图像处理的相关软件有点low,建议用C#的WinForm实现。
代码工程下载地址:
链接:
https://pan.baidu.com/s/1Q7bVtF5G5cAXuj1_7YhJHQ
提取码:4cp4