Opencv 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,

为什么这两行代码不相等?因为一些饱和演员

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, 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;
    }