编写接受 cv::Mat 或 cv::UMat 类型输入的模板函数

Posted

技术标签:

【中文标题】编写接受 cv::Mat 或 cv::UMat 类型输入的模板函数【英文标题】:Writing template functions accepting inputs of type cv::Mat or cv::UMat 【发布时间】:2018-09-05 08:13:36 【问题描述】:

编写一个接受 Mat 或 UMat 类型输入参数的函数的最简单和最简洁的方法是什么?

我应该使用 InputArray、使用模板还是有更好的选择?我现在拥有为 Mat 和 UMat 编写的具有相同实现的函数。

该函数应充分利用 OpenCL 上的 UMat 抽象,并且运行速度大致与仅为 UMats 编写的一样快,并且无需将 UMats 复制到 Mats 的开销。

我可以为 Mat 和 UMat 定义的函数示例如下(请不要建议重构以删除本地 Mat/UMat 变量,这只是一个示例)

using namespace cv;    

void foo(const Mat & in1, const Mat & in2, Mat & out)

    Mat aux1;
    Mat aux2;
    exp(in1, aux1);
    exp(in2, aux2);
    add(aux1, aux2, out);
    return;


void foo(const UMat & in1, const UMat & in2, UMat & out)

    UMat aux1;
    UMat aux2;
    exp(in1, aux1);
    exp(in2, aux2);
    add(aux1, aux2, out);
    return;

【问题讨论】:

你可以使用InputArray,就像所有的OpenCV函数一样 这是最方便的选择吗?来自docs.opencv.org/3.4.0/d4/d32/… 我读到“这个类是专门为传递参数而设计的。也就是说,通常你不应该声明这种类型的类成员、局部和全局变量。”。我的函数确实根据输入类型声明/使用本地 Mats/UMats 请提供一些代码示例。 “最方便”的定义并不明确 在我看来就像一个经典的模板。 【参考方案1】:

@Miki 和@Gianni 建议,Mat, Mat_<T>, Matx<T, m, n>, std::vector<T>, std::vector<std::vector<T> >, std::vector<Mat>, std::vector<Mat_<T> >, UMat, std::vector<UMat> or double. 的通用模板类型我们可以选择InpputArray and OutputArray

void func(InputArray _src1, InputArray _src2, OutputArray _dst)

    Mat src1 = _src1.getMat(), src2 = _src2.getMat();
    CV_Assert( src1.type() == src2.type() && src1.size() == src2.size());
    Mat aux1 = Mat(src1.size(), src1.type());
    Mat aux2 = Mat(src1.size(), src1.type());
    cv::exp(src1, aux1);
    cv::exp(src2, aux2);

    _dst.create(src1.size(), src1.type());
    Mat dst = _dst.getMat();
    cv::add(aux1, aux2, dst);

现在您可以使用MatUMat 甚至std::vector 对其进行测试

int test()
    std::vector<float> vec1 = 1,2,3;
    std::vector<float> vec2 = 3,2,1;
    std::vector<float> dst;

    func(vec1, vec2, dst);
    // now dst is [22.8038, 14.7781, 22.8038]


【讨论】:

我突然意识到GpuMat 可能不合适。但我没有测试。 +1 因为它确实有效。但我想利用 UMat 抽象:在这里,我的 UMat 将转换为 Mats,而我的 exp() 和 add() 调用将在 CPU 中运行。我也不想通过 .getMat() 调用将内存从设备移动到主机,因为这可能意味着显着的额外处理开销。我将编辑我的问题,因为它可能不清楚【参考方案2】:

我使用了一个模板:

using namespace cv;    

// MatType is either cv::Mat or cv::UMat.
template<typename MatType>
void foo(const MatType& in1, const MatType& in2, MatType& out)

    MatType aux1;
    MatType aux2;
    exp(in1, aux1);
    exp(in2, aux2);
    add(aux1, aux2, out);
    return;

优点:

很容易根据输入类型声明本地Mats 或UMats。 没有MatUMat 转换。

缺点:

所有矩阵参数必须是同一类型,不能混合使用Mats 和UMats。

【讨论】:

以上是关于编写接受 cv::Mat 或 cv::UMat 类型输入的模板函数的主要内容,如果未能解决你的问题,请参考以下文章

Opencv学习笔记 - 关于OpenCV的UMat 类

为啥 cv2.rectangle 有时会返回 np.ndarray,而有时会返回 cv2.UMat

OpenCV 3:如何将 cv::Mat 作为可选参数传递

OpenCV TypeError: Expected cv::UMat for argument 'src' - 这是啥?

如何将 <class 'streamlit.uploaded_file_manager.UploadedFile'> 类型的文件转换为 Ptr<cv::UMat>?

需要一种更快的方法将 cv::Mat 转换为一维向量形式