Opencv Mat加法异常行为
为什么这两行代码不相等?因为一些饱和演员 Mat类型为CV_8U,bgr为1通道Mat的矢量,灰色为单通道图像Opencv Mat加法异常行为,opencv,matrix,casting,Opencv,Matrix,Casting,为什么这两行代码不相等?因为一些饱和演员 Mat类型为CV_8U,bgr为1通道Mat的矢量,灰色为单通道图像 vector<Mat> bgr; Mat gray; 二, 以下是用于复制的最低代码: void Test() { Mat A= Mat::zeros(100,100,CV_8UC1); A(Rect(20,20,60,60)).setTo(128); Mat R= Mat::zeros(100,100,CV_8UC1); randu(R,
vector<Mat> bgr;
Mat gray;
二,
以下是用于复制的最低代码:
void Test()
{
Mat A= Mat::zeros(100,100,CV_8UC1);
A(Rect(20,20,60,60)).setTo(128);
Mat R= Mat::zeros(100,100,CV_8UC1);
randu(R, Scalar::all(0), Scalar::all(255));
//v1
//A+= (R-128)*2;
//v2
A= A+(R-128)*2;
imwrite("A.png", A);
}
简短回答:是的,这是因为
饱和演员
基本上,在版本1中,您正在执行以下操作:
Mat1b gray;
// ... gray somehow initialized
Mat1b temp = saturate_cast<uchar>(bgr * 2 - 256);
gray += temp;
不明白为什么-256?这就是它的实际计算方式。。。查看已发布代码的注释<代码>(bgr-128)*2->bgr*2-256。让我知道是否清楚我认为括号定义了表达式求值的顺序。@MrGlud嗯,是的。这里的问题不是计算顺序,而是灰色矩阵的赋值。分配时,OpenCV将执行到相同类型的目标矩阵的转换,在您的情况下,这会导致问题,因为您操作的部分结果超出了
uchar
范围。在您的两个版本中,对矩阵的赋值的执行方式不同,因此结果也不同。saturate\u cast
在对矩阵进行赋值时应用(=
)。内部MatExpr
对不会饱和的数据类型进行计算(在本例中是float
(为了更一般,我只在示例中添加了double
)。因此,真正发生的是,所有矩阵运算都存储在MatExpr
对象中,当有赋值时,该对象的计算不会饱和。在分配过程中,结果被饱和以适应目标矩阵。
void Test()
{
Mat A= Mat::zeros(100,100,CV_8UC1);
A(Rect(20,20,60,60)).setTo(128);
Mat R= Mat::zeros(100,100,CV_8UC1);
randu(R, Scalar::all(0), Scalar::all(255));
//v1
//A+= (R-128)*2;
//v2
A= A+(R-128)*2;
imwrite("A.png", A);
}
Mat1b gray;
// ... gray somehow initialized
Mat1b temp = saturate_cast<uchar>(bgr * 2 - 256);
gray += temp;
Mat1b gray;
// ... gray somehow initialized
gray = saturate_cast<uchar>((2 * bgr + 1 * gray) - 256);
#include <opencv2\opencv.hpp>
using namespace cv;
int main()
{
Mat1b bgr(10, 10, uchar(100));
Mat1b gray1(10, 10, uchar(100));
Mat1b gray2(10, 10, uchar(100));
Mat1b gray3(10, 10, uchar(100));
Mat1b gray4(10, 10, uchar(100));
// *****************************************
// v1
// *****************************************
gray1 += (bgr - 128) * 2;
// MatExpr e1(a = bgr, alpha = 1, beta = 0, s = -128) <- MatExpr operator - (bgr, 128); // (bgr - 128)
// MatExpr e2(a = bgr, alpha = 2, beta = 0, s = -256) <- MatExpr operator * (e1, 2); // (bgr - 128) * 2 -> bgr * 2 - 256
// Mat_<uchar>& operator += (bgr, e2);
// temp = saturate_cast<uchar>(bgr * 2 - 256);
// gray += temp;
// *****************************************
// v2
// *****************************************
gray2 = (bgr - 128) * 2 + gray2;
// MatExpr e1(a = bgr, alpha = 1, beta = 0, s = -128) <- MatExpr operator - (rgb, 128); // (bgr - 128)
// MatExpr e2(a = bgr, alpha = 2, beta = 0, s = -256) <- MatExpr operator * (e1, 2); // (bgr - 128) * 2 -> = bgr * 2 - 256
// MatExpr e3(a = bgr, b = gray, alpha = 2, beta = 1, s = -256) <- MatExpr operator + (e2, gray); // (bgr - 128) * 2 + gray -> (2 * bgr + 1 * gray) - 256
// gray = saturate_cast<uchar>((2 * bgr + 1 * gray) - 256);
// *****************************************
// v3 equivalent to v1
// *****************************************
Mat1b temp3 = (bgr - 128) * 2;
gray3 = gray3 + temp3;
// *****************************************
// v4 equivalent to v2
// *****************************************
Mat1d bgrd;
bgr.convertTo(bgrd, CV_64F);
Mat1d temp4 = (bgrd - 128) * 2;
Mat1d gray4d;
gray4.convertTo(gray4d, CV_64F);
gray4d = gray4d + temp4;
gray4d.convertTo(gray4, CV_8U);
// gray1 == gray3
// gray2 == gray4
return 0;
}