916
魔獸
【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