之前做的老项目了,摸索了几个小时才搞出来的。
代码资源地址:MFC源代码
按照惯例,先上效果图,下图是我的女神詹姆斯的照片,精致的面部轮廓,真心好看,咳咳,扯远了。。。。
使用流程,点击确定,导入女神;选择;点击ROI1或者ROI2,被选择的区域就会另外显示出来。
实现:
简单的MFC项目建立方法,图片的导入与显示不再赘述,相信点进来看本文的都有一定的基础,那就直接捡干货说。
1)绿色选择框的实现 OnLButtonDown消息 OnMouseMove鼠标移动消息 OnLButtonUp消息
绿色选择框的大小实时调整使用橡皮筋实现。
//written by Z_Benny @2018.2.4
void CpictureROIDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CRect cwrect;
GetDlgItem(IDC_PIC_STATIC)->GetWindowRect(&cwrect); //获取窗体中控件的区域
ScreenToClient(&cwrect); //转换为相对区域的CRect
if(point.x>cwrect.left && point.y>cwrect.top ) //确保按下的坐标在控件区域内 && point.x
{
if (m_RectTracker.HitTest(point) < 0) //如果未击中矩形选择框,重新画选择框
{
m_RectTracker.TrackRubberBand(this, point, TRUE);
m_RectTracker.m_rect.NormalizeRect(); //正规化矩形(关于正规化矩形下面有介绍)
}
else //如果击中矩形选择框
{
m_RectTracker.Track(this, point, TRUE);
m_RectTracker.m_rect.NormalizeRect(); //正规化矩形
//SendMessage(WM_LBUTTONUP,NULL,NULL);
}
//Invalidate(TRUE); //刷新窗口区域,使得CrectTracker对象重绘到窗口上
}
flag = true;
m_ptOld = m_ptOrigin = point;
//
//point点的初始原点是程序客户区左上角
strtPoint = point;
CString strtPx, strtPy;
int x = point.x;
int y = point.y;
strtPx.Format(_T("%d"), x);
strtPy.Format(_T("%d"), y);
m_startPX.SetWindowText(strtPx);
m_startPY.SetWindowText(strtPy);
//CDialogEx::OnLButtonDown(nFlags, point);
}
void CpictureROIDlg::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CString strtPx, strtPy;
int x = point.x;
int y = point.y;
strtPx.Format(_T("%d"), x);
strtPy.Format(_T("%d"), y);
m_startPX.SetWindowText(strtPx);
m_startPY.SetWindowText(strtPy);
if (flag) {
CDC* pdcpic = m_picture.GetDC(); // 获得DC
HDC m_hdc = pdcpic->m_hDC;
CRect rc2;
CWnd* pwnd2 = GetDlgItem(IDC_PIC_STATIC);
pwnd2->GetClientRect(&rc2); // 获得IDC_ICTURE控件的客户区大小
pwnd2->MapWindowPoints(this, &rc2); // 将坐标转换为对话框窗口的坐标
int oldRop = ::SetROP2(m_hdc, R2_NOT);
// 画线
::MoveToEx(m_hdc, strtPoint.x - rc2.left, strtPoint.y - rc2.top, NULL);
::LineTo(m_hdc, point.x - rc2.left, point.y - rc2.top);
::MoveToEx(m_hdc, strtPoint.x - rc2.left, strtPoint.y - rc2.top, NULL);
::LineTo(m_hdc, point.x - rc2.left, point.y - rc2.top);
terminatePoint = point;
CvPoint strt;
CvPoint last;
strt.x = strtPoint.x ;
strt.y = strtPoint.y ;
last.x = terminatePoint.x;
last.y = terminatePoint.y;
rectangle(srcImage, strt, last, cvScalar(0, 255, 0), 1);
showImage(srcImage);
flag = FALSE;
CDialogEx::OnMouseMove(nFlags, point);
}
}
void CpictureROIDlg::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CDialogEx::OnLButtonUp(nFlags, point);
}
2)其中,子函数showImage的实现
void CpictureROIDlg::showImage(Mat img)
{
int width = img.cols;
int height = img.rows;
Mat showImage;
img.copyTo(showImage);
CRect rect;
GetDlgItem(IDC_PIC_STATIC)->GetClientRect(&rect);
resize(showImage, showImage, Size(rect.Width(), rect.Height()));
unsigned int displayWidth = rect.Width();
unsigned int displayHeight = rect.Height();
unsigned int displayRadio = displayWidth / displayHeight;
switch (showImage.channels())
{
case 1:
cvtColor(showImage, showImage, CV_GRAY2BGRA);
break;
case 3:
cvtColor(showImage, showImage, CV_BGR2BGRA);
break;
default:
break;
}
int pixBytes = showImage.channels()*(showImage.depth() + 1);
//制作数据头
BITMAPINFO bitInfo;
bitInfo.bmiHeader.biBitCount = 8 * pixBytes;
bitInfo.bmiHeader.biWidth = showImage.cols;
bitInfo.bmiHeader.biHeight = -showImage.rows;
bitInfo.bmiHeader.biPlanes = 1;
bitInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitInfo.bmiHeader.biCompression = BI_RGB;
bitInfo.bmiHeader.biClrImportant = 0;
bitInfo.bmiHeader.biClrUsed = 0;
bitInfo.bmiHeader.biSizeImage = 0;
bitInfo.bmiHeader.biXPelsPerMeter = 0;
bitInfo.bmiHeader.biYPelsPerMeter = 0;
CDC *pDC = GetDlgItem(IDC_PIC_STATIC)->GetDC();
::StretchDIBits(pDC->GetSafeHdc(), 0, 0,
rect.Width(), rect.Height(), 0, 0, rect.Width(), rect.Height(),
showImage.data, &bitInfo, DIB_RGB_COLORS, SRCCOPY);
ReleaseDC(pDC);
}
Fightting !!!!