不同类型的 OpenCV 乘法矩阵 (cv::Mat)

OpenCV multiplying matrices (cv::Mat) of different types

错误:

what(): OpenCV(4.2.0) ../modules/core/src/arithm.cpp:691: error: (-5:Bad argument) When the input arrays in add/subtract/multiply/divide functions have different types, the output array type must be explicitly specified in function 'arithm_op'

代码:

// cx is a cv::Mat containing a 1280x720x1 matrix of floats

// what i want is an output of 0.0 where cx <= 0.5 and (cx-0.5)*2 otherwise

auto c0 = (cx > 0.5).mul((cx - 0.5) * 2);

我试过了:

auto c0 = (cx > 0.5).mul((cx - 0.5) * 2, CV_32F);

哪个没用。

主要问题是 (cx > 0.5) 的类型是 CV_8U 而不是 CV_32F

看看下面的代码示例:

//Initialize 3x3 matrix for example
cv::Mat cx = (cv::Mat_<float>(3, 3) << 5.0f, 0, 0, 0, 5.0f, 0, 0, 0, 5.0f);

//The type of "logical matrix" result of (cx > 0.5f) is UINT8 (255 where true).
cv::Mat cx_above05 = (cx > 0.5f);

为了方便起见,我使用 Image Watch 和 Visual Studio 2017。

这是 cv::Mat cx_above05 = (cx > 0.5f) 的结果:

如您所见,类型为 UINT8,值为 255,其中 cx>0.50,否则为


您可以使用 convertTo 将类型转换为 CV_32F 并除以 255:

cx_above05.convertTo(cx_above05 , CV_32F, 1.0/255.0);  //Convert type to float (1.0f where true).

结果:

如您所见,类型为 FLOAT32255 值转到 1.0f


完整代码示例:

cv::Mat cx = (cv::Mat_<float>(3, 3) << 5.0f, 0, 0, 0, 5.0f, 0, 0, 0, 5.0f);  //Initialize 3x3 matrix for example      
cv::Mat cx_above05 = (cx > 0.5f); //The type of "logical matrix" result of (cx > 0.5f) is UINT8 (255 where true).
cx_above05.convertTo(cx_above05 , CV_32F, 1.0/255.0); //Convert type to float (1.0f where true).
cv::Mat c0 = cx_above05.mul((cx - 0.5f) * 2.0f);

结果:


我们可以使用 OpenCV pow documentation:

中描述的技巧,而不是乘以掩码
cv::Mat cx = (cv::Mat_<float>(3, 3) << 5.0f, 0, 0, 0, 5.0f, 0, 0, 0, 5.0f);  //Initialize 3x3 matrix for example      
cv::Mat mask = (cx <= 0.5f); //The type of "logical matrix" result of (cx <= 0.5f) is UINT8 (255 where true).
cv::Mat c0 = (cx - 0.5f) * 2.0f;
cv::subtract(c0, c0, c0, mask);

我找到了一个更优雅的解决方案 (using setTo):

cv::Mat c0 = (cx - 0.5f) * 2.0f;
c0.setTo(0, cx <= 0.5f);

一行解法:

表达式((cx - 0.5f) * 2.0f)的类型是cv::MatExpr,我们可以将其转换为cv::Mat:

cv::Mat c0 = ((cv::Mat)((cx - 0.5f) * 2.0f)).setTo(0, cx <= 0.5f);