//#include "stdafx.h"
#define _AFXDLL //spc
#include "afx.h"
#include "cv.h"
#include "highgui.h"
#include <stdio.h>
#include <ctype.h>
#include<iostream>
using namespace std;
static CvHaarClassifierCascade* faceCascade = 0;
const char* cascade_name = "haarcascade_frontalface_alt2.xml";
IplImage *image = 0, *hsv = 0, *hue = 0, *mask[10] = { 0 }, *backproject[10] = { 0 }, *histimg[10] = { 0 };//backproject为反向投影图像
CvHistogram *hist[10] = { 0 };//存储颜色直方图
int nFaces;
double area0[100] = { 0 }, area1[100] = { 0 };//某一跟踪窗口的面积
int backproject_mode = 0;
int select_object = 0;
int track_object = 0;
CvPoint origin;
CvRect selection[10];
CvRect track_window[10] = { 0 };
CvBox2D track_box;
CvConnectedComp track_comp;
int hdims = 24;
float hranges_arr[] = { 0, 180 };
float* hranges = hranges_arr;
int vmin = 90, vmax = 256, smin = 90;
CvScalar hsv2rgb(float hue);
void detectFaceInImage(IplImage *inputImg, CvHaarClassifierCascade* cascade);
int main()
{
CvCapture* capture = 0;
//capture = cvCaptureFromCAM(0);
capture = cvCaptureFromFile("1.mp4"); //spc
//capture = cvCreateCameraCapture(0); //spc
if (!capture)
{
fprintf(stderr, "Could not initialize capturing...\n");
return -1;
}
cvNamedWindow("CamShiftDemo", 1);
cvCreateTrackbar("Vmin", "CamShiftDemo", &vmin, 256, 0);//Vmin被创建的trackbar名字,CamShiftDemo为工具条属于的窗口,vmin这个变量指定创建时的滑块位置
cvCreateTrackbar("Vmax", "CamShiftDemo", &vmax, 256, 0);
cvCreateTrackbar("Smin", "CamShiftDemo", &smin, 256, 0);
IplImage* frame = 0;
frame = cvQueryFrame(capture);
while (1)
{
int c;
frame = cvQueryFrame(capture);//获取摄像头的序列,将图像序列存在frame中
if (!frame)
break;
if (!image)//image是进行处理的图像,开始的时候image = 0;若image =0,则要分配初始空间
{
image = cvCreateImage(cvGetSize(frame), 8, 3);
image->origin = frame->origin;
hsv = cvCreateImage(cvGetSize(frame), 8, 3);
hue = cvCreateImage(cvGetSize(frame), 8, 1);
}
cvCopy(frame, image, 0);
cvCvtColor(image, hsv, CV_RGB2HSV);
faceCascade = (CvHaarClassifierCascade*)cvLoad(cascade_name, 0, 0, 0);
if (!faceCascade)
{
fprintf(stderr, "ERROR: Could not load classifier cascade\n");
return -1;
}
if (!track_object)
{
detectFaceInImage(image, faceCascade);
}//检测人脸区域,将检测到的一系列人脸区域存储到selection[]中,得到初始的搜索窗口
else//track_object = 1或者是-1,进行人脸跟踪
{
int _vmin = vmin, _vmax = vmax;
cvSplit(hsv, hue, 0, 0, 0);//提取人脸图像的Hue分量
if (track_object<0)//track_object < 0 ,表示刚刚检测到人脸区域,然后进行人脸区域直方图计算
{
for (int n = 0; n < nFaces; n++)
{
mask[n] = cvCreateImage(cvGetSize(frame), 8, 1);//得到全黑的mask
cvZero(mask[n]);
backproject[n] = cvCreateImage(cvGetSize(frame), 8, 1);
hist[n] = cvCreateHist(1, &hdims, CV_HIST_ARRAY, &hranges, 1);
cvSetImageROI(mask[n], selection[n]);//此时是检测到的人脸区域用于得到掩膜
cvAddS(mask[n], cvScalar(255), mask[n]);//得到mask掩膜,用于求人脸部分的hue分量的直方图
float max_val = 0.f;
cvSetImageROI(hue, selection[n]);
cvDilate(hue, hue, NULL, 2);
cvErode(hue, hue, NULL, 2);
cvSmooth(hue, hue, CV_MEDIAN, 3, 0, 0, 0);
cvCalcHist(&hue, hist[n], 0, mask[n]);//建立人脸区域Hue分量的颜色直方图
cvResetImageROI(hue);//释放ROI区域
cvResetImageROI(mask[n]);
track_window[n] = selection[n];//此时的跟踪窗口是上步中人脸检测得到的区域。
track_object = 1;//计算得到图像的直方图后,是track_objedt=1 ,方便后面进行跟踪,且不在计算初始的搜索窗口的颜色直方图以及掩膜图像
}
}
else
{
for (int k = 0; k < nFaces; k++)
{
cvZero(mask[k]);
cvSetImageROI(mask[k], track_window[k]);//此时是用跟踪到的人脸区域得到掩膜图像
cvAddS(mask[k], cvScalar(255), mask[k]);
cvResetImageROI(mask[k]);//得到mask掩膜,用于求人脸部分的hue分量的直方图
}
}
//下面是利用上面得到的直方图,以及掩膜图像得到反向投影图像
for (int m = 0; m < nFaces; m++)
{
cvCalcBackProject(&hue, backproject[m], hist[m]);//计算人脸部分的hue分量在整幅图像中的反向投影图
cvAnd(backproject[m], mask[m], backproject[m], 0);
cvDilate(backproject[m], backproject[m], NULL, 2);
cvErode(backproject[m], backproject[m], NULL, 2);
}
for (int m = 0; m < nFaces; m++)
{
cvCamShift(backproject[m], track_window[m],
cvTermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 10, 1),
&track_comp, &track_box);//使用camshift进行人脸跟踪
area0[m] = track_window[m].height * track_window[m].width;
area1[m] = track_comp.rect.height * track_comp.rect.width;
track_window[m] = track_comp.rect;//重新设置搜索窗口
if (image->origin)
track_box.angle = -track_box.angle;
cvEllipseBox(image, track_box, CV_RGB(255, 0, 0), 3, CV_AA, 0);
}
for (int l = 0; l < nFaces; l++)
{
if ((0.4 * area0[l] <= area1[l]) && (area1[l] <= 1.1 * area0[l]))
track_object = 1;
else
track_object = 0;
}
}
cvShowImage("CamShiftDemo", image);//显示的是人脸图像的跟踪情况
c = cvWaitKey(5);//此处过大的话时间就会等很久,在这个小问题上一定要注意,否则的话跟踪效率很低。
if (c == 27)//ESC,退出程序
break;
}
cvReleaseCapture(&capture);
cvDestroyWindow("CamShiftDemo");
return 0;
}
//下面是颜色空间
CvScalar hsv2rgb(float hue)
{
int rgb[3], p, sector;
static const int sector_data[][3] =
{ { 0, 2, 1 }, { 1, 2, 0 }, { 1, 0, 2 }, { 2, 0, 1 }, { 2, 1, 0 }, { 0, 1, 2 } };
hue *= 0.033333333333333333333333333333333f;
sector = cvFloor(hue);
p = cvRound(255 * (hue - sector));
p ^= sector & 1 ? 255 : 0;
rgb[sector_data[sector][0]] = 255;
rgb[sector_data[sector][1]] = 0;
rgb[sector_data[sector][2]] = p;
return cvScalar(rgb[2], rgb[1], rgb[0], 0);
}
void detectFaceInImage(IplImage* inputImg, CvHaarClassifierCascade* cascade)
{
CvSize minFeatureSize = cvSize(50, 50);
int flags = CV_HAAR_DO_CANNY_PRUNING;
float search_scale_factor = 1.2f;
IplImage *detectImg;
IplImage *greyImg = 0;
CvMemStorage* storage;
CvSize size;
int ms;
storage = cvCreateMemStorage(0);
cvClearMemStorage(storage);
// If the image is color, use a greyscale copy of the image.
detectImg = (IplImage*)inputImg;
if (inputImg->nChannels > 1)
{
size = cvSize(inputImg->width, inputImg->height);
greyImg = cvCreateImage(size, IPL_DEPTH_8U, 1);
cvCvtColor(inputImg, greyImg, CV_BGR2GRAY);
detectImg = greyImg; // Use the greyscale image.
}
// Detect all the faces in the greyscale image.
double t = (double)cvGetTickCount();
CvSeq* rects = cvHaarDetectObjects(detectImg, cascade, storage, search_scale_factor, 2, flags, minFeatureSize);
t = (double)cvGetTickCount() - t;
ms = cvRound(t / ((double)cvGetTickFrequency() * 1000.0));
nFaces = rects->total;
printf("Face Detection took %d ms and found %d objects\n", ms, nFaces);
if (nFaces > 0)
{
for (int i = 0; i < nFaces; i++)
{
selection[i] = *(CvRect*)cvGetSeqElem(rects, i);
cvRectangle(inputImg, cvPoint(selection[i].x - 3, selection[i].y - 3), cvPoint(selection[i].x + selection[i].width + 2, selection[i].y + selection[i].height + 2), CV_RGB(255, 0, 0), 3);
track_object = -1;
}
}
else
selection[0] = cvRect(-1, -1, -1, -1);
if (greyImg)
cvReleaseImage(&greyImg);
cvReleaseMemStorage(&storage);
}
评论0