如何在OpenCV中对CV_32FC1和CV_32FC3图像进行逐像素乘法?

4

我正在使用OpenCV进行像素级的乘法运算,将一张二维图像A(CV_32FC1)与另一张三维图像B(CV_32FC3)相乘,即将图像A在第三个方向上广播为三维图像,然后与图像B逐像素相乘。现在,我是这样做的:

vector<Mat> temp{imageA, imageA, imageA};   // imageA is CV_32FC1
merge(temp, sampA);                         // sameA is CV_32FC3 now, and each channel is same as imageA
Out = imageB.mul(sampA);                    // imageB is CV_32FC3, and do pixel-wise with sameA

我的问题是: 我能否使用OpenCV获得另一种更有效的方法来达到这个目的?比如OpenCV中的一个函数。

我知道这与MXNet中的“Broadcast”相同,即将2维图像沿第3个方向广播为3维图像,并且结果的每个通道都与输入的2维图像相同。

提前致谢 :-)

2个回答

2
你正在进行的方式虽然理论上是正确的,但不够高效。调用A.convertTo(A, CV_32FC3)不起作用。最有效的方法是调用:
cv::cvtColor(A, A, CV_GRAY2BGR);
这将复制或重新分配内存,但比你当前应用的方式(没有为充当向量视图的cv :: Mats创建额外的头文件)略微更有效。
OpenCV之所以不支持这种乘法,是因为它使用Intel IPP库,在IPP下也不支持这种乘法。这正是OpenCV用于每个元素矩阵乘法的实现方式: https://software.intel.com/en-us/ipp-dev-reference-mul。基本上,A和B中的数据大小必须相同,才能使任何一个函数工作,并且另外,假定A和B都是连续的,因此在你的情况下,需要重新分配或复制。

非常感谢。这正是我想了解的。再次感谢。 - smh

1

这是我的代码,用于对CV_32FC3和CV_32FC1进行乘法操作

Mat matmul32F(Mat& bgr, Mat& mask)
{
    assert(bgr.type() == CV_32FC3 && mask.type() == CV_32FC1 && bgr.size() == mask.size());
    int H = bgr.rows;
    int W = bgr.cols;
    Mat dst(bgr.size(), bgr.type());

    if (bgr.isContinuous() && mask.isContinuous())
    {
        W *= H;
        H = 1;
    }

    for( int i = 0; i < H; ++i)
    {
        float* pdst = ((float*)dst.data)+i*W*3;
        float* pbgr = ((float*)bgr.data)+i*W*3;
        float* pmask = ((float*)mask.data) + i*W;
        for ( int j = 0; j < W; ++j)
        {
            (*pdst++) = (*pbgr++) *(*pmask);
            (*pdst++) = (*pbgr++) *(*pmask);
            (*pdst++) = (*pbgr++) *(*pmask);
            pmask+=1;
        }
    }
    return dst;
}

最高效的方法是自己迭代。

我测试了三种方法:

A:使用mergemul

B:使用cvtColormul

C:循环指针并手动相乘。

就时间成本而言,在大多数情况下,A ≈ B ≈ 2 x C。典型的时间成本如下:

Test A: 3.23E-03 s
Test B: 3.26E-03 s
Test C: 1.85E-03 s

这是我找到的快速方法。我认为,在一个函数中使用指针运算符和循环将节省时间。 - Kinght 金
在我看来,“cvtColor”是最清晰易懂的,但我打算使用“Pointer”的那个。 - smh
csu?我知道知乎应该已经被放弃了,因为有太多的水货。如果一直使用中英混合的语言,外国人会不会感到困惑呢?Pointer更快,cv::Mat::mul更干净,而封装指针函数也很干净。这取决于你的真实目的。选择你喜欢的吧。 - Kinght 金

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接