嘗試視頻處理
上一次就是簡單的跑了下邊緣檢測函卒,在上次的代碼中全部都是使用的OpenCV原生API戏溺,最后的數(shù)據(jù)也說明了OpenCL是有用的。
這一次嘗試人臉識別拦止,同樣有是CPU和OpenCL測試县遣。
但是這一次無法像上次那樣打印出全部數(shù)據(jù)然后做總結(jié),只能大體上根據(jù)FPS和硬件使用率來判斷。
首先放上代碼:
facedetect.cpp
#include <iostream>
#include "opencv2/objdetect.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
using namespace std;
using namespace cv;
void detect_cpu(cv::Mat frame);
void detect_opencl(cv::Mat frame); // Transparent API
CascadeClassifier face_cascade;
CascadeClassifier eyes_cascade;
int main( int argc, const char** argv )
{
// read xml files
string face_cascade_file = haarcascade_frontalface_alt.xml的路徑;
string eye_cascade_file = haarcascade_eye_tree_eyeglasses.xml的路徑;
face_cascade.load(face_cascade_file);
if( !face_cascade.load(face_cascade_file) ){
cerr << "Error loading face cascade\n";
return -1;
}
eyes_cascade.load(eye_cascade_file);
if( !eyes_cascade.load(eye_cascade_file) ){
cerr << "Error loading eyes cascade\n";
return -1;
}
VideoCapture capture;
capture.open(0); // read frame from camera 0
if (!capture.isOpened()){
cerr << "Error opening video capture\n";
return -1;
}
while (1){
Mat frame;
capture >> frame;
detect_cpu(frame);
// detect_opencl(frame);
char key = (char)waitKey(1);
if(key == 27 || key == 'q' || key == 'Q')break;
}
return 0;
}
void detect_opencl(cv::Mat frame){
double start = (double)getTickCount();
UMat Uframe;
frame.copyTo(Uframe); // copy Mat frame -> UMat Uframe
UMat Uframe_gray;
cvtColor( Uframe, Uframe_gray, COLOR_BGR2GRAY );
equalizeHist( Uframe_gray, Uframe_gray );
//-- Detect faces
std::vector<Rect> faces;
face_cascade.detectMultiScale( Uframe_gray, faces );
for ( size_t i = 0; i < faces.size(); i++ ){
Point center( faces[i].x + faces[i].width/2, faces[i].y + faces[i].height/2 );
ellipse( Uframe, center, Size( faces[i].width/2, faces[i].height/2 ), 0, 0, 360, Scalar( 255, 0, 255 ), 4 );
UMat faceROI = Uframe_gray( faces[i] );
//-- In each face, detect eyes
std::vector<Rect> eyes;
eyes_cascade.detectMultiScale( faceROI, eyes );
for ( size_t j = 0; j < eyes.size(); j++ ){
Point eye_center( faces[i].x + eyes[j].x + eyes[j].width/2, faces[i].y + eyes[j].y + eyes[j].height/2 );
int radius = cvRound( (eyes[j].width + eyes[j].height)*0.25 );
circle( Uframe, eye_center, radius, Scalar( 255, 0, 0 ), 4 );
}
}
double time_consume = ((double)getTickCount() - start) / getTickFrequency();
double fps = 1.0 / time_consume;
char str[50];
sprintf(str,"Resolution: %dx%d and FPS:%.2f",Uframe.cols,Uframe.rows,fps);
putText(Uframe,str,Point(0,30),FONT_HERSHEY_TRIPLEX,1,Scalar(0,0,255),2,8); //show resolution and fps
imshow( "Process with OpenCL", Uframe ); //show Uframe
}
void detect_cpu(cv::Mat frame){
double start = (double)getTickCount();
Mat frame_gray;
cvtColor( frame, frame_gray, COLOR_BGR2GRAY );
equalizeHist( frame_gray, frame_gray );
//-- Detect faces
std::vector<Rect> faces;
face_cascade.detectMultiScale( frame_gray, faces );
for ( size_t i = 0; i < faces.size(); i++ )
{
Point center( faces[i].x + faces[i].width/2, faces[i].y + faces[i].height/2 );
ellipse( frame, center, Size( faces[i].width/2, faces[i].height/2 ), 0, 0, 360, Scalar( 255, 0, 255 ), 4 );
Mat faceROI = frame_gray( faces[i] );
//-- In each face, detect eyes
std::vector<Rect> eyes;
eyes_cascade.detectMultiScale( faceROI, eyes );
for ( size_t j = 0; j < eyes.size(); j++ )
{
Point eye_center( faces[i].x + eyes[j].x + eyes[j].width/2, faces[i].y + eyes[j].y + eyes[j].height/2 );
int radius = cvRound( (eyes[j].width + eyes[j].height)*0.25 );
circle( frame, eye_center, radius, Scalar( 255, 0, 0 ), 4 );
}
}
double time_consume = ((double)getTickCount() - start) / getTickFrequency();
double fps = 1.0 / time_consume;
char str[50];
sprintf(str,"Resolution: %dx%d and FPS:%.2f",frame.cols,frame.rows,fps); //show resolution and fps
putText(frame,str,Point(0,30),FONT_HERSHEY_TRIPLEX,1,Scalar(0,0,255),2,8);
imshow("Process with CPU",frame);
}
在xml
文件出填上正確的的文件絕對路徑艺玲,參考編譯命令如下
clang++ -std=c++11 facedetect.cpp -o facedetect `pkg-config --cflags --libs opencv4`
運行結(jié)果:
可以看到括蝠,幀數(shù)很低,基本上就像是放映PPT饭聚,而且CPU占用飚滿。
要使用OpenCL運行搁拙,請注釋掉40行的detect_cpu(frame)
函數(shù)秒梳,然后取消掉下一行的detect_opencl(frame)
,重新編譯運行箕速。
這里問題就來了:OpenCL的運行結(jié)果酪碘,和CPU是一樣的。(就連硬件占用率也一樣盐茎,參考上圖)
這就不免讓人感到很疑惑了兴垦,OpenCV官方說明是絕大多數(shù)的API是可以直接用UMat
的,那么我代碼里面字柠,與OpenCV相關(guān)的函數(shù)就應(yīng)該都沒有問題探越,于是抱著試試的心態(tài),我做了些更改:
注釋掉以下代碼窑业,僅做最基本的顏色空間轉(zhuǎn)換和直方圖均量化:
// std::vector<Rect> faces;
// face_cascade.detectMultiScale( Uframe_gray, faces );
// for ( size_t i = 0; i < faces.size(); i++ ){
// Point center( faces[i].x + faces[i].width/2, faces[i].y + faces[i].height/2 );
// ellipse( Uframe, center, Size( faces[i].width/2, faces[i].height/2 ), 0, 0, 360, Scalar( 255, 0, 255 ), 4 );
// UMat faceROI = Uframe_gray( faces[i] );
// //-- In each face, detect eyes
// std::vector<Rect> eyes;
// eyes_cascade.detectMultiScale( faceROI, eyes );
// for ( size_t j = 0; j < eyes.size(); j++ ){
// Point eye_center( faces[i].x + eyes[j].x + eyes[j].width/2, faces[i].y + eyes[j].y + eyes[j].height/2 );
// int radius = cvRound( (eyes[j].width + eyes[j].height)*0.25 );
// circle( Uframe, eye_center, radius, Scalar( 255, 0, 0 ), 4 );
// }
// }
然后再重新編譯钦幔,查看運行結(jié)果:
這樣一看,CPU使用率下來了常柄,然后是有GPU使用率的鲤氢,雖然使用率很低。最后就是FPS西潘,有點虛飄(攝像頭每秒能捕捉的幀數(shù)都沒有這么高卷玉,但是至少明顯的延遲是沒有的)
原因分析
忽略那虛飄的FPS,考慮實際的問題:OpenCV中人臉檢測使用的是 detectMultiScale
函數(shù)喷市。它可以檢測出圖片中所有的人臉相种,并使用std::vector
保存各個人臉的坐標(biāo)、大小东抹,函數(shù)由分類器對象調(diào)用蚂子。
首先,我們要定義保存臉部和眼部的vector
缭黔,然后使用detectMultiScale
函數(shù)將識別到的臉部和眼部信息保存至我們定義的std::vector<Rect> faces
和std::vector<Rect> eyes
中食茎,vector
中有了點(Point
)的信息,那么我們便可以使用循環(huán)遍歷后繪制橢圓(ellipse
)和圓形(circle
)馏谨。
1.問題就出在detectMultiScale
函數(shù)上别渔,執(zhí)行這個函數(shù)的時間是最長的。
2.具體到變量就在std::vector faces
上:OpenCV官網(wǎng)的說明是,當(dāng)有不滿足T-API使用需求的函數(shù)或變量哎媚,UMat
就會變成普通的Mat
喇伯;那么很顯然,我們的vector
并沒有放入OpenCL設(shè)備中去計算拨与。
所以去掉了識別處理的這部分稻据,會發(fā)現(xiàn)其實GPU有占用率(雖然很小)买喧。
后續(xù)解決辦法
挖坑嘛捻悯,固然是有的,至于這個坑能不能填起來淤毛,我就不確定了今缚。
detectMultiScale
這個函數(shù)是不支持T-API的。故沒有較好的解決辦法低淡。除非是了解算法原理后姓言,重新寫一個OpenCL版本的函數(shù)。