美文网首页OpenCv目标检测
OpenCV Graph API初体验

OpenCV Graph API初体验

作者: Parker2019 | 来源:发表于2020-02-16 14:48 被阅读0次

    OpenCV Graph API (G-API)

    Introduction:

    OpenCV的Graph API(或称G-API)是一个让常规图像处理变得更快(fast)和轻量(portable)的新模块。这两种方式的是通过引入一个新的基于图像的执行模型实现的(graph-based model of execution)。

    G-API是一个特殊的OpenCV模块。和其它大多数的主要模块(OpenCV本体模块)不同的是,此模块扮演的角色是一个框架,而不是某种特别的CV算法。G-API提供了定义CV操作的方式,用以构图(以一种表达的方式),最终通过特定的后端(backend)来生效和执行操作。

    注意:G-API是一个新模块,目前正处在活跃的开发过程中,它的API现阶段是不稳定的,在未来或许会有一些微小但破坏兼容性的变化。

    Contents

    G-API的文档被编排为如下篇章:

    开发G-API背后的动机和其的目标
    G-API构架的总体概览和其主要的内部构件
    学习如何引入G-API中新的操作并使其在不同的后端下生效
    G-API的核心操作,算术、布尔和其他矩阵运算
    图像处理的函数:色彩空间转换,滤波器等等

    API Example

    下面举一个非常简单的G-API应用的例子:

    g-api.cpp

    #include <opencv2/videoio.hpp>
    #include <opencv2/highgui.hpp>
    #include <opencv2/gapi.hpp>
    #include <opencv2/gapi/core.hpp>
    #include <opencv2/gapi/imgproc.hpp>
    int main(int argc, char *argv[])
    {
        cv::VideoCapture cap;
        if (argc > 1) cap.open(argv[1]);
        else cap.open(0);
        CV_Assert(cap.isOpened());
        cv::GMat in;
        cv::GMat vga      = cv::gapi::resize(in, cv::Size(), 0.5, 0.5);
        cv::GMat gray     = cv::gapi::BGR2Gray(vga);
        cv::GMat blurred  = cv::gapi::blur(gray, cv::Size(5,5));
        cv::GMat edges    = cv::gapi::Canny(blurred, 32, 128, 3);
        cv::GMat b,g,r;
        std::tie(b,g,r)   = cv::gapi::split3(vga);
        cv::GMat out      = cv::gapi::merge3(b, g | edges, r);
        cv::GComputation ac(in, out);
        cv::Mat input_frame;
        cv::Mat output_frame;
        CV_Assert(cap.read(input_frame));
        do
        {
            ac.apply(input_frame, output_frame);
            cv::imshow("output", output_frame);
        } while (cap.read(input_frame) && cv::waitKey(30) < 0);
        return 0;
    }
    

    注意 必须编译opencv-contrib,才能正常编译以上代码。且必须为OpenCV 4.x
    代码中调用了摄像头,没有摄像头可以用视频代替,cap.open("filename.xxx")或者在运行程序时在后面加入视频的名称(如./g-api ./filename.xxx)。
    编译命令:
    g++ g-api.cpp -o g-api `pkg-config --flags --libs opencv4`

    由于G-API是OpenCV的一个独立模块,所以其头文件必须单独引入。
    也就是说 直接引入#include <opencv2/opencv.hpp>头文件不行,opencv.hpp里面没有包含G-API的头文件。main()函数里面首先创建和初始化了标准OpenCV视频类,可以从视频流或者摄像头读取每帧图像。

    G-API的管线(pipeline:pipeline表示在外接程序与其宿主之间交换数据的管线段的线性通信模型。从宿主端开始,管线具有以下一系列管线段:宿主、外接程序的宿主视图、宿主端适配器、协定、外接程序端适配器、外接程序视图和外接程序。)随之被创建,事实上它是通过调用cv::GMat来完成一系列的G-API数据操作。关于这块代码比较重要的一个方面是:它只是声明了要去做什么操作,而并不是直接执行什么操作。到此时也还没有进行任何的图像处理。G-API只追踪管线的操作以及其实如何连接的。G-API的数据对象(在此处是cv::GMat)是用以连接各种操作的(PS,这点其实就等同于流水线作业)。cv::GMat in则是一个为空的GMat信号,用于告知计算的开始。

    在写完G-API这块代码之后,图像(frame帧)便被捕捉到一个调用图(call graph)中,并同时实例化cv::GComputation这个对象。此对象把输入/输出(input/output)数据当做参数(在本例中依次是inout这两个cv::GMat对象),并基于in和out的中的数据流来重建调用图。

    在某种程度上,cv::GComputation是一个缩减对象(thin object,我也不知道怎么翻译好),它负责捕捉何种图像处理操作来组成计算。但他也可以用于执行计算——在接下来的循环处理中,每次捕捉到的帧(cv::Mat frame)就被传入cv::GComputation::apply()中。

    官网测试图

    cv::GComputation::apply()是一个多态方法(polimorphic method),它可以接受数量可变(variadic number)的参数。由于定义好了一个输入和一个输出,cv::GComputation::apply()的一个特殊重载函数就被用于传入输入参数,得到输出参数。
    总而言之,cv::GComputation::apply()就根据给定输入参数来编译捕捉图(captured graph)并立即执行编译捕捉图。

    针对这个例子中一些比较重要的概念可以列出如下大纲:
    • 图像(Graph)的声明和执行时分开的两个步骤
    • 图像是根据一系列的G-API表达式来隐式构建的
    • G-API支持一些类似函数的调用——比如cv::gapi::resize()以及一些重载操作符,比如 operator|() 一个用于按位或的操作符。
    • G-API的语法力求简洁,每一项调用操作即在一个图(Graph)中产生一个新的结果,从而形成了有向无环图(Directed Acyclic Graph,DAG)。
    • 图的声明并没有绑定任何的数据——真实数据(cv::Mat)是在图(Graph)已经定义之后才生成的。

    PS:这里的图(Graph)实际上是不能看到的,OpenCV调用cv::imshow()函数现阶段是不支持cv::GMat格式的,只有转化为cv::Mat格式才能正常显示。

    如果对G-API的特性和理念有兴趣,还可以上OpenCV看更多的例子和教程。教程和例子

    以下是个人实验的部分

    (没有拿去和普通OpenCV操作作对比。)
    g-api.cpp中我加入了计时部分。编译时加入-DDEBUG显示时间
    头文件额外引入#include <iomanip>,不然setprecision()可能不能用。

    do
        {
            double start = (double)cv::getTickCount();
            ac.apply(input_frame, output_frame);
            cv::imshow("output", output_frame);
            double time_consume = ((double)cv::getTickCount() - start) / cv::getTickFrequency();
    #ifdef DEBUG
            std::cout << "time_comsume = "<< time_consume * 100  //以s做单位没意义,改为ms
            << std::setprecision(2) << "ms"<<std::endl;
    #endif
        } while (cap.read(input_frame) && cv::waitKey(30) < 0);
    

    以下是测试的结果:


    测试结果

    CPU占用也如图所示,大概在30%左右,消耗的时间在调试控制台中显示,平均时间大概在0.3ms左右。

    相关文章

      网友评论

        本文标题:OpenCV Graph API初体验

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