【问题标题】:Adding a scalar to a Mat object向 Mat 对象添加标量
【发布时间】:2015-08-04 20:25:06
【问题描述】:

所以我试图在 openCV 中为 Mat 对象的所有元素添加一个标量值,但是对于 raw_t_ubit8 和 raw_t_ubit16 类型,我得到错误的结果。这是代码。

Mat A;
//Initialize Mat A; 
A = A + 0.1; 

矩阵最初是

相加的结果是完全相同的矩阵。当我尝试将标量添加到 raw_t_real 类型的矩阵时,不会出现此问题。 raw_t_ubit8 我的意思是深度是 CV_8UC1

【问题讨论】:

  • 我不知道 raw_t_real 类型是什么(谷歌没有告诉我)......你试过:docs.opencv.org/modules/core/doc/operations_on_arrays.html#add 吗?可能没有为所有类型定义重载的“+”运算符。
  • by raw_t_ubit8 我的意思是 Mat A 是由 A.create(sizes_height,sizes_width,CV_8UC1) 创建的,是的,我也尝试过添加,产生相同的结果。
  • 如果您使用 CV_8UC1 创建它,它不可能包含您提到的值。
  • 它在每一行包含值 100 200 和 250,这基本上相当于我发布的带有缩放因子的数字,如果 1/255,我用来查看结果的查看器只是除以那个因素。
  • 您不能将 0.1(浮点/双精度类型)添加到整数类型。结果将始终转换为 uchar(或 raw_t_ubit8)。

标签: opencv addition mat


【解决方案1】:

如果,正如您在 cmets 中提到的,包含的值在矩阵中缩放以适合整数域 0..255,那么您还应该缩放您求和的标量值。即:

A = A + cv::Scalar(round(0.1 * 255) ); 

甚至更好:

A += cv::Scalar(round(0.1 * 255) ); 

请注意,正如 Miki 在 cmets 中指出的那样,cv::Scalar 在任何情况下都是由 double 组成的(它是 cv::Scalar_<double>)。 可以省略舍入,但是您可以选择如何将双精度数转换为整数到函数实现。 您还应该检查值饱和时会发生什么。

Documentation for Opencv matrix expressions.

【讨论】:

  • 我认为您可以避免使用cv::Scalar(int(round(...)...))。乘法是在内部对双精度进行的,然后结果是“饱和转换”到 A 类型。所以只需A += (0.1 * 255); 就可以了。可以查吗?
  • @Miki 如果我没记错的话,operator+cv::Mat 不会执行乘法运算。虽然我认为它适用于cv::Rect(对 cv::Size 求和它是一个缩放操作)。
  • @Miki 我认为提交标量比提交双精度值更有效,因此值不必在内部/临时转换为双精度值。
  • 创建一个Scalar提交,或者提交一个内部转换为Scalar的double是一样的。在我看来,A += 0.1*255; 也更直接。
  • 很高兴我们同意 :D。我刚刚写了另一个问题,还指出他可能需要转换为 CV_32FC1。我已经 +1 你了,因为你的解决方案实际上是正确的。
【解决方案2】:

如 cmets 和 @Antonio 的回答中所述,您不能将 0.1 添加到整数。

如果您使用的是 CV_8UC1 矩阵,但您想使用浮点值,则应乘以 255。

Mat1b A; // <-- type CV_8UC1
...
A += 0.1 * 255;

如果需要转换操作的结果,如本例,则最终调用saturated_cast

这相当于@Antonio 的回答,但它会产生更简洁的代码(至少对我而言)。 如果您对doubleScalar 求和,将使用相同的代码。 Scalar 对象将使用以下两种方式创建:

template<typename _Tp> inline
Scalar_<_Tp>::Scalar_(_Tp v0)
{
    this->val[0] = v0;
    this->val[1] = this->val[2] = this->val[3] = 0;
}

但是,如果您需要将 0.1 与矩阵相加(而不是将其缩放 255),则需要将矩阵转换为 CV_32FC1:

#include <opencv2/opencv.hpp>
using namespace cv;

int main(int, char** argv)
{
    Mat1b A = (Mat1b(3,3) << 1,2,3,4,5,6,7,8,9);

    Mat1f F;
    A.convertTo(F, CV_32FC1);
    F += 0.1;

    return 0;
}

【讨论】:

  • 你还知道饱和度是怎么处理的吗?我认为这可能是有用的信息。顺便说一句,我不认为隐式转换 (double -> cv::Scalar) 一定是更干净的代码:)
  • 如果需要对运算结果进行强制转换,如本例,则最终调用saturated_cast
  • @Antonio 我同意,添加了“(至少对我而言)”,因为这显然是基于意见的。还添加了“saturated_cast”的东西。
猜你喜欢
  • 1970-01-01
  • 2012-09-20
  • 2012-05-18
  • 2018-08-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多