閱讀916 返回首頁    go 魔獸


【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

  上一篇:go 創業如此艱難,該何去何從?
  下一篇:go 【原】訓練自己haar-like特征分類器並識別物體(1)