我正在研究二维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维图像相同。
提前致谢: - )
答案 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)
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;
}
最有效的方法是自己迭代。
我测试了三种方法:
答:使用
merge
和mul
B:使用
cvtColor
和mul
C:循环唱指针和手工制作。
至于时间成本核算,在大多数情况下,A ≈ B ≈ 2 x C
。典型的时间成本是:
Test A: 3.23E-03 s
Test B: 3.26E-03 s
Test C: 1.85E-03 s