OpenCV GAPI 性能不如预期

Posted

技术标签:

【中文标题】OpenCV GAPI 性能不如预期【英文标题】:OpenCV GAPI performance not good as expected 【发布时间】:2020-03-11 04:36:14 【问题描述】:

我做了以下测试,但是结果不是很好,因为我希望 GAPI 可以改进很多。不知道是不是我做错了,希望大家帮我指正,非常感谢!

我的测试环境是OpenCV4.2官方构建,Windows 10 x64,VS2019 Release x64,i7-8700K。

#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/gapi.hpp>
#include <opencv2/gapi/core.hpp>
#include <opencv2/gapi/imgproc.hpp>

std::string image_path = "1.png";
cv::Mat GAPITEST(const cv::Mat& input_frame)

    cv::Mat output_frame;

    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 out = cv::gapi::Canny(blurred, 32, 128, 3);
    cv::GComputation ac(in, out);

    int64 t0 = cv::getTickCount();
    for(int i=0;i<200;i++)
        ac.apply(input_frame, output_frame);
    int64 t1 = cv::getTickCount();
    std::cout <<__func__<< "\t seconds:" << (t1 - t0) / cv::getTickFrequency()<<std::endl;

    return output_frame;


cv::Mat TraditionalTEST(const cv::Mat& input_frame)

    cv::Mat output_frame;
    cv::Mat vga;
    cv::Mat gray;
    cv::Mat blurred;

    int64 t0 = cv::getTickCount();
    for (int i = 0; i < 200; i++)
    
        cv::resize(input_frame,vga, cv::Size(), 0.5, 0.5);
        cv::cvtColor(vga, gray, cv::COLOR_BGR2GRAY);
        cv::blur(gray, blurred,cv::Size(5,5));
        cv::Canny(blurred,output_frame,32,128,3);
    
    int64 t1 = cv::getTickCount();
    std::cout << __func__ << "\t seconds:" << (t1 - t0) / cv::getTickFrequency()<<std::endl;
    return output_frame;

int main()

    cv::Mat input_frame = cv::imread(image_path);
    cv::imshow("input_frame",input_frame);
    cv::waitKey(100);
    auto result1 = GAPITEST(input_frame);
    auto result2 = TraditionalTEST(input_frame);
    //check result whether identical or not.
    bool eq = cv::countNonZero(result1 != result2) == 0;
    std::cout << "result equal  "<< eq;
    return 0;


输出

GAPITEST         seconds:4.92153
TraditionalTEST  seconds:4.68761
result equal  1

【问题讨论】:

看看这个presentation。当前的改进在于使用的内存。默认的经典 OpenCV 函数,如 cvtColorblur 已经使用并行化、矢量化技术。所以你不应该看到太大的改进。此外,还有一个理论上的计算限制:这些 OpenCV 函数已经高度优化,因此计算时间不会大幅改善。更多信息here. 【参考方案1】:

GAPI 仍处于早期开发阶段,它在单台机器上的性能相当糟糕。 GAPI 本身并非主要设计用于直接计算算法,因此它使用后端库来执行计算。默认是 OpenCV 的默认后端,这很糟糕。您可以将其替换为 Fluid 后端,据说它在执行算法时具有更好的缓存局部性,但在我的几次测试中仍然很糟糕。

这些后端非常缺乏基本 OpenCV 函数的实现(例如,Fluid 仅支持用于盒形过滤器的 3x3 内核),并且当您使用不受支持的操作时,GComputation::apply 将不正常地崩溃,并且经常没有任何有用的错误消息。

GAPI 的优点在于它实现的图形模型与硬件无关。您可以将它生成的图形放到具有多个 GPU、CPU 等的云或分布式计算系统上,它会自动充分利用可用的资源。

如果你想在单台机器上获得快速的性能,我推荐使用 cv::cuda::GpuMat。我自己经常使用它,它对于许多操作来说都非常快。它省去了编写自定义 CUDA 内核的麻烦。

我不能保证 UMat 或其他 GPU 实现质量,因为我只使用过带有 Nvidia 卡的 OpenCV。

您还可以考虑使用 OpenMP 支持编译 OpenCV 以提高性能。

无论如何,这是一种霰弹枪式的回答。转到此处了解有关 GAPI 的更多详细信息以及比较多个后端的更完整的测试程序:https://docs.opencv.org/master/d3/d7a/tutorial_gapi_anisotropic_segmentation.html

【讨论】:

【参考方案2】:

G-API 团队正在通话中!

正如 Alex 所提到的,将默认执行的 G-API 与 OpenCV 模拟代码进行比较目前不会大大提高您的性能。

Fluid 后端成功了,但到目前为止它仍然是单线程的。这意味着,与默认为多线程的常规 OpenCV 代码相比,它不会有太大优势。

您可能想尝试 Fluid 后端,但使用 setNumThreads(1) 进行测试以注意差异。您的输入图像越大(就分辨率而言),您应该在那里看到的效果就越好。

另外,我鼓励您阅读这些新教程:

    https://docs.opencv.org/4.3.0/d8/d24/tutorial_gapi_interactive_face_detection.html https://docs.opencv.org/4.3.0/d4/d48/tutorial_gapi_face_beautification.html

我们现在更加重视混合 CV/DL 执行和面向视频流的处理。


添加

G-API 附带一个简单的测试来说明上述“G-Effect”,尽管测试不是 OpenCV 或 OpenVINO 的常规(二进制)分发的一部分:

https://github.com/opencv/opencv/blob/master/modules/gapi/perf/perf_bench.cpp

如果您自己构建 OpenCV(或只是一个目标 opencv_perf_gapi),您将能够像这样运行它

./bin/opencv_perf_gapi --gtest_filter="Benchmark*"

我很想看看你在你的机器上获得的数字。

【讨论】:

以上是关于OpenCV GAPI 性能不如预期的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV 预期的构造函数、析构函数或类型转换

虽然找到2张图片之间的差异,但OpenCV差异大于预期

为啥我在嵌套的 for 循环中分配 OpenCV Mat 对象后不包含预期值?

python OpenCV中的ValueError - 没有足够的值来解包(预期3,得到2)

C++ - 错误:为 OpenCV 的 cv::Scalar::all 创建 C 包装器时出现预期的类型说明符

opencv怎么截取视频图片