如何在OpenCV中的CV_32FC1和CV_32FC3图像之间进行像素倍数

时间:2018-01-19 07:54:28

标签: opencv image-processing matrix-multiplication

我正在研究二维imageA(CV_32FC1)与另一个具有OpenCV的三维imageB(CV_32FC3)之间的像素倍数,即imageA逐像素地乘以imageB的每个R \ G \ B通道。这与沿第3方向的广播图像A到3维相同,然后与图像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中的“广播”相同,即沿着第3个方向将2维图像广播到3维图像,并且每个结果通道与输入的2维图像相同。

提前致谢: - )

2 个答案:

答案 0 :(得分:2)

你这样做的方式是记忆无效,但理论上是正确的。调用A.convertTo(A,CV_32FC3);不幸的是不行。最有效的方法是致电

  

cv :: cvtColor(A,A,CV_GRAY2BGR);

这将复制或重新分配内存,但是比你当前应用的方式稍微有效一些(不为cv :: Mats创建额外的标题,在向量中充当视图)。

OpenCV不支持这种乘法的原因是因为在下面使用了英特尔IPP库,而且IPP也不支持这种乘法。这是OpenCV中每个元素矩阵乘法的确切用法: https://software.intel.com/en-us/ipp-dev-reference-mul。本质上,A和B中的数据大小必须相同才能使任何这些函数工作,此外,假设A和B都是连续的,因此在您的情况下,重新分配或复制是必要的。

答案 1 :(得分: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;
}

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

  

我测试了三种方法:

     

答:使用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