【问题标题】:OpenCV multiplying matrices (cv::Mat) of different types不同类型的OpenCV乘法矩阵(cv::Mat)
【发布时间】:2021-08-11 15:05:46
【问题描述】:

错误:

what(): OpenCV(4.2.0) ../modules/core/src/arithm.cpp:691: error: (-5:Bad argument) 当输入数组在加/减/乘/除函数中时有不同的类型,输出数组类型必须在函数'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);

这没用。

【问题讨论】:

  • 你想如何从矩阵中减去一个浮点值?
  • @AbdelAzizAbdelLatef 这应该在整个矩阵中广播。我认为这不是问题,问题是掩码 (cx > 0.5) 是一个 int 值,我想将 int 0 或 1 乘以右侧的浮点数。它说“必须明确指定输出数组类型”,但我不确定如何明确指定它。

标签: c++ opencv math matrix multiplication


【解决方案1】:

主要问题是(cx &gt; 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 &gt; 0.5f)的结果:

如您所见,类型为UINT8,值为255,其中cx&gt;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);

我找到了一个更优雅的解决方案here(使用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);

【讨论】:

  • 谢谢!我想知道在这一点上迭代矩阵中的所有值是否会更有效,因为如果掩码为 0,我可以首先避免浮点计算......我不确定 OpenCV 是否有任何矢量化魔法虽然(?)
  • 一个简单的循环可能会更快,因为代码足够简单,编译器可以向量化。您也可以尝试使用Eigen 库,但我不知道是否有一个优雅的解决方案来实现条件(cx &gt; 0.5f)。 OpenCV 可以使用 Eigen 构建,并且 OpenCV 数学表达式具有矢量化魔法的变化。但是setTo(0, cx &lt;= 0.5f) 很可能会降低性能。
猜你喜欢
  • 1970-01-01
  • 2018-07-09
  • 1970-01-01
  • 2014-01-28
  • 2012-09-02
  • 2012-02-12
  • 2013-01-25
  • 1970-01-01
  • 2012-07-17
相关资源
最近更新 更多