opencv3.0+VS2013平台人脸检测MFC
来源:互联网 发布:excel制作数据录入窗体 编辑:程序博客网 时间:2024/06/16 12:42
OpenCV3.0+VS2013平台人脸检测MFC
说明:
本程序构建于VS2013基本对话框,调用了OPENCV3.0库,可以通过打开摄像头、打开图片,打开视频获取数据文件,再进行检测(最后有效果图),三者数据流之间可以任意切换。几点说明:视频和摄像机的显示和检测用到了定时器;在代码的现实中,图片是显示在控件中,用到CvvImage类,而OPENCV3.0库中没有这个类了,需要自己添加相应cpp和h文件到工程目录中。
实现函数位于1420190255Dlg.cpp中,成员变量和位于1420190255Dlg.h文件,少量全局变量在1420190255Dlg.h中。本文中的代码,网上有很多。本文只是为了展示MFC的框架以及代码的移植实现。
一、程序代码
1、1420190255Dlg.h
有注释部分是基本是自己添加部分(下同).
// 1420190255Dlg.h : 头文件#pragma once// CMy1420190255Dlg 对话框class CMy1420190255Dlg : public CDialogEx{// 构造public: CMy1420190255Dlg(CWnd* pParent = NULL); // 标准构造函数// 对话框数据 enum { IDD = IDD_MY1420190255_DIALOG }; protected: virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持public: IplImage* m_pImg, *m_pImg_=0; // 文件读取图像 IplImage* m_pRstImg; // 处理后的图像 BOOL m_bDrawFlag; // 是否有图像 int m_nFileType; // 打开文件类型 float m_fTime; // 检测时间 int m_nNum; // 检测人脸个数 // 摄像头 // 本版本CvCapture 不能启动设备,用VideoCapture替代; Mat m_Frame, m_Frame_; // 从摄像机capture获取的 IplImage m_frame, m_frame_; // 从Mat图像转换而来 VideoCapture cap; // 视频 (同上) VideoCapture capture ; Mat m_vFrame, m_vFrame_; IplImage m_vframe, m_vframe_; void DrawImageToHDC( IplImage *pImg, UINT nID); // 图片显示到控件 void ClearControlImage(UINT nID); // 清空画面(用以加载另外的图片,避免大小不同而不能完全覆盖) void face_detect(IplImage * img); // 检测图片子函数// 实现protected: HICON m_hIcon; // 生成的消息映射函数 virtual BOOL OnInitDialog(); afx_msg void OnSysCommand(UINT nID, LPARAM lParam); afx_msg void OnPaint(); afx_msg HCURSOR OnQueryDragIcon(); DECLARE_MESSAGE_MAP()public:// 消息映射函数 afx_msg void OnBnClickedGetCam(); // 打开摄像头 afx_msg void OnBnClickedVideo(); // 打开视频 afx_msg void OnBnClickedPicture(); // 打开图片afx_msg void OnTimer(UINT_PTR nIDEvent); // 定时器}
2、1420190255Dlg.cpp
这部分,贴出添加的初始化的变量,以及函数实现。代码中有一些解释。 就不进行整体的说明了。
(1) 引用
2个cpp类的引用,我放在了stdafx.h中
// 1420190255Dlg.cpp : 实现文件#include "CvvImage.h" //高版本OpenCV不存在该类,需要自己创建及添加//#include "opencv2/opencv.hpp"//#include "opencv2/highgui.hpp"</span>
stdafx.h中用到了宏定义,以避免重复定义:
// stdafx.h : 标准系统包含文件的包含文件,#ifndef _OPCV_3_0_HEADER_ // 支持 opencv#include "opencv2/opencv.hpp"#include "opencv2/highgui.hpp"using namespace cv;#endif
(2) 全局变量,构造函数初始化
static CvMemStorage * storage = 0;static CvHaarClassifierCascade *cascade = 0;static CvScalar colors[] = { // 8种标记颜色 { 0, 0, 255 }, { 0, 128, 255 }, { 0, 255, 255 }, { 0, 255, 0 }, { 255, 128, 0 }, { 255, 255, 0 }, { 255, 0, 0 }, { 255, 0, 255 } };BOOL bDttFlag = FALSE; // 检测按钮标记BOOL bPlayOver = FALSE; // 视频播放结束标记
下面是构造函数的初始化,消息映射表, 数据交换
CMy1420190255Dlg::CMy1420190255Dlg(CWnd* pParent /*=NULL*/) :CDialogEx(CMy1420190255Dlg::IDD, pParent){ m_pImg = NULL; m_pRstImg = NULL; m_bDrawFlag = NULL; m_fTime = 0; m_nNum = 0; m_nFileType = 0; // 1-摄像,2-视频, 3-图片 // 加载分类器 opencv1.0中文件,924kb const char * cascade_name = "haarcascade_frontalface_alt.xml"; cascade = (CvHaarClassifierCascade*)cvLoad(cascade_name); if (cascade == NULL) MessageBox("Load HaarCascade error!\n"); m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);} //BEGIN_MESSAGE_MAP(CMy1420190255Dlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_BN_CLICKED(IDC_GETCAM, &CMy1420190255Dlg::OnBnClickedGetCam) ON_BN_CLICKED(IDC_PICTURE, &CMy1420190255Dlg::OnBnClickedPicture) ON_BN_CLICKED(IDC_Detect, &CMy1420190255Dlg::OnBnClickedDetect) ON_WM_TIMER() ON_BN_CLICKED(IDC_Video, &CMy1420190255Dlg::OnBnClickedVideo)<span END_MESSAGE_MAP()void CMy1420190255Dlg::DoDataExchange(CDataExchange* pDX){ CDialogEx::DoDataExchange(pDX); DDX_Text(pDX, IDC_TIME, m_fTime); DDX_Text(pDX, IDC_NUM, m_nNum);}
(3) 画图到控件
void CMy1420190255Dlg::DrawImageToHDC(IplImage * pImg, UINT nID){ CvvImage image; CRect rect; //获取设备上下文 CDC *pDC = GetDlgItem(nID)->GetDC(); HDC hDC = pDC->GetSafeHdc(); //获取PictureBox边框 GetDlgItem(nID)->GetClientRect(&rect); //防止去除PictureBox的边框 rect.top = rect.top + 1; rect.bottom = rect.bottom - 1; rect.left = rect.left + 1; rect.right = rect.right - 1; //图像基本参数 int nWidth = pImg->width; int nHeight = pImg->height; //等比例缩放,防止图像变形 if ((rect.right - rect.left) < nWidth || (rect.bottom - rect.top)<nHeight) { if ((float)nWidth / (float)nHeight>(float)(rect.right - rect.left) / (float)(rect.bottom - rect.top)) { rect.bottom = nHeight*(rect.right - rect.left) / nWidth + rect.top; } else { rect.right = nWidth*(rect.bottom - rect.top) / nHeight + rect.left; } } else { rect.right = nWidth + rect.left; rect.bottom = nHeight + rect.top; } //获取图像,绘制图像设备 image.CopyOf(pImg); image.DrawToHDC(hDC, &rect); //释放资源 ReleaseDC(pDC); image.Destroy();}
(4) 清空控件图片
// 实际是用和对话框颜色的图像覆盖对话框void CMy1420190255Dlg::ClearControlImage(UINT nID){ CvvImage image; CRect rect; //获取设备上下文 CDC *pDC = GetDlgItem(nID)->GetDC(); HDC hDC = pDC->GetSafeHdc(); //获取PictureBox边框 GetDlgItem(nID)->GetClientRect(&rect); //创建与图像窗口大小一致的图像 IplImage* pImg = cvCreateImage(cvSize(rect.right - rect.left, rect.bottom - rect.left), IPL_DEPTH_8U, 3); //设置为背景色,通过取色发现,背景颜色为(240,240,240) cvSet(pImg, cvScalar(240, 240, 240)); //防止去除PictureBox的边框 rect.top = rect.top + 1; rect.bottom = rect.bottom - 1; rect.left = rect.left + 1; rect.right = rect.right - 1; //获取图像,绘制图像设备 image.CopyOf(pImg); image.DrawToHDC(hDC, &rect); //释放资源 ReleaseDC(pDC); cvReleaseImage(&pImg); image.Destroy();}
(5) 人脸检测子函数
void CMy1420190255Dlg::face_detect(IplImage * img){ double scale = 1.3; IplImage * copyImg = cvCloneImage(img); IplImage * gray = cvCreateImage(cvSize(copyImg->width, copyImg->height), 8, 1); IplImage * small_img = cvCreateImage(cvSize(cvRound(copyImg->width / scale), cvRound(copyImg->height / scale)), 8, 1); cvCvtColor(copyImg, gray, CV_BGR2GRAY); // 灰度化 cvResize(gray, small_img, CV_INTER_LINEAR); // 尺度 cvEqualizeHist(small_img, small_img); // 均衡化 cvClearMemStorage(storage); m_fTime = (float)cvGetTickCount(); CvSeq * faces = cvHaarDetectObjects(small_img, cascade, storage, 1.1, 2, 0/*CV_HAAR_DO_CANNY_PRUNING*/, cvSize(30, 30)); m_fTime = (float)cvGetTickCount() - m_fTime; m_fTime = (float)(m_fTime / (cvGetTickFrequency() * 1000)); if ( ! (m_nNum = faces->total)) m_fTime = 0; for (int i = 0; i < (faces ? faces->total : 0); i++) { CvRect * r = (CvRect *)cvGetSeqElem(faces, i); CvPoint center; int radius; center.x = cvRound((r->x + r->width * 0.5) *scale); center.y = cvRound((r->y + r->height * 0.5) *scale); radius = cvRound((r->width + r->height) * 0.25 * scale); cvCircle(copyImg, center, radius, colors[i % 8], 3, 8, 0); } cvReleaseImage(&m_pRstImg); m_pRstImg = cvCloneImage(copyImg); cvReleaseImage(©Img); cvReleaseImage(&gray); cvReleaseImage(&small_img);}
(6) 定时器
void CMy1420190255Dlg::OnTimer(UINT_PTR nIDEvent){ // TODO: 在此添加消息处理程序代码和/或调用默认值 switch (nIDEvent) { case 1: // 摄像机 cap >> m_Frame; m_frame = m_Frame; //Mat 转化为 IplImage if (!&m_frame) return; cvReleaseImage(&m_pImg); m_pImg = cvCloneImage(&m_frame); face_detect(m_pImg); DrawImageToHDC(m_pRstImg, IDC_SHOWPIC); UpdateData(FALSE); break; case 2: // 视频 capture >> m_vFrame; if (m_vFrame.data) { m_vframe = m_vFrame; //Mat 转化为 IplImage cvReleaseImage(&m_pImg); m_pImg = cvCloneImage(&m_vframe); face_detect(m_pImg); DrawImageToHDC(m_pRstImg, IDC_SHOWPIC); UpdateData(FALSE); } else { bPlayOver = TRUE; KillTimer(2); MessageBox("视频检测结束"); } break; case 3: // 仅显示获取的祯图片 if (m_nFileType == 1) { cap >> m_Frame_; m_frame_ = m_Frame_; if (!&m_frame_) return; cvReleaseImage(&m_pImg_); m_pImg_ = cvCloneImage(&m_frame_); DrawImageToHDC(m_pImg_, IDC_SHOWPIC); UpdateData(FALSE); } if (m_nFileType == 2) { capture >> m_vFrame_; if (m_vFrame_.data) { m_vframe_ = m_vFrame_; cvReleaseImage(&m_pImg_); m_pImg_ = cvCloneImage(&m_vframe_); DrawImageToHDC(m_pImg_, IDC_SHOWPIC); UpdateData(FALSE); } else { KillTimer(3); bPlayOver = TRUE; MessageBox("视频播放结束"); } } break; default: break; } CDialogEx::OnTimer(nIDEvent);}
(7) 以下是4个按钮的消息响应函数
摄像头按钮,视频文件按钮,图片文件按钮,检测按钮
//打开摄像头void CMy1420190255Dlg::OnBnClickedGetCam(){ // TODO: 在此添加控件通知处理程序代码 ClearControlImage(IDC_SHOWPIC); m_nNum = 0; m_fTime = 0; UpdateData(FALSE); storage = cvCreateMemStorage(0); if (capture.isOpened()) // 如果视频打开,释放,关闭定时器3 { KillTimer(3); capture.release(); if (bDttFlag == TRUE) KillTimer(2); // 检测状态,关闭定时器1 } bDttFlag = FALSE; m_nFileType = 1; if (!cap.isOpened()) { cap.open(CV_CAP_ANY); SetTimer(3, 40, NULL); // 显示 摄像头 或者 视频的 图像;}
//打开视频文件按钮void CMy1420190255Dlg::OnBnClickedVideo(){ // TODO: 在此添加控件通知处理程序代码 storage = cvCreateMemStorage(0); ClearControlImage(IDC_SHOWPIC); m_nNum = 0; m_fTime = 0; UpdateData(FALSE); if (cap.isOpened()) // 如果摄像头打开,释放,关闭定时器3 { KillTimer(3); cap.release(); if (bDttFlag == TRUE) KillTimer(1); // 检测状态,关闭定时器1 } bDttFlag = FALSE; bPlayOver = FALSE; m_nFileType = 2; CString FilePathName; const char* AviPathName; if (!capture.isOpened()) { CFileDialog FileOpenDlg(TRUE, "", "", OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "视频文件(*.avi;*.mp4;*.wmv)|*.avi;*.mp4;*.wmv|所有文件(*.*)|*.*||"); if (FileOpenDlg.DoModal() != IDOK) return; FilePathName = FileOpenDlg.GetPathName(); AviPathName = FilePathName.GetBuffer(sizeof(FilePathName)); // CString转const char* capture = VideoCapture(AviPathName); SetTimer(3, 40, NULL); // 显示 摄像头 或者 视频的 图像; } else { KillTimer(2); KillTimer(3); capture.release(); CFileDialog FileOpenDlg(TRUE, "", "", OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "视频文件(*.avi;*.mp4;*.wmv)|*.avi;*.mp4;*.wmv|所有文件(*.*)|*.*||"); if (FileOpenDlg.DoModal() != IDOK) return; FilePathName = FileOpenDlg.GetPathName(); AviPathName = FilePathName.GetBuffer(sizeof(FilePathName)); // CString转const char* capture = VideoCapture(AviPathName); SetTimer(3, 40, NULL); // 显示 摄像头 或者 视频的 图像; }}
//打开图片文件按钮void CMy1420190255Dlg::OnBnClickedPicture(){ // TODO: 在此添加控件通知处理程序代码 ClearControlImage(IDC_SHOWPIC); m_nNum = 0; m_fTime = 0; UpdateData(FALSE); if (cap.isOpened()) //如果摄像头打开,释放,关闭定时器3 { KillTimer(3); cap.release(); if (bDttFlag == TRUE) KillTimer(1); // 检测状态,关闭定时器1 } if (capture.isOpened()) // 如果视频打开,释放,关闭定时器3 { KillTimer(3); capture.release(); if (bDttFlag == TRUE) KillTimer(2); // 检测状态,关闭定时器1 } bDttFlag = FALSE; storage = cvCreateMemStorage(0); m_nFileType = 3; CString ImagePathName; if (m_pImg == NULL) { //获取打开文件路径 CFileDialog FileOpenDlg(TRUE, "", "", OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,"图像文件(*.BMP;*.JPG;*.PNG)|*.BMP;*.JPG;*.PNG|所有文件(*.*)|*.*||"); if (FileOpenDlg.DoModal() != IDOK) return; ImagePathName = FileOpenDlg.GetPathName(); m_pImg = cvLoadImage(ImagePathName); m_bDrawFlag = true; ClearControlImage(IDC_SHOWPIC); DrawImageToHDC(m_pImg, IDC_SHOWPIC); } else { CFileDialog FileOpenDlg(TRUE, "", "", OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "图像文件(*.BMP;*.JPG;*.PNG)|*.BMP;*.JPG;*.PNG|所有文件(*.*)|*.*||"); if (FileOpenDlg.DoModal() != IDOK) return; ImagePathName = FileOpenDlg.GetPathName(); cvReleaseImage(&m_pImg); m_pImg = cvLoadImage(ImagePathName); ClearControlImage(IDC_SHOWPIC); DrawImageToHDC(m_pImg, IDC_SHOWPIC); }}
// 人脸检测按钮
void CMy1420190255Dlg::OnBnClickedDetect(){ KillTimer(3); bDttFlag = TRUE; ClearControlImage(IDC_SHOWPIC); // TODO: 在此添加控件通知处理程序代码 switch (m_nFileType) { case 1: //摄像机 if (cap.isOpened()) SetTimer(1, 40, NULL); // 显示摄像机检测结果 else MessageBox("摄像机开启失败!"); break; case 2: // 视频 if (capture.isOpened()) { if (!bPlayOver) { SetTimer(2, 40, NULL); // 显示视频检测结果 bPlayOver = FALSE; } else MessageBox("视频已结束!"); } else MessageBox("视频读取失败!"); break; case 3: // 图片 face_detect(m_pImg); DrawImageToHDC(m_pRstImg, IDC_SHOWPIC); UpdateData(FALSE); break; default: // 没有文件,“0” break; } m_nFileType = 0; // 使得打开某个文件,点击检测之后,继续点击无效}
二、程序界面
程序不复杂,就不写整体的总结。要说明的是,这个程序可以在3个按钮实时的进行数据文件选择,所以两两之间逻辑关系,用到了几个标记,需要自己好好梳理流程。视频文件播放没有做成循环,可以在文件读完后从新定位到第一帧,实现请参考opencv代码。定时器取的40ms,对应的帧率问25fps。不同视频文件,播放和检测的画面播放可能较快或者减慢,需要统一视频文件的帧率或者在程序中设定。
附件(CvvImage类):
//CvvImage.cpp#include "StdAfx.h"#include "CvvImage.h"// Construction/DestructionCV_INLINE RECT NormalizeRect(RECT r);CV_INLINE RECT NormalizeRect(RECT r) { int t; if (r.left > r.right){ t = r.left; r.left = r.right; r.right = t; } if (r.top > r.bottom) { t = r.top; r.top = r.bottom; r.bottom = t; } return r;}CV_INLINE CvRect RectToCvRect(RECT sr);CV_INLINE CvRect RectToCvRect(RECT sr) { sr = NormalizeRect(sr); return cvRect(sr.left, sr.top, sr.right - sr.left, sr.bottom - sr.top);}CV_INLINE RECT CvRectToRect(CvRect sr);CV_INLINE RECT CvRectToRect(CvRect sr) { RECT dr; dr.left = sr.x; dr.top = sr.y; dr.right = sr.x + sr.width; dr.bottom = sr.y + sr.height; return dr;}CV_INLINE IplROI RectToROI(RECT r);CV_INLINE IplROI RectToROI(RECT r) { IplROI roi; r = NormalizeRect(r); roi.xOffset = r.left; roi.yOffset = r.top; roi.width = r.right - r.left; roi.height = r.bottom - r.top; roi.coi = 0; return roi;}void FillBitmapInfo(BITMAPINFO* bmi, int width, int height, int bpp, int origin) { assert(bmi && width >= 0 && height >= 0 && (bpp == 8 || bpp == 24 || bpp == 32)); BITMAPINFOHEADER* bmih = &(bmi->bmiHeader); memset(bmih, 0, sizeof(*bmih)); bmih->biSize = sizeof(BITMAPINFOHEADER); bmih->biWidth = width; bmih->biHeight = origin ? abs(height) : -abs(height); bmih->biPlanes = 1; bmih->biBitCount = (unsigned short)bpp; bmih->biCompression = BI_RGB; if (bpp == 8) { RGBQUAD* palette = bmi->bmiColors; int i; for (i = 0; i < 256; i++) { palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed = (BYTE)i; palette[i].rgbReserved = 0; } }}CvvImage::CvvImage() { m_img = 0; }void CvvImage::Destroy() { cvReleaseImage(&m_img); }CvvImage::~CvvImage() { Destroy(); }bool CvvImage::Create(int w, int h, int bpp, int origin) { const unsigned max_img_size = 10000; if ((bpp != 8 && bpp != 24 && bpp != 32) || (unsigned)w >= max_img_size || (unsigned)h >= max_img_size || (origin != IPL_ORIGIN_TL && origin != IPL_ORIGIN_BL)) { assert(0); // most probably, it is a programming error return false; } if (!m_img || Bpp() != bpp || m_img->width != w || m_img->height != h) { if (m_img && m_img->nSize == sizeof(IplImage)) Destroy(); m_img = cvCreateImage(cvSize(w, h), IPL_DEPTH_8U, bpp / 8); } if (m_img) m_img->origin = origin == 0 ? IPL_ORIGIN_TL : IPL_ORIGIN_BL; return m_img != 0;}void CvvImage::CopyOf(CvvImage& image, int desired_color) { IplImage* img = image.GetImage(); if (img) { CopyOf(img, desired_color); }}#define HG_IS_IMAGE(img) \ ((img) != 0 && ((const IplImage*)(img))->nSize == sizeof(IplImage) && \ ((IplImage*)img)->imageData != 0)void CvvImage::CopyOf(IplImage* img, int desired_color){ if (HG_IS_IMAGE(img)) { int color = desired_color; CvSize size = cvGetSize(img); if (color < 0) color = img->nChannels > 1; if (Create(size.width, size.height, (!color ? 1 : img->nChannels > 1 ? img->nChannels : 3) * 8, img->origin)) { cvConvertImage(img, m_img, 0); } }}bool CvvImage::Load(const char* filename, int desired_color){ IplImage* img = cvLoadImage(filename, desired_color); if (!img) return false; CopyOf(img, desired_color); cvReleaseImage(&img); return true;}bool CvvImage::LoadRect(const char* filename, int desired_color, CvRect r){ if (r.width < 0 || r.height < 0) return false; IplImage* img = cvLoadImage(filename, desired_color); if (!img) return false; if (r.width == 0 || r.height == 0) { r.width = img->width; r.height = img->height; r.x = r.y = 0; } if (r.x > img->width || r.y > img->height || r.x + r.width < 0 || r.y + r.height < 0) { cvReleaseImage(&img); return false; } if (r.x < 0) { r.width += r.x; r.x = 0; } if (r.y < 0) { r.height += r.y; r.y = 0; } if (r.x + r.width > img->width) r.width = img->width - r.x; if (r.y + r.height > img->height) r.height = img->height - r.y; cvSetImageROI(img, r); CopyOf(img, desired_color); cvReleaseImage(&img); return true;}bool CvvImage::Save(const char* filename){ if (!m_img) return false; cvSaveImage(filename, m_img); return true;}void CvvImage::Show(const char* window){ if (m_img) cvShowImage(window, m_img);}void CvvImage::Show(HDC dc, int x, int y, int w, int h, int from_x, int from_y){ if (m_img && m_img->depth == IPL_DEPTH_8U) { uchar buffer[sizeof(BITMAPINFOHEADER)+1024]; BITMAPINFO* bmi = (BITMAPINFO*)buffer; int bmp_w = m_img->width, bmp_h = m_img->height; FillBitmapInfo(bmi, bmp_w, bmp_h, Bpp(), m_img->origin); from_x = MIN(MAX(from_x, 0), bmp_w - 1); from_y = MIN(MAX(from_y, 0), bmp_h - 1); int sw = MAX(MIN(bmp_w - from_x, w), 0); int sh = MAX(MIN(bmp_h - from_y, h), 0); SetDIBitsToDevice( dc, x, y, sw, sh, from_x, from_y, from_y, sh, m_img->imageData + from_y*m_img->widthStep, bmi, DIB_RGB_COLORS); }}void CvvImage::DrawToHDC(HDC hDCDst, RECT* pDstRect){ if (pDstRect && m_img && m_img->depth == IPL_DEPTH_8U && m_img->imageData) { uchar buffer[sizeof(BITMAPINFOHEADER)+1024]; BITMAPINFO* bmi = (BITMAPINFO*)buffer; int bmp_w = m_img->width, bmp_h = m_img->height; CvRect roi = cvGetImageROI(m_img); CvRect dst = RectToCvRect(*pDstRect); if (roi.width == dst.width && roi.height == dst.height) { Show(hDCDst, dst.x, dst.y, dst.width, dst.height, roi.x, roi.y); return; } if (roi.width > dst.width) { SetStretchBltMode(hDCDst, HALFTONE); // handle to device context } else { SetStretchBltMode(hDCDst, COLORONCOLOR); } FillBitmapInfo(bmi, bmp_w, bmp_h, Bpp(), m_img->origin); ::StretchDIBits( hDCDst, dst.x, dst.y, dst.width, dst.height, roi.x, roi.y, roi.width, roi.height, m_img->imageData, bmi, DIB_RGB_COLORS, SRCCOPY); }}void CvvImage::Fill(int color){ cvSet(m_img, cvScalar(color & 255, (color >> 8) & 255, (color >> 16) & 255, (color >> 24) & 255));}
// CvvImage.h#pragma once#ifndef CVVIMAGE_CLASS_DEF#define CVVIMAGE_CLASS_DEF#include "opencv2/opencv.hpp"class CvvImage{public: CvvImage(); virtual ~CvvImage(); virtual bool Create(int width, int height, int bits_per_pixel, int image_origin = 0); virtual bool Load(const char* filename, int desired_color = 1); virtual bool LoadRect(const char* filename, int desired_color, CvRect r);#if defined WIN32 || defined _WIN32 virtual bool LoadRect(const char* filename, int desired_color, RECT r) { return LoadRect(filename, desired_color, cvRect(r.left, r.top, r.right - r.left, r.bottom - r.top)); }#endif virtual bool Save(const char* filename); virtual void CopyOf(CvvImage& image, int desired_color = -1); virtual void CopyOf(IplImage* img, int desired_color = -1); IplImage* GetImage() { return m_img; }; virtual void Destroy(void); int Width() { return !m_img ? 0 : !m_img->roi ? m_img->width : m_img->roi->width; }; int Height() { return !m_img ? 0 : !m_img->roi ? m_img->height : m_img->roi->height; }; int Bpp() { return m_img ? (m_img->depth & 255)*m_img->nChannels : 0; }; virtual void Fill(int color); virtual void Show(const char* window);#if defined WIN32 || defined _WIN32 virtual void Show(HDC dc, int x, int y, int width, int height, int from_x = 0, int from_y = 0); virtual void DrawToHDC(HDC hDCDst, RECT* pDstRect);#endifprotected: IplImage* m_img;};//typedef CvvImage CImage;namespace cv{ typedef CvvImage CImage;}#endif
完整的工程文件打包(包含了最初的控制台程序)点击下载。(其他opencv版本,修改引用和添加依赖库,重新编译即可)
- opencv3.0+VS2013平台人脸检测MFC
- opencv+人脸检测(OpenCv3.0+VS2013)
- VS2013 MFC使用opencv3.0显示图片
- VS2013 MFC + OpenCV3.0 打开图片
- win7平台下vs2013配置opencv3.0
- win7平台下vs2013配置opencv3.0
- vs13 opencv3.0 人脸检测
- VS2013+openCV3.0置配【64位windows平台】
- VS2013配置OpenCV3.0
- VS2013配置OpenCV3.0
- opencv3.0, vs2013配置
- VS2013配置Opencv3.0
- VS2013+opencv3.0配置
- VS2013配置opencv3.0
- OpenCV3.0 + vs2013 +win8
- VS2013编译opencv3.0
- qt+vs2013+opencv3.0
- Windows平台下OpenCV3源码编译(VS2013)
- jsonp
- Java学习--多线程中synchronized的使用心得
- IOC(Inverse of Controller) 控制反转
- php-fpm
- android view 绘制流程
- opencv3.0+VS2013平台人脸检测MFC
- linux常用命令:mkdir,more,less,
- makefile知识点01
- Android 之短信验证码自动填写
- Extjs和jQuery的区别
- 工控自动化通讯测试工具总结之--串口
- hdu 5289 Assignment(2015 Multi-University Training Contest 1)
- 数组的下标访问和指针访问方式效率分析比较
- 微信QQ骗子资料曝光