使用OpenCV進行人臉檢測(Viola-Jones人臉檢測方法)
擴充套件閱讀:
參考文獻:Paul Viola, Michael J. Jones. Robust Real-Time Face Detection[J]. International Journal of Computer Vision,2004,57(2):137-154.
優點:
1.積分影象(integral image)快速計算Haar-like特徵。
2.利用Adaboost演算法進行特徵選擇和分類器訓練,把弱分類器組合成強分類器。
3.採用分類器級聯提高效率。
檢測步驟:
Step1 載入分類器
讀入xml格式的模型檔案,其中haarcascade_frontalface_atl.xml和haarcascade_frontalface_atl2.xml
Step2 讀入待檢測影象(或者視訊解碼後的影象)
Step3 呼叫用函式檢測人臉。
程式碼1:
#include "opencv2/core/core.hpp" #include "opencv2/objdetect/objdetect.hpp" #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> #include <stdio.h> using namespace std; using namespace cv; string face_cascade_name = "haarcascade_frontalface_alt.xml"; //該檔案存在於OpenCV安裝目錄下的\sources\data\haarcascades內,需要將該xml檔案複製到當前工程目錄下 CascadeClassifier face_cascade; void detectAndDisplay( Mat frame ); int main( int argc, char** argv ){ Mat image; image =imread("face.jpg",1); //當前工程的image目錄下的mm.jpg檔案,注意目錄符號 if( !face_cascade.load( face_cascade_name ) ){ printf("級聯分類器錯誤,可能未找到檔案,拷貝該檔案到工程目錄下!\n"); return -1; } detectAndDisplay(image); //呼叫人臉檢測函式 waitKey(0); //暫停顯示一下。 } void detectAndDisplay( Mat face ){ std::vector<Rect> faces; Mat face_gray; cvtColor( face, face_gray, CV_BGR2GRAY ); //rgb型別轉換為灰度型別 equalizeHist( face_gray, face_gray ); //直方圖均衡化 face_cascade.detectMultiScale( face_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(1, 1) ); for( int i = 0; i < faces.size(); i++ ){ Point center( faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5 ); ellipse( face, center, Size( faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 0), 2,7, 0 ); } imshow("人臉識別", face ); }
程式碼1效果:
程式碼2:
#include "cv.h" #include "highgui.h" #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> #include <math.h> #include <float.h> #include <limits.h> #include <time.h> #include <ctype.h> static CvMemStorage* storage = 0; static CvHaarClassifierCascade* cascade = 0; void detect_and_draw( IplImage* image ); const char* cascade_name = "haarcascade_frontalface_alt.xml"; /* "haarcascade_profileface.xml";*/ int main( int argc, char** argv ) { cascade_name = "haarcascade_frontalface_alt2.xml"; cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 ); if( !cascade ) { fprintf( stderr, "ERROR: Could not load classifier cascade\n" ); return -1; } storage = cvCreateMemStorage(0); cvNamedWindow( "result", 1 ); const char* filename = "face.jpg"; IplImage* image = cvLoadImage( filename, 1 ); if( image ) { detect_and_draw( image ); cvWaitKey(0); cvReleaseImage( &image ); } cvDestroyWindow("result"); return 0; } void detect_and_draw(IplImage* img ) { double scale=1.2; static CvScalar colors[] = { {{0,0,255}},{{0,128,255}},{{0,255,255}},{{0,255,0}}, {{255,128,0}},{{255,255,0}},{{255,0,0}},{{255,0,255}} };//Just some pretty colors to draw with //Image Preparation // IplImage* gray = cvCreateImage(cvSize(img->width,img->height),8,1); IplImage* small_img=cvCreateImage(cvSize(cvRound(img->width/scale),cvRound(img->height/scale)),8,1); cvCvtColor(img,gray, CV_BGR2GRAY); cvResize(gray, small_img, CV_INTER_LINEAR); cvEqualizeHist(small_img,small_img); //直方圖均衡 //Detect objects if any // cvClearMemStorage(storage); double t = (double)cvGetTickCount(); CvSeq* objects = cvHaarDetectObjects(small_img, cascade, storage, 1.1, 2, 0/*CV_HAAR_DO_CANNY_PRUNING*/, cvSize(30,30)); t = (double)cvGetTickCount() - t; printf( "detection time = %gms\n", t/((double)cvGetTickFrequency()*1000.) ); //Loop through found objects and draw boxes around them for(int i=0;i<(objects? objects->total:0);++i) { CvRect* r=(CvRect*)cvGetSeqElem(objects,i); cvRectangle(img, cvPoint(r->x*scale,r->y*scale), cvPoint((r->x+r->width)*scale,(r->y+r->height)*scale), colors[i%8]); } for( int i = 0; i < (objects? objects->total : 0); i++ ) { CvRect* r = (CvRect*)cvGetSeqElem( objects, i ); CvPoint center; 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); cvCircle( img, center, radius, colors[i%8], 3, 8, 0 ); } cvShowImage( "result", img ); cvReleaseImage(&gray); cvReleaseImage(&small_img); }
程式碼2效果
從效果看,程式碼1的效果較好。原因使用的函式不同,內部的實現和引數也有區別。請根據實際情況子集選擇。
程式碼3,OpenCV 原版附帶眼睛檢測
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <cctype>
#include <iostream>
#include <iterator>
#include <stdio.h>
using namespace std;
using namespace cv;
static void help()
{
cout << "\nThis program demonstrates the cascade recognizer. Now you can use Haar or LBP features.\n"
"This classifier can recognize many kinds of rigid objects, once the appropriate classifier is trained.\n"
"It's most known use is for faces.\n"
"Usage:\n"
"./facedetect [--cascade=<cascade_path> this is the primary trained classifier such as frontal face]\n"
" [--nested-cascade[=nested_cascade_path this an optional secondary classifier such as eyes]]\n"
" [--scale=<image scale greater or equal to 1, try 1.3 for example>]\n"
" [--try-flip]\n"
" [filename|camera_index]\n\n"
"see facedetect.cmd for one call:\n"
"./facedetect --cascade=\"../../data/haarcascades/haarcascade_frontalface_alt.xml\" --nested-cascade=\"../../data/haarcascades/haarcascade_eye.xml\" --scale=1.3\n\n"
"During execution:\n\tHit any key to quit.\n"
"\tUsing OpenCV version " << CV_VERSION << "\n" << endl;
}
void detectAndDraw( Mat& img, CascadeClassifier& cascade,
CascadeClassifier& nestedCascade,
double scale, bool tryflip );
string cascadeName = "../../data/haarcascades/haarcascade_frontalface_alt.xml";
string nestedCascadeName = "../../data/haarcascades/haarcascade_eye_tree_eyeglasses.xml";
int main( int argc, const char** argv )
{
CvCapture* capture = 0;
Mat frame, frameCopy, image;
const string scaleOpt = "--scale=";
size_t scaleOptLen = scaleOpt.length();
const string cascadeOpt = "--cascade=";
size_t cascadeOptLen = cascadeOpt.length();
const string nestedCascadeOpt = "--nested-cascade";
size_t nestedCascadeOptLen = nestedCascadeOpt.length();
const string tryFlipOpt = "--try-flip";
size_t tryFlipOptLen = tryFlipOpt.length();
string inputName;
bool tryflip = false;
help();
CascadeClassifier cascade, nestedCascade;
double scale = 1;
for( int i = 1; i < argc; i++ )
{
cout << "Processing " << i << " " << argv[i] << endl;
if( cascadeOpt.compare( 0, cascadeOptLen, argv[i], cascadeOptLen ) == 0 )
{
cascadeName.assign( argv[i] + cascadeOptLen );
cout << " from which we have cascadeName= " << cascadeName << endl;
}
else if( nestedCascadeOpt.compare( 0, nestedCascadeOptLen, argv[i], nestedCascadeOptLen ) == 0 )
{
if( argv[i][nestedCascadeOpt.length()] == '=' )
nestedCascadeName.assign( argv[i] + nestedCascadeOpt.length() + 1 );
if( !nestedCascade.load( nestedCascadeName ) )
cerr << "WARNING: Could not load classifier cascade for nested objects" << endl;
}
else if( scaleOpt.compare( 0, scaleOptLen, argv[i], scaleOptLen ) == 0 )
{
if( !sscanf( argv[i] + scaleOpt.length(), "%lf", &scale ) || scale < 1 )
scale = 1;
cout << " from which we read scale = " << scale << endl;
}
else if( tryFlipOpt.compare( 0, tryFlipOptLen, argv[i], tryFlipOptLen ) == 0 )
{
tryflip = true;
cout << " will try to flip image horizontally to detect assymetric objects\n";
}
else if( argv[i][0] == '-' )
{
cerr << "WARNING: Unknown option %s" << argv[i] << endl;
}
else
inputName.assign( argv[i] );
}
if( !cascade.load( cascadeName ) )
{
cerr << "ERROR: Could not load classifier cascade" << endl;
help();
return -1;
}
if( inputName.empty() || (isdigit(inputName.c_str()[0]) && inputName.c_str()[1] == '\0') )
{
capture = cvCaptureFromCAM( inputName.empty() ? 0 : inputName.c_str()[0] - '0' );
int c = inputName.empty() ? 0 : inputName.c_str()[0] - '0' ;
if(!capture) cout << "Capture from CAM " << c << " didn't work" << endl;
}
else if( inputName.size() )
{
image = imread( inputName, 1 );
if( image.empty() )
{
capture = cvCaptureFromAVI( inputName.c_str() );
if(!capture) cout << "Capture from AVI didn't work" << endl;
}
}
else
{
image = imread( "lena.jpg", 1 );
if(image.empty()) cout << "Couldn't read lena.jpg" << endl;
}
cvNamedWindow( "result", 1 );
if( capture )
{
cout << "In capture ..." << endl;
for(;;)
{
IplImage* iplImg = cvQueryFrame( capture );
frame = iplImg;
if( frame.empty() )
break;
if( iplImg->origin == IPL_ORIGIN_TL )
frame.copyTo( frameCopy );
else
flip( frame, frameCopy, 0 );
detectAndDraw( frameCopy, cascade, nestedCascade, scale, tryflip );
if( waitKey( 10 ) >= 0 )
goto _cleanup_;
}
waitKey(0);
_cleanup_:
cvReleaseCapture( &capture );
}
else
{
cout << "In image read" << endl;
if( !image.empty() )
{
detectAndDraw( image, cascade, nestedCascade, scale, tryflip );
waitKey(0);
}
else if( !inputName.empty() )
{
/* assume it is a text file containing the
list of the image filenames to be processed - one per line */
FILE* f = fopen( inputName.c_str(), "rt" );
if( f )
{
char buf[1000+1];
while( fgets( buf, 1000, f ) )
{
int len = (int)strlen(buf), c;
while( len > 0 && isspace(buf[len-1]) )
len--;
buf[len] = '\0';
cout << "file " << buf << endl;
image = imread( buf, 1 );
if( !image.empty() )
{
detectAndDraw( image, cascade, nestedCascade, scale, tryflip );
c = waitKey(0);
if( c == 27 || c == 'q' || c == 'Q' )
break;
}
else
{
cerr << "Aw snap, couldn't read image " << buf << endl;
}
}
fclose(f);
}
}
}
cvDestroyWindow("result");
return 0;
}
void detectAndDraw( Mat& img, CascadeClassifier& cascade,
CascadeClassifier& nestedCascade,
double scale, bool tryflip )
{
int i = 0;
double t = 0;
vector<Rect> faces, faces2;
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 );
resize( gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR );
equalizeHist( smallImg, smallImg );
t = (double)cvGetTickCount();
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) );
if( tryflip )
{
flip(smallImg, smallImg, 1);
cascade.detectMultiScale( smallImg, faces2,
1.1, 2, 0
//|CV_HAAR_FIND_BIGGEST_OBJECT
//|CV_HAAR_DO_ROUGH_SEARCH
|CV_HAAR_SCALE_IMAGE
,
Size(30, 30) );
for( vector<Rect>::const_iterator r = faces2.begin(); r != faces2.end(); r++ )
{
faces.push_back(Rect(smallImg.cols - r->x - r->width, r->y, r->width, r->height));
}
}
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;
double aspect_ratio = (double)r->width/r->height;
if( 0.75 < aspect_ratio && aspect_ratio < 1.3 )
{
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 );
}
else
rectangle( img, cvPoint(cvRound(r->x*scale), cvRound(r->y*scale)),
cvPoint(cvRound((r->x + r->width-1)*scale), cvRound((r->y + r->height-1)*scale)),
color, 3, 8, 0);
if( nestedCascade.empty() )
continue;
smallImgROI = smallImg(*r);
nestedCascade.detectMultiScale( smallImgROI, nestedObjects,
1.1, 2, 0
//|CV_HAAR_FIND_BIGGEST_OBJECT
//|CV_HAAR_DO_ROUGH_SEARCH
//|CV_HAAR_DO_CANNY_PRUNING
|CV_HAAR_SCALE_IMAGE
,
Size(30, 30) );
for( vector<Rect>::const_iterator nr = nestedObjects.begin(); nr != nestedObjects.end(); nr++ )
{
center.x = cvRound((r->x + nr->x + nr->width*0.5)*scale);
center.y = cvRound((r->y + nr->y + nr->height*0.5)*scale);
radius = cvRound((nr->width + nr->height)*0.25*scale);
circle( img, center, radius, color, 3, 8, 0 );
}
}
cv::imshow( "result", img );
cv::waitKey(0);
}
相關推薦
使用OpenCV進行人臉檢測(Viola-Jones人臉檢測方法)
擴充套件閱讀: 參考文獻:Paul Viola, Michael J. Jones. Robust Real-Time Face Detection[J]. International Journal of Computer Vision,2004,57(2):13
12.QT + OpenCV打包成應用(以及QT圖示問題詳細) --- OpenCV從零開始到影象(人臉 + 物體)識別系列
本文作者:小嗷 微信公眾號:aoxiaoji 關鍵詞:QT + OpenCV打包成應用(接著第11篇) QT開發的程式釋出的時候經常採用兩種方式: 靜態編譯,可生成單一的可執行檔案。 動態編譯,需同時附上需要的dll檔案。 不
Android FaceDetector實現人臉檢測,人臉追蹤(框出人臉)(MVP模式)
一 主要流程: 1.通過FaceDetector類來檢測人臉,返回獲取到的人臉資訊,以及人臉的座標,通過人臉座標可以做人臉追蹤的操作。 2.通過兩個surfaceview,一個surfaceview用來做相機的預覽,另外一個surfaceview附著在相機預覽surface
人工智慧 - 人臉合成 (騰訊AI開放平臺)
如果是從事微信開發的同事我想以前應該見過火爆朋友圈的軍裝照這個小程式吧,感覺將自己的人臉P無縫P上去感覺高大上。那麼這個是怎麼實現的呢? 我也不曉得具體怎麼實現的,我只需要知道我能通過第三方平臺實現這個功能就行了。在此,感謝各位前輩先驅們將相應的技術介面公開免費給我們使用,正因
OpenCV探索之路(六):邊緣檢測(canny、sobel、laplacian)
邊緣檢測的一般步驟: 濾波——消除噪聲 增強——使邊界輪廓更加明顯 檢測——選出邊緣點 Canny演算法 Canny邊緣檢測演算法被很多人推崇為當今最優秀的邊緣檢測演算法,所以我們第一個就介紹他。 opencv中提供了Canny函式。 #include<
C# 利用 OpenCV 進行視訊捕獲 (筆記)
簡介 這個專案是關於如何從網路攝像頭或者視訊檔案(*.AVI)中捕獲視訊的,這個專案是用C#和OPENCV編寫的。 這將有助於那些喜歡C#和OpenCV環境的人。這個程式完全基於Visual Studio 2010 version C#.NET環境。這個程式展示了怎樣用C#.NET環境的Visual Stu
人臉識別(VS2015+opencv3.2的配置)
初學人臉識別,感覺安裝也是一個很大的麻煩。 寫在這裡記錄一下吧 一:先安裝好我們需要的軟體 首先安裝Vs2015,在官網或者csdn搜一下應該找的到。 安裝步驟沒有太多講究。 點選exe檔案,我選擇的是預設安裝,你也可以自定義安裝。 然後在opencv
3 用python進行OpenCV實戰之畫圖(直線,矩形,圓形)
前言 在上一節我們通過使用NumPy的陣列分割成功的在我們的影象上畫了一個綠色的方塊,但是如果我們想畫一個單一的線條或者圓圈該怎麼辦呢?NumPy沒有提供相關的功能,但是OpenCV提供了相關的函式,在本節就將為大家介紹三個基本的OpenCV畫圖方法:
使用PCA實現人臉變換(從一個人臉漸變為另一個)(一)
原理 PCA方式用於提取相似樣本的共有特徵,將樣本投影到特徵向量構成的特徵空間可以使用較少的量表示原本複雜的量。在此的基礎上,使用投影值可以重構出樣本。若特徵空間提取優良的話,重構出來的樣本與原始樣本將非常相似。因此可以通過重構的方式來實現人臉的變換。
ios開發之人臉識別(給眼睛打上馬賽克)
#import "ViewController.h" @interfaceViewController () @end @implementationViewController - (v
目標檢測之四,使用multinet的KittiBox部分進行車輛檢測 (demo,train,evalute)
目標檢測之四,使用multinet的KittiBox部分進行車輛檢測(demo,train,evalute) 使用KittiBox進行車輛檢測,訓練環境和配置:Ubuntu16.04,python3.5,TensorFlow1.4,i76700K+雙GT
微信小程式-人臉識別(2)實現人臉識別功能
上一篇的部落格已經將圖片存入到百度雲與自己的伺服器阿里雲上面了,接下來就是在寫一個頁面,是刷臉頁面,通過這個頁面你將自己的臉拍照,傳入到自己的伺服器上,去與存入百度雲上面的照片進行對比。下面是程式碼。前臺程式碼:<camera device-position="fron
OpenCV計算機視覺學習(13)——影象特徵點檢測(Harris角點檢測,sift演算法)
如果需要處理的原圖及程式碼,請移步小編的GitHub地址 傳送門:請點選我 如果點選有誤:https://github.com/LeBron-Jian/ComputerVisionPractice 前言 特徵點檢測廣泛應用到目標匹配,目標跟蹤,三維重建等應用中,在進行目標建模時會對影象進行目標特徵
OpenCV---直方圖的應用(均衡化和圖像比較)
當我 全局 for 函數 灰度 row ros 應用 部分 一:全局直方圖均衡化(對比度增強)equalizeHist def equalHist_demo(image): #OpenCV直方圖均衡化都是基於灰度圖像 gray = cv.cvtColor(ima
OpenCV 計算執行時間(us,ms,s)
1. cvGetTickCount()和cvGetTickFrequency()計時,得到的單位是us級的統計時間: double start = static_cast<double>(cvGetTickCount()); double time = ((double)cvGe
OpenCV之基本繪圖(在Mat和Bitmap上)
在之前的部落格中,關於通過Canvas配合Paint繪圖儲存在Bitmap上,最後展示在ImageView上,我還專門做了一個畫圖釋義的Demo,具體請轉至我用2D繪圖API畫了一隻好醜的雞,Canvas配合MotionEvent實現畫板功能檢
Visual Studio進行Python程式設計(新增自定義Python直譯器)
這篇部落格主要介紹一下在Visual Studio下安裝python開發環境,在vs下配置python開發環境的部落格不少,但是都介紹的是使用vs提供的預設的python直譯器,很少有使用自己安裝的直譯器的文章,因此今天就稍作介紹 安裝Visual Studio 安裝vi
學生類,含學生姓名與成績,用友元函式訪問私有成員,對兩個物件的成績進行比較。(2018.9.19 c++作業)
定義兩個物件,與一個友元函式(使用c++中引用傳遞的方式,實現引數的傳遞) #include using namespace std; class student { private: char name[20]; float grade; public: s
N76E003之ADC電量檢測(程式、分析、電路)
模數轉換器即A/D轉換器,或簡稱ADC,通常是指一個將模擬訊號轉變為數字訊號的電子元件。 先來看看N76E003 ADC工作方式 再看下相關暫存器,方便理解上圖 現在我們只需要配置好以上幾個暫存器,就可以開始使用ADC了,為了保證程式的及時性,我們採取A
括號匹配檢測(難度:半顆星)
問題描述: 輸入一個字串,字串中只包含兩種字元:’(‘和’)’,判斷字串的括號是否匹配,如果匹配輸出YES,否則輸出NO。 例如: (())是匹配的 ()))是不匹配的 參考程式碼: #define _CRT_SECURE_NO_WARNINGS #include <