如何在 OpenCV 中的 CV_32FC1 和 CV_32FC3 图像之间进行像素倍增
How can I do pixel-wise multiple between CV_32FC1 and CV_32FC3 images in OpenCV
我正在使用 OpenCV 在 2 维图像 A(CV_32FC1) 和另一个 3 维图像 B(CV_32FC3) 之间进行像素乘法,即 imageA 像素乘法imageB 的每个 R\G\B 通道。这与沿第 3 个方向将 imageA 广播到 3 维,然后按像素与 imageB 广播相同。
现在,我通过:
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"相同,即沿第3个方向将2维图像广播到3维图像,结果的每个通道与输入2维相同图片。
提前致谢:-)
您的做法是 memory-ineffective,但理论上是正确的。调用 A.convertTo(A, CV_32FC3);不幸的是不会工作。最有效的方法是调用
cv::cvtColor(A, A, CV_GRAY2BGR);
这将复制或重新分配内存,但以一种比您当前应用的方式稍微更有效的方式(无需为 cv::Mats 创建额外的 headers 作为向量中的视图)。
OpenCV之所以不支持这种乘法是因为底层使用了Intel IPP库,IPP也不支持这种乘法。这正是 OpenCV 中用于每个元素矩阵乘法的内容:
https://software.intel.com/en-us/ipp-dev-reference-mul。基本上 A 和 B 中的数据大小必须相同才能使这些函数中的任何一个起作用,此外,假设 A 和 B 是连续的,因此在您的情况下,重新分配或复制是必要的。
这是我对 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;
}
最有效的方法是自己迭代。
I test three method for :
A: use merge
and mul
B: use cvtColor
and mul
C: loop sing pointer and mutiply by hand.
至于时间成本,大多数情况下,A ≈ B ≈ 2 x C
。典型的时间成本是:
Test A: 3.23E-03 s
Test B: 3.26E-03 s
Test C: 1.85E-03 s
我正在使用 OpenCV 在 2 维图像 A(CV_32FC1) 和另一个 3 维图像 B(CV_32FC3) 之间进行像素乘法,即 imageA 像素乘法imageB 的每个 R\G\B 通道。这与沿第 3 个方向将 imageA 广播到 3 维,然后按像素与 imageB 广播相同。 现在,我通过:
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"相同,即沿第3个方向将2维图像广播到3维图像,结果的每个通道与输入2维相同图片。
提前致谢:-)
您的做法是 memory-ineffective,但理论上是正确的。调用 A.convertTo(A, CV_32FC3);不幸的是不会工作。最有效的方法是调用
cv::cvtColor(A, A, CV_GRAY2BGR);
这将复制或重新分配内存,但以一种比您当前应用的方式稍微更有效的方式(无需为 cv::Mats 创建额外的 headers 作为向量中的视图)。
OpenCV之所以不支持这种乘法是因为底层使用了Intel IPP库,IPP也不支持这种乘法。这正是 OpenCV 中用于每个元素矩阵乘法的内容: https://software.intel.com/en-us/ipp-dev-reference-mul。基本上 A 和 B 中的数据大小必须相同才能使这些函数中的任何一个起作用,此外,假设 A 和 B 是连续的,因此在您的情况下,重新分配或复制是必要的。
这是我对 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;
}
最有效的方法是自己迭代。
I test three method for :
A: use
merge
andmul
B: use
cvtColor
andmul
C: loop sing pointer and mutiply by hand.
至于时间成本,大多数情况下,A ≈ B ≈ 2 x C
。典型的时间成本是:
Test A: 3.23E-03 s
Test B: 3.26E-03 s
Test C: 1.85E-03 s