OpenCV T-API的测试(二)

尝试视频处理


上一次就是简单的跑了下边缘检测,在上次的代码中全部都是使用的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版本的函数。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,558评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,002评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,036评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,024评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,144评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,255评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,295评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,068评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,478评论 1 305
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,789评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,965评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,649评论 4 336
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,267评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,982评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,223评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,800评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,847评论 2 351