美文网首页OpenCL编程指南
OpenCV T-API的测试(二)

OpenCV T-API的测试(二)

作者: Parker2019 | 来源:发表于2020-02-27 13:40 被阅读0次

    尝试视频处理


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

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

    但是这一次无法像上次那样打印出全部数据然后做总结,只能大体上根据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`

    运行结果:


    CPU运行结果

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

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

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

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

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

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

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


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

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

    原因分析


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

    首先,我们要定义保存脸部和眼部的vector,然后使用detectMultiScale函数将识别到的脸部和眼部信息保存至我们定义的std::vector<Rect> facesstd::vector<Rect> 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的测试(二)

        本文链接:https://www.haomeiwen.com/subject/tauthhtx.html