添加功能
接着上一篇,加入其它功能。
如图:
按照之前的添加方法,为每个Button添加如下代码:
之前的代码也有所改动:
在XxxDlg.h中添加:
添加的代码:
#include "cv.h"
#include "highgui.h"
#include "CvvImage.h"
#include <iostream>
using namespace std;
//为人脸检测功能添加头文件
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
#include <float.h>
#include <limits.h>
#include <time.h>
#include <ctype.h>
#ifdef _EiC
#define WIN32
#endif
static CvMemStorage* storage = 0;
static CvHaarClassifierCascade* cascade = 0;
需要手工添加的函数:
//添加声明
void DrawPicToHDC(IplImage * img , UINT ID);
// 读图像
IplImage * ReadImage();
// 将图像转为灰度图像
IplImage * ImageGray();
//人脸检测
IplImage * detect_and_draw( IplImage* img );
在XxxDlg.cpp中,添加的代码有。
//添加代码
void CImageDemo1Dlg::DrawPicToHDC(IplImage *img, UINT ID)
{
CDC *pDC = GetDlgItem(ID)->GetDC();
HDC hDC= pDC->GetSafeHdc();
CRect rect;
GetDlgItem(ID)->GetClientRect(&rect);
CvvImage cimg;
cimg.CopyOf( img ); // 复制图片
cimg.DrawToHDC( hDC, &rect ); // 将图片绘制到显示控件的指定区域内
ReleaseDC( pDC );
}
//与上篇不同,这里将读图单独写为一个函数,以便之后的使用
IplImage * CImageDemo1Dlg::ReadImage()
{
IplImage *img=NULL; //原始图像
if(img) cvReleaseImage(&img);
img = cvLoadImage("lena.jpg",1); //显示图片
return img;
}
void CImageDemo1Dlg::OnBnClickedBopen()
{
// TODO: 在此添加控件通知处理程序代码
IplImage *img=NULL; //原始图像
//if(img) cvReleaseImage(&img);
//img = cvLoadImage("lena.jpg",1); //显示图片
img = ReadImage();
DrawPicToHDC(img, IDC_STATIC);
cvReleaseImage(&img);
}
//对图像做高斯平滑处理
void CImageDemo1Dlg::OnBnClickedBsmooth()
{
// TODO: 在此添加控件通知处理程序代码
IplImage * out = NULL;
out = ReadImage();
cvSmooth(out,out,CV_GAUSSIAN, 7,7);
DrawPicToHDC(out, IDC_STATIC);
cvReleaseImage(&out);
}
// 膨胀
void CImageDemo1Dlg::OnBnClickedBerode()
{
// TODO: 在此添加控件通知处理程序代码
IplImage * out = NULL;
out = ReadImage();
cvErode(out,out,0,1);
DrawPicToHDC(out, IDC_STATIC);
cvReleaseImage(&out);
}
// 腐蚀
void CImageDemo1Dlg::OnBnClickedBdilate()
{
// TODO: 在此添加控件通知处理程序代码
IplImage * out = NULL;
out = ReadImage();
cvDilate(out,out,0,1);
DrawPicToHDC(out, IDC_STATIC);
cvReleaseImage(&out);
}
// 自适应阈值化
void CImageDemo1Dlg::OnBnClickedBthreshold()
{
// TODO: 在此添加控件通知处理程序代码
IplImage * Igray = ImageGray();
cvAdaptiveThreshold(Igray, Igray, 255,
CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, 3, 5);
DrawPicToHDC(Igray, IDC_STATIC);
cvReleaseImage(&Igray);
}
// Sobel 导数
void CImageDemo1Dlg::OnBnClickedBsobel()
{
// TODO: 在此添加控件通知处理程序代码
IplImage * out = NULL;
out = ReadImage();
cvSobel(out,out,0,1,3);
DrawPicToHDC(out, IDC_STATIC);
cvReleaseImage(&out);
}
// 拉普拉斯
void CImageDemo1Dlg::OnBnClickedBlaplace()
{
// TODO: 在此添加控件通知处理程序代码
IplImage * out = NULL;
out = ReadImage();
cvLaplace(out,out,7);
DrawPicToHDC(out, IDC_STATIC);
cvReleaseImage(&out);
}
// canny算子
void CImageDemo1Dlg::OnBnClickedBcanny()
{
// TODO: 在此添加控件通知处理程序代码
IplImage * img = ReadImage();
IplImage* out = cvCreateImage(
cvGetSize(img),IPL_DEPTH_8U,
1); // Canny只接受单通道图像
cvCanny(img, out, 50, 150, 3);
DrawPicToHDC(out, IDC_STATIC);
cvReleaseImage(&out);
cvReleaseImage(&img);
}
// 图像卷积
void CImageDemo1Dlg::OnBnClickedBfilter()
{
// TODO: 在此添加控件通知处理程序代码
float ke[9] = {1.0, -2.0, 1.0,
2.0, -4.0, 2.0,
1.0, -2.0, 1.0
};
CvMat km;
km = cvMat(3,3, CV_32FC1,ke);
IplImage * out = ReadImage();
cvFilter2D(out, out, &km, cvPoint(-1,-1));
DrawPicToHDC(out, IDC_STATIC);
cvReleaseImage(&out);
}
//直方图均衡化
void CImageDemo1Dlg::OnBnClickedBequalhist()
{
// TODO: 在此添加控件通知处理程序代码
IplImage * img = ReadImage();
int i;
IplImage* pImageChannel[4] = {0, 0, 0, 0};
IplImage* pImage = cvCreateImage(cvGetSize(img), img->depth, img->nChannels);
for(i = 0; i < img->nChannels; i++)
{
pImageChannel[i] = cvCreateImage(cvGetSize(img), img->depth,1);
}
//信道分离
cvSplit(img, pImageChannel[0], pImageChannel[1], pImageChannel[2],pImageChannel[3]);
for(i = 0; i<pImage->nChannels; i++)
{
//直方图均衡化
cvEqualizeHist(pImageChannel[i], pImageChannel[i]);
}
//信道组合
cvMerge(pImageChannel[0],pImageChannel[1], pImageChannel[2],pImageChannel[3], pImage);
// 释放资源
for( i = 0; i < img->nChannels; i++ )
{
if ( pImageChannel[i] )
{
cvReleaseImage( &pImageChannel[i] );
pImageChannel[i] = 0;
}
}
//
DrawPicToHDC(pImage, IDC_STATIC);
}
// 输出彩色图像的直方图
void CImageDemo1Dlg::OnBnClickedBhist()
{
// TODO: 在此添加控件通知处理程序代码
IplImage * img = ReadImage();
IplImage* hsv = cvCreateImage(cvGetSize(img), 8, 3);
IplImage* h_plane = cvCreateImage(cvGetSize(img), 8, 1);
IplImage* s_plane = cvCreateImage(cvGetSize(img), 8, 1);
IplImage* v_plane = cvCreateImage(cvGetSize(img), 8, 1);
IplImage* planes[] = {h_plane, s_plane};
int h_bins = 16,s_bins = 8;
int hist_size[] = {h_bins, s_bins};
// H分量的变化范围
float h_ranges[] = {0,180};
// S分量的变化范围
float s_ranges[] = {0,255};
float* ranges[] = {h_ranges, s_ranges};
//将图像转换到HSV颜色空间
cvCvtColor(img,hsv, CV_BGR2HSV);
cvCvtPixToPlane(hsv, h_plane, s_plane, v_plane, 0);
//创建直方图
CvHistogram* hist = cvCreateHist(2, hist_size, CV_HIST_ARRAY, ranges, 1);
// 根据H,S两个平面数据统计直方图
cvCalcHist(planes,hist, 0,0);
//获取直方图统计的最大值和最小值,用于动态显示直方图
float max_value;
cvGetMinMaxHistValue(hist, 0, &max_value, 0, 0);
//设置直方图显示图像
int height = 240;
int width = (h_bins*s_bins*6);
IplImage* hist_img = cvCreateImage(cvSize(width, height), 8, 3);
cvZero(hist_img);
//用来进行HSV到RGB颜色转换的临时图像
IplImage* hsv_color = cvCreateImage(cvSize(1,1), 8,3);
IplImage* rgb_color = cvCreateImage(cvSize(1,1), 8, 3);
int bin_w = width/(h_bins*s_bins);
for(int h = 0; h < h_bins; h++)
{
for(int s = 0; s < s_bins; s++)
{
int i = h*s_bins+s;
//获得直方图中的统计次数,计算显示在图中的高度
float bin_val = cvQueryHistValue_2D(hist, h, s);
int intensity = cvRound(bin_val*height/max_value);
//获取当前直方图代表的颜色,转换成RGB用于绘制
cvSet2D(hsv_color, 0, 0, cvScalar(h*180.f/h_bins, s*255.f/s_bins, 255,0));
cvCvtColor(hsv_color, rgb_color,CV_HSV2BGR);
CvScalar color = cvGet2D(rgb_color, 0, 0);
cvRectangle(hist_img, cvPoint(i*bin_w, height),
cvPoint((i+1)*bin_w, height - intensity),
color, -1, 8, 0);
}
}
//
DrawPicToHDC(hist_img, IDC_STATIC);
cvReleaseImage(&img);
cvReleaseImage(&hsv);
cvReleaseImage(&h_plane);
cvReleaseImage(&s_plane);
cvReleaseImage(&v_plane);
cvReleaseImage(&hsv_color);
cvReleaseImage(&rgb_color);
cvReleaseImage(&hist_img);
}
// 将图像转换为灰度图像
IplImage * CImageDemo1Dlg::ImageGray()
{
IplImage * img = ReadImage();
IplImage * Igray = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
cvCvtColor(img, Igray, CV_RGB2GRAY);
cvReleaseImage(&img);
return Igray;
}
// 输出灰度图像
void CImageDemo1Dlg::OnBnClickedBgray()
{
// TODO: 在此添加控件通知处理程序代码
IplImage * Igray = ImageGray();
DrawPicToHDC(Igray, IDC_STATIC);
}
// 透视变换
void CImageDemo1Dlg::OnBnClickedBperspective()
{
// TODO: 在此添加控件通知处理程序代码
IplImage * img = ReadImage();
CvPoint2D32f srcQuad[4], dstQuad[4];
CvMat* warp_matrix = cvCreateMat(3,3, CV_32FC1);
IplImage *dst;
dst = cvCloneImage(img);
dst->origin = img->origin;
cvZero(dst);
srcQuad[0].x = 0;
srcQuad[0].y = 0;
srcQuad[1].x = img->width -1;
srcQuad[1].y = 0;
srcQuad[2].x = 0;
srcQuad[2].y = img->height -1;
srcQuad[3].x = img->width -1;
srcQuad[3].y = img->height -1;
dstQuad[0].x = img->width*0.05;
dstQuad[0].y = img->height*0.33;
dstQuad[1].x = img->width*0.9;
dstQuad[1].y = img->height*0.25;
dstQuad[2].x = img->width*0.2;
dstQuad[2].y = img->height*0.7;
dstQuad[3].x = img->width*0.8;
dstQuad[3].y = img->height*0.9;
cvGetPerspectiveTransform(
srcQuad,
dstQuad,
warp_matrix
);
cvWarpPerspective(img, dst, warp_matrix);
//
DrawPicToHDC(dst, IDC_STATIC);
cvReleaseImage(&dst);
}
// 仿射变换
void CImageDemo1Dlg::OnBnClickedBaffine()
{
// TODO: 在此添加控件通知处理程序代码
IplImage * img = ReadImage();
CvPoint2D32f srcTri[3], dstTri[3];
CvMat* rot_mat = cvCreateMat(2,3, CV_32FC1);
CvMat* warp_mat = cvCreateMat(2,3,CV_32FC1);
IplImage* dst = cvCloneImage(img);
dst->origin = img->origin;
cvZero(dst);
srcTri[0].x = 0;
srcTri[0].y = 0;
srcTri[1].x = img->width-1;
srcTri[1].y = 0;
srcTri[2].x = 0;
srcTri[2].y = img->height-1;
dstTri[0].x = img->width * 0.0;
dstTri[0].y = img->height * 0.33;
dstTri[1].x = img->width * 0.85;
dstTri[1].y = img->height * 0.25;
dstTri[2].x = img->width * 0.15;
dstTri[2].y = img->height * 0.7;
cvGetAffineTransform(srcTri, dstTri, warp_mat); // 计算仿射矩阵
cvWarpAffine(img, dst, warp_mat);
cvCopy(dst, img);
// 计算旋转矩阵
CvPoint2D32f center = cvPoint2D32f(
img ->width/2,
img ->height/2
);
double angle = -50.0;
double scale = 0.6;
cv2DRotationMatrix(center, angle, scale, rot_mat);
cvWarpAffine(img, dst, rot_mat);
//
DrawPicToHDC(dst, IDC_STATIC);
cvReleaseImage(&dst);
}
//霍夫线变换
void CImageDemo1Dlg::OnBnClickedBhoughline()
{
// TODO: 在此添加控件通知处理程序代码
IplImage * img = ReadImage();
IplImage* dst = cvCreateImage(cvGetSize(img), 8, 1);
IplImage* color_dst = cvCreateImage(cvGetSize(img), 8, 3);
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* lines = 0;
cvCanny(img, dst, 50, 200, 3);
cvCvtColor(dst, color_dst, CV_GRAY2BGR);
lines = cvHoughLines2(dst, storage, CV_HOUGH_PROBABILISTIC,1, CV_PI/180,80,30,10);
int i;
for(i = 0; i<lines->total; i++)
{
CvPoint* line = (CvPoint*)cvGetSeqElem(lines, i);
cvLine(color_dst, line[0], line[1], CV_RGB(255,0,0), 3, 8);
}
//
DrawPicToHDC(color_dst, IDC_STATIC);
cvReleaseImage(&dst);
cvReleaseImage(&color_dst);
}
void CImageDemo1Dlg::OnBnClickedBhoughcircles()
{
// TODO: 在此添加控件通知处理程序代码
IplImage * img = ReadImage();
IplImage* dst = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
cvCvtColor(img,dst,CV_RGB2GRAY);
CvMemStorage* storage = cvCreateMemStorage(0);
cvSmooth(dst,dst,CV_GAUSSIAN, 5,5);
CvSeq* circle = cvHoughCircles(dst, storage, CV_HOUGH_GRADIENT, 2, img->width/10);
for(int i = 0; i < circle->total; i++)
{
float* p = (float*) cvGetSeqElem(circle, i);
CvPoint pt = cvPoint(cvRound(p[0]), cvRound(p[1]));
cvCircle(dst, pt, cvRound(p[2]), CV_RGB(255,255,255));
}
//
DrawPicToHDC(dst, IDC_STATIC);
cvReleaseImage(&dst);
}
// 关闭窗口
void CImageDemo1Dlg::OnBnClickedBclose()
{
// TODO: 在此添加控件通知处理程序代码
CImageDemo1Dlg::OnCancel();
}
//检测人脸并标记
IplImage * CImageDemo1Dlg::detect_and_draw(IplImage * img)
{
double scale=1.2;
static CvScalar colors[] = {
{{0,0,255}},{{0,128,255}},{{0,255,255}},{{0,255,0}},
{{255,128,0}},{{255,255,0}},{{255,0,0}},{{255,0,255}}
};//Just some pretty colors to draw with
IplImage* gray = cvCreateImage(cvSize(img->width,img->height),8,1);
IplImage* small_img=cvCreateImage(cvSize(cvRound(img->width/scale),cvRound(img->height/scale)),8,1);
cvCvtColor(img,gray, CV_BGR2GRAY);
cvResize(gray, small_img, CV_INTER_LINEAR);
cvEqualizeHist(small_img,small_img); //直方图均衡
//Detect objects if any
//
cvClearMemStorage(storage);
double t = (double)cvGetTickCount();
CvSeq* objects = cvHaarDetectObjects(small_img, cascade, storage, 1.1, 2,
0/*CV_HAAR_DO_CANNY_PRUNING*/,
cvSize(30,30));
t = (double)cvGetTickCount() - t;
//printf( "detection time = %gms\n", t/((double)cvGetTickFrequency()*1000.) );
//Loop through found objects and draw boxes around them
for(int i=0;i<(objects? objects->total:0);++i)
{
CvRect* r=(CvRect*)cvGetSeqElem(objects,i);
cvRectangle(img, cvPoint(r->x*scale,r->y*scale), cvPoint((r->x+r->width)*scale,(r->y+r->height)*scale), colors[i%8]);
}
for( int i = 0; i < (objects? objects->total : 0); i++ )
{
CvRect* r = (CvRect*)cvGetSeqElem( objects, 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( img, center, radius, colors[i%8], 3, 8, 0 );
}
//cvShowImage("result",img);
return img;
}
// 人脸检测
const char* cascade_name =
"haarcascade_frontalface_alt.xml";
void CImageDemo1Dlg::OnBnClickedBface()
{
// TODO: 在此添加控件通知处理程序代码
cascade_name = "E:\\Program Files (x86)\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt2.xml";
cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 );
storage = cvCreateMemStorage(0);
IplImage* image = ReadImage();
image = detect_and_draw(image);
DrawPicToHDC(image, IDC_STATIC);
}
测试功能如下图:
人脸检测功能
拉普拉斯算子:
自适应阈值:
直方图均衡化:
彩色图像直方图:
这里不在一一尝试。