【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