OpenCV T-API的测试(二)

尝试视频处理


上一次就是简单的跑了下边缘检测,在上次的代码中全部都是使用的OpenCV原生API,最后的数据也说明了OpenCL是有用的。

这一次尝试人脸识别,同样有是CPU和OpenCL测试。

但是这一次无法像上次那样打印出全部数据然后做总结,只能大体上根据FPS和硬件使用率来判断。

首先放上代码:
facedetect.cpp

#include 
#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 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 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 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 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`

运行结果:


CPU运行结果

可以看到,帧数很低,基本上就像是放映PPT,而且CPU占用飚满。

要使用OpenCL运行,请注释掉40行的detect_cpu(frame)函数,然后取消掉下一行的detect_opencl(frame),重新编译运行。

这里问题就来了:OpenCL的运行结果,和CPU是一样的。(就连硬件占用率也一样,参考上图)

这就不免让人感到很疑惑了,OpenCV官方说明是绝大多数的API是可以直接用UMat的,那么我代码里面,与OpenCV相关的函数就应该都没有问题,于是抱着试试的心态,我做了些更改:

注释掉以下代码,仅做最基本的颜色空间转换和直方图均量化:

// std::vector 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 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 );
    //     }
    // }

然后再重新编译,查看运行结果:


OpenCL基本处理(没有识别的部分)

这样一看,CPU使用率下来了,然后是有GPU使用率的,虽然使用率很低。最后就是FPS,有点虚飘(摄像头每秒能捕捉的帧数都没有这么高,但是至少明显的延迟是没有的)

原因分析


忽略那虚飘的FPS,考虑实际的问题:OpenCV中人脸检测使用的是 detectMultiScale函数。它可以检测出图片中所有的人脸,并使用std::vector保存各个人脸的坐标、大小,函数由分类器对象调用。

首先,我们要定义保存脸部和眼部的vector,然后使用detectMultiScale函数将识别到的脸部和眼部信息保存至我们定义的std::vector facesstd::vector eyes中,vector中有了点(Point)的信息,那么我们便可以使用循环遍历后绘制椭圆(ellipse)和圆形(circle)。

1.问题就出在detectMultiScale函数上,执行这个函数的时间是最长的。
2.具体到变量就在std::vector faces上:OpenCV官网的说明是,当有不满足T-API使用需求的函数或变量,UMat就会变成普通的Mat;那么很显然,我们的vector并没有放入OpenCL设备中去计算。

所以去掉了识别处理的这部分,会发现其实GPU有占用率(虽然很小)。

后续解决办法


挖坑嘛,固然是有的,至于这个坑能不能填起来,我就不确定了。
detectMultiScale这个函数是不支持T-API的。故没有较好的解决办法。除非是了解算法原理后,重新写一个OpenCL版本的函数。

你可能感兴趣的:(OpenCV T-API的测试(二))