【haartraining】正样本 只框头部 (I)
这个版本的头部可以框出,但是好像不是很清晰,最好能改在原尺寸上。。。
后面改进后好一些了。。
//opencv2.0风格 //本程序有几个可调值 //1.背景更新 学习率 learningRate //2.去掉小面积阈值 area_threshold #include "cv.h" #include "highgui.h" #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/core/core.hpp> #include <iostream> #include <string> #include <cstdio> using namespace std; using namespace cv; //函数声明 void findBoundary(Rect r,Point &a,Point &c);//找到贴合矩形框 void biggerRect(Point &a,Point &c,Mat img); //将矩形框适当放大 void hugeRect(Point &a,Point &c,Mat img); //如果比例缩小太大,直接将矩形巨大化 void pedDetection(Mat& img);//行人检测 void saveImg(Mat img); void detectAndDraw( Mat& img, CascadeClassifier& cascade, double scale); //String cascadeName = "./haarcascades/haarcascade_frontalface_alt2.xml";//人脸的训练数据 String cascadeName = "./cascades.xml";//高密度人头检测训练数据 char input_name[50]; char outFolder[50]; char countChar[10000]; char tmp[50]; int cnt=0; //主函数 int main() { //输入 cout<<"please input the src video :"<<endl; cin>>input_name; cout<<"please input the output folder :"<<endl; cin>>outFolder; //可调参数 //char* input_name = "0012.mp4"; double fScale = 0.5; //缩放倍数 double learningRate=0.5; // 控制背景累积学习的速率 double area_threshold = 30; //区域面积大小阈值 int nThreshold=30; //二值化阈值 CascadeClassifier cascade;//创建级联分类器对象 Mat frame_ori; //每一帧原图像,绝不处理 Mat frame; //每一帧图像处理 Mat gray; //frame转成的灰度图 Mat frame_copy_8U; //copy过来的8U图像 Mat frame_copy; Mat img1; //差分输出 Mat outBinary; //二值图输出 int lastRectHeight=0; //一般都是矩形的高度变化,存储上一个矩形高度 //从指定的文件目录中加载级联分类器 if( !cascade.load( cascadeName ) ) { cerr << "ERROR: Could not load classifier cascade" << endl; return 0; } //从视频读入 VideoCapture capture(input_name); if(capture.isOpened()/*capture*/) //读取文件开关 { //对每一帧做处理 for(;;) { //单帧处理 capture >> frame_ori; if(!frame_ori.empty())//如果捕捉到了 { cout<<"\n\n***************New Start********************"<<endl; //将原图像缩放 //resize(frame_ori,frame,Size(frame_ori.cols * fScale,frame_ori.rows * fScale),0,0,CV_INTER_LINEAR); frame=frame_ori; //送去行人检测 //pedDetection(frame); //frame->gray 单通道灰度图 cvtColor(frame, gray, CV_BGR2GRAY); //进行处理 if (frame_copy.empty()) { //记录第一帧 gray->frame_copy gray.convertTo(frame_copy, CV_32F); } frame_copy.convertTo(frame_copy_8U, CV_8U); //差分 absdiff(frame_copy_8U, gray, img1); //二值化 threshold(img1, outBinary, nThreshold, 255, THRESH_BINARY); accumulateWeighted(gray, frame_copy,learningRate,outBinary); //加一个中值滤波,会减少不少误差 cv::medianBlur(outBinary, outBinary,5); //初始化边界极值点坐标 Point A,C; A.x=0x7fffffff; A.y=0x7fffffff; C.x=0; C.y=0; //轮廓检测 vector<vector<Point>> _contours;//储存所有轮廓 vector<Vec4i>hierarchy; Mat imageROI;; cv::findContours( outBinary, _contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); for(size_t i = 0; i< _contours.size(); ++i) { //遍历所有轮廓 //计算轮廓面积 double contArea = fabs(contourArea(_contours[i])); //去除较小面积的轮廓 if( contArea < area_threshold) continue; //获得外接矩形 Rect r0 = boundingRect(Mat(_contours[i])); //找出最边界的点 findBoundary(r0,A,C); //实时画出每个矩形 rectangle(outBinary,r0,cvScalar(255,255,255),1,8,0); } biggerRect(A,C,frame); cout<<"A.x == "<<A.x<<endl; cout<<"A.y == "<<A.y<<endl; cout<<"C.x == "<<C.x<<endl; cout<<"C.y == "<<C.y<<endl; int a=A.x,b=A.y,c=C.x-A.x,d=C.y-A.y; //矩形框不存在,检测不了 if (c<=0 || d<=0) { //cout<<"弹回去"<<endl; imshow("src", frame); imshow("outBinary", outBinary); cvWaitKey(1); continue; } if(d<lastRectHeight*0.7) hugeRect(A,C,frame); //得到要识别的矩形框 Rect r=Rect(a,b,c,d); //画出一个大的框架 rectangle(outBinary,r,cvScalar(255,255,255),1,8,0); rectangle(frame,r,cvScalar(255,255,255),1,8,0); /*cout<<"r.x "<<r.x<<endl; cout<<"r.y "<<r.y<<endl; cout<<"r.width "<<r.width<<endl; cout<<"r.height "<<r.height<<endl; cout<<"frame.cols "<<frame.cols<<endl; cout<<"frame.rows "<<frame.rows<<endl;*/ //截取frame中的r矩形框大小 Mat src=frame(r); //送去行人检测 //pedDetection(src); //送去人脸检测 detectAndDraw(src,cascade, 1.3); imshow("src", frame); imshow("outBinary", outBinary); lastRectHeight=d; } else { printf(" --(!) No captured frame -- Break!"); break; } //10ms中按任意键进入此if块 if( cvWaitKey( 10 ) >= 0 ) break; } } return 0; } //找一帧中所有矩形的边界四点 void findBoundary(Rect r,Point &a,Point &c) { //a是矩形原点 //c是原点对角线点 //r.x还在a.x的左边 if (r.x < a.x) a.x = r.x; //r.y 还在 a.y 上面 if(r.y < a.y) a.y = r.y; //r.x+r.width 还在c.x的右边 if ((r.x+r.width) > c.x) c.x = r.x+r.width; //(r.y+r.height) 还在 c.y 下面 if((r.y+r.height) > c.y) c.y = r.y+r.height; } void biggerRect(Point &a,Point &c,Mat img) { if (c.x-a.x<0 || c.y-a.y<0) return; a.x -= 30; a.y -= 100; c.x += 30; c.y += 100; if(a.x<0) a.x=0; if(a.y<0) a.y=0; if(c.x>img.cols) c.x=img.cols; if(c.y>img.rows) c.y=img.rows; } void hugeRect(Point &a,Point &c,Mat img) { a.y = 0; c.y = img.rows; } //行人检测 void pedDetection(Mat& image) { // 1. 定义HOG对象 cv::HOGDescriptor hog; // 采用默认参数 64*128 (像素为单位) // 2. 设置SVM分类器 hog.setSVMDetector(cv::HOGDescriptor::getDefaultPeopleDetector()); // 采用已经训练好的行人检测分类器 // 3. 在测试图像上检测行人区域 std::vector<cv::Rect> regions; hog.detectMultiScale(image, regions, 0, cv::Size(8,8), cv::Size(32,32), 1.05, 1); if(regions.size()>0) { printf("是一个人!!!!!!!!!!!!!!!!\n"); printf("是一个人!!!!!!!!!!!!!!!!\n"); printf("是一个人!!!!!!!!!!!!!!!!\n"); printf("是一个人!!!!!!!!!!!!!!!!\n"); printf("是一个人!!!!!!!!!!!!!!!!\n"); printf("是一个人!!!!!!!!!!!!!!!!\n"); } // 显示 for (size_t i = 0; i < regions.size(); i++) { cv::rectangle(image, regions[i], cv::Scalar(0,0,255), 2); } cv::imshow("hog", image); } //人脸检测并画出 void detectAndDraw( Mat& img, CascadeClassifier& cascade, double scale) { int i = 0; double t = 0; vector<Rect> faces; const static Scalar colors[] = { CV_RGB(0,0,255), CV_RGB(0,128,255), CV_RGB(0,255,255), CV_RGB(0,255,0), CV_RGB(255,128,0), CV_RGB(255,255,0), CV_RGB(255,0,0), CV_RGB(255,0,255)} ;//用不同的颜色表示不同的人脸 Mat gray, smallImg( cvRound (img.rows/scale), cvRound(img.cols/scale), CV_8UC1 );//将图片缩小,加快检测速度 cvtColor( img, gray, CV_BGR2GRAY );//因为用的是类haar特征,所以都是基于灰度图像的,这里要转换成灰度图像 resize( gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR );//将尺寸缩小到1/scale,用线性插值 equalizeHist( smallImg, smallImg );//直方图均衡 t = (double)cvGetTickCount();//用来计算算法执行时间 //检测人脸 //detectMultiScale函数中smallImg表示的是要检测的输入图像为smallImg,faces表示检测到的人脸目标序列,1.1表示 //每次图像尺寸减小的比例为1.1,2表示每一个目标至少要被检测到3次才算是真的目标(因为周围的像素和不同的窗口大 //小都可以检测到人脸),CV_HAAR_SCALE_IMAGE表示不是缩放分类器来检测,而是缩放图像,Size(30, 30)为目标的 //最小最大尺寸 cascade.detectMultiScale( smallImg, faces, 1.1, 2, 0 //|CV_HAAR_FIND_BIGGEST_OBJECT //|CV_HAAR_DO_ROUGH_SEARCH |CV_HAAR_SCALE_IMAGE , Size(30, 30) ); t = (double)cvGetTickCount() - t;//相减为算法执行的时间 printf( "detection time = %g ms\n", t/((double)cvGetTickFrequency()*1000.) ); for( vector<Rect>::const_iterator r = faces.begin(); r != faces.end(); r++, i++ ) { Mat smallImgROI; vector<Rect> nestedObjects; Point center; Scalar color = colors[i%8]; 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); circle( img, center, radius, color, 3, 8, 0 ); smallImgROI = smallImg(*r); saveImg(smallImgROI); } } void saveImg(Mat img) { strcpy(countChar,outFolder); strcat(countChar,"\\"); //cout<<countChar<<endl; cout<<"有了有了!!!!!!!!"<<endl; cnt++; itoa(cnt,tmp,10); strcat(tmp,".jpg"); strcat(countChar,tmp); //cout<<countChar<<endl; imwrite(countChar,img); }
改进后:
//opencv2.0风格 //本程序有几个可调值 //1.背景更新 学习率 learningRate //2.去掉小面积阈值 area_threshold #include "cv.h" #include "highgui.h" #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <opencv2/core/core.hpp> #include <iostream> #include <string> #include <cstdio> using namespace std; using namespace cv; //函数声明 void findBoundary(Rect r,Point &a,Point &c);//找到贴合矩形框 void biggerRect(Point &a,Point &c,Mat img); //将矩形框适当放大 void hugeRect(Point &a,Point &c,Mat img); //如果比例缩小太大,直接将矩形巨大化 void pedDetection(Mat& img);//行人检测 void saveImg(Mat img); void detectAndDraw( Mat& img, CascadeClassifier& cascade, double scale); //String cascadeName = "./haarcascades/haarcascade_frontalface_alt2.xml";//人脸的训练数据 String cascadeName = "./cascades.xml";//高密度人头检测训练数据 char input_name[50]; char outFolder[50]; char countChar[10000]; char tmp[50]; int cnt=0; //主函数 int main() { //输入 cout<<"please input the src video :"<<endl; cin>>input_name; cout<<"please input the output folder :"<<endl; cin>>outFolder; //可调参数 //char* input_name = "0012.mp4"; double fScale = 0.5; //缩放倍数 double learningRate=0.5; // 控制背景累积学习的速率 double area_threshold = 30; //区域面积大小阈值 int nThreshold=30; //二值化阈值 CascadeClassifier cascade;//创建级联分类器对象 Mat frame_ori; //每一帧原图像,绝不处理 Mat frame; //每一帧图像处理 Mat gray; //frame转成的灰度图 Mat frame_copy_8U; //copy过来的8U图像 Mat frame_copy; Mat img1; //差分输出 Mat outBinary; //二值图输出 int lastRectHeight=0; //一般都是矩形的高度变化,存储上一个矩形高度 //从指定的文件目录中加载级联分类器 if( !cascade.load( cascadeName ) ) { cerr << "ERROR: Could not load classifier cascade" << endl; return 0; } //从视频读入 VideoCapture capture(input_name); if(capture.isOpened()/*capture*/) //读取文件开关 { //对每一帧做处理 for(;;) { //单帧处理 capture >> frame_ori; if(!frame_ori.empty())//如果捕捉到了 { cout<<"\n\n***************New Start********************"<<endl; //将原图像缩放 //resize(frame_ori,frame,Size(frame_ori.cols * fScale,frame_ori.rows * fScale),0,0,CV_INTER_LINEAR); frame=frame_ori; //送去行人检测 //pedDetection(frame); //frame->gray 单通道灰度图 cvtColor(frame, gray, CV_BGR2GRAY); //进行处理 if (frame_copy.empty()) { //记录第一帧 gray->frame_copy gray.convertTo(frame_copy, CV_32F); } frame_copy.convertTo(frame_copy_8U, CV_8U); //差分 absdiff(frame_copy_8U, gray, img1); //二值化 threshold(img1, outBinary, nThreshold, 255, THRESH_BINARY); accumulateWeighted(gray, frame_copy,learningRate,outBinary); //加一个中值滤波,会减少不少误差 cv::medianBlur(outBinary, outBinary,5); //初始化边界极值点坐标 Point A,C; A.x=0x7fffffff; A.y=0x7fffffff; C.x=0; C.y=0; //轮廓检测 vector<vector<Point>> _contours;//储存所有轮廓 vector<Vec4i>hierarchy; Mat imageROI;; cv::findContours( outBinary, _contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE); for(size_t i = 0; i< _contours.size(); ++i) { //遍历所有轮廓 //计算轮廓面积 double contArea = fabs(contourArea(_contours[i])); //去除较小面积的轮廓 if( contArea < area_threshold) continue; //获得外接矩形 Rect r0 = boundingRect(Mat(_contours[i])); //找出最边界的点 findBoundary(r0,A,C); //实时画出每个矩形 rectangle(outBinary,r0,cvScalar(255,255,255),1,8,0); } biggerRect(A,C,frame); cout<<"A.x == "<<A.x<<endl; cout<<"A.y == "<<A.y<<endl; cout<<"C.x == "<<C.x<<endl; cout<<"C.y == "<<C.y<<endl; int a=A.x,b=A.y,c=C.x-A.x,d=C.y-A.y; //矩形框不存在,检测不了 if (c<=0 || d<=0) { //cout<<"弹回去"<<endl; imshow("src", frame); imshow("outBinary", outBinary); cvWaitKey(1); continue; } if(d<lastRectHeight*0.7) hugeRect(A,C,frame); //得到要识别的矩形框 Rect r=Rect(a,b,c,d); //画出一个大的框架 rectangle(outBinary,r,cvScalar(255,255,255),1,8,0); rectangle(frame,r,cvScalar(255,255,255),1,8,0); /*cout<<"r.x "<<r.x<<endl; cout<<"r.y "<<r.y<<endl; cout<<"r.width "<<r.width<<endl; cout<<"r.height "<<r.height<<endl; cout<<"frame.cols "<<frame.cols<<endl; cout<<"frame.rows "<<frame.rows<<endl;*/ //截取frame中的r矩形框大小 Mat src=frame(r); //送去行人检测 //pedDetection(src); //送去人脸检测 detectAndDraw(src,cascade, 1.0); imshow("src", frame); imshow("outBinary", outBinary); lastRectHeight=d; } else { printf(" --(!) No captured frame -- Break!"); break; } //10ms中按任意键进入此if块 if( cvWaitKey( 10 ) >= 0 ) break; } } return 0; } //找一帧中所有矩形的边界四点 void findBoundary(Rect r,Point &a,Point &c) { //a是矩形原点 //c是原点对角线点 //r.x还在a.x的左边 if (r.x < a.x) a.x = r.x; //r.y 还在 a.y 上面 if(r.y < a.y) a.y = r.y; //r.x+r.width 还在c.x的右边 if ((r.x+r.width) > c.x) c.x = r.x+r.width; //(r.y+r.height) 还在 c.y 下面 if((r.y+r.height) > c.y) c.y = r.y+r.height; } void biggerRect(Point &a,Point &c,Mat img) { if (c.x-a.x<0 || c.y-a.y<0) return; a.x -= 30; a.y -= 100; c.x += 30; c.y += 100; if(a.x<0) a.x=0; if(a.y<0) a.y=0; if(c.x>img.cols) c.x=img.cols; if(c.y>img.rows) c.y=img.rows; } void hugeRect(Point &a,Point &c,Mat img) { a.y = 0; c.y = img.rows; } //行人检测 void pedDetection(Mat& image) { // 1. 定义HOG对象 cv::HOGDescriptor hog; // 采用默认参数 64*128 (像素为单位) // 2. 设置SVM分类器 hog.setSVMDetector(cv::HOGDescriptor::getDefaultPeopleDetector()); // 采用已经训练好的行人检测分类器 // 3. 在测试图像上检测行人区域 std::vector<cv::Rect> regions; hog.detectMultiScale(image, regions, 0, cv::Size(8,8), cv::Size(32,32), 1.05, 1); if(regions.size()>0) { printf("是一个人!!!!!!!!!!!!!!!!\n"); printf("是一个人!!!!!!!!!!!!!!!!\n"); printf("是一个人!!!!!!!!!!!!!!!!\n"); printf("是一个人!!!!!!!!!!!!!!!!\n"); printf("是一个人!!!!!!!!!!!!!!!!\n"); printf("是一个人!!!!!!!!!!!!!!!!\n"); } // 显示 for (size_t i = 0; i < regions.size(); i++) { cv::rectangle(image, regions[i], cv::Scalar(0,0,255), 2); } cv::imshow("hog", image); } //人脸检测并画出 void detectAndDraw( Mat& img, CascadeClassifier& cascade, double scale) { Mat img_ori=img.clone(); int i = 0; double t = 0; vector<Rect> faces; const static Scalar colors[] = { CV_RGB(0,0,255), CV_RGB(0,128,255), CV_RGB(0,255,255), CV_RGB(0,255,0), CV_RGB(255,128,0), CV_RGB(255,255,0), CV_RGB(255,0,0), CV_RGB(255,0,255)} ;//用不同的颜色表示不同的人脸 Mat gray, smallImg( cvRound (img.rows/scale), cvRound(img.cols/scale), CV_8UC1 );//将图片缩小,加快检测速度 cvtColor( img, gray, CV_BGR2GRAY );//因为用的是类haar特征,所以都是基于灰度图像的,这里要转换成灰度图像 resize( gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR );//将尺寸缩小到1/scale,用线性插值 equalizeHist( smallImg, smallImg );//直方图均衡 t = (double)cvGetTickCount();//用来计算算法执行时间 //检测人脸 //detectMultiScale函数中smallImg表示的是要检测的输入图像为smallImg,faces表示检测到的人脸目标序列,1.1表示 //每次图像尺寸减小的比例为1.1,2表示每一个目标至少要被检测到3次才算是真的目标(因为周围的像素和不同的窗口大 //小都可以检测到人脸),CV_HAAR_SCALE_IMAGE表示不是缩放分类器来检测,而是缩放图像,Size(30, 30)为目标的 //最小最大尺寸 cascade.detectMultiScale( smallImg, faces, 1.1, 2, 0 //|CV_HAAR_FIND_BIGGEST_OBJECT //|CV_HAAR_DO_ROUGH_SEARCH |CV_HAAR_SCALE_IMAGE , Size(30, 30) ); t = (double)cvGetTickCount() - t;//相减为算法执行的时间 printf( "detection time = %g ms\n", t/((double)cvGetTickFrequency()*1000.) ); for( vector<Rect>::const_iterator r = faces.begin(); r != faces.end(); r++, i++ ) { Mat smallImgROI; vector<Rect> nestedObjects; Point center; Scalar color = colors[i%8]; 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); circle( img, center, radius, color, 3, 8, 0 ); smallImgROI = img_ori(*r); saveImg(smallImgROI); } } void saveImg(Mat img) { strcpy(countChar,outFolder); strcat(countChar,"\\"); //cout<<countChar<<endl; cout<<"有了有了!!!!!!!!"<<endl; cnt++; itoa(cnt,tmp,10); strcat(tmp,".jpg"); strcat(countChar,tmp); //cout<<countChar<<endl; imwrite(countChar,img); }
最后更新:2017-04-03 05:40:06