我正在使用Qt Creator在C++的Windows 7上进行开发。
我也使用库OpenCV

我遇到了一个奇怪的问题assert函数。
我开发了一个函数,可以对图像进行线性变换以获得更好的对比度,并可以指定我们要处理的图像区域(x1,x2,y1,y2)以及公差(Tolmin和Tolmax):我们要忽略的直方图的百分位数。

我需要确保:

  • 图像为16位灰度(img.type()= CV_16U && img.channels()= 1)
  • 区域坐标正确(正,不超过图像大小...)
  • Tolmin,Tolmax阳性,Tolmin + Tolmax!= 1(如果Tolmin + Tolmax = 1,则除以0)

  • 我使用了功能assert
    我的代码如下:
    void equalizeHist_16U_linear(Mat &img, float Tolmin, float Tolmax, int x1, int x2, int y1, int y2)
    {
        assert(img.channels() == 1);
        assert(img.type() == CV_16U);
        assert(x1>=0 && y1>=0 && x2>=x1 && y2>=y1);
        assert(y2<img.rows && x2<img.cols);
        assert(Tolmin>0 && Tolmax>0);
        assert(Tolmin+Tolmax != 1.0);
    
        ## code ##
        ...
    
    }
    

    前五个assert可以正常工作,但最后一个assert(Tolmin+Tolmax != 1.0)不起作用。即使使用Tolmin+Tolmax=1,assert也不停止执行,因此程序崩溃(除以0)。
    可以肯定的是,我在Tolmin+Tolmax调用之前打印了assert
    void equalizeHist_16U_linear(Mat &img, float Tolmin, float Tolmax, int x1, int x2, int y1, int y2)
    {
        cout << endl << "Tolmin+Tolmax = " << Tolmin+Tolmax << endl;
    
        assert(img.channels() == 1);
        assert(img.type() == CV_16U);
        assert(x1>=0 && y1>=0 && x2>=x1 && y2>=y1);
        assert(y2<img.rows && x2<img.cols);
        assert(Tolmin>0 && Tolmax>0);
        assert(Tolmin+Tolmax != 1.0);
    
        ## code ##
        ...
    
    }
    

    它显示“Tolmin + Tolmax = 1”,这一次,assert停止了程序的执行!

    这怎么可能 ?为什么显示Tolmin+Tolmax可以使assert工作?

    我试图添加以下内容:
    void equalizeHist_16U_linear(Mat &img, float Tolmin, float Tolmax, int x1, int x2, int y1, int y2)
    {
        float sum = Tolmin+Tolmax;
    
        assert(img.channels() == 1);
        assert(img.type() == CV_16U);
        assert(x1>=0 && y1>=0 && x2>=x1 && y2>=y1);
        assert(y2<img.rows && x2<img.cols);
        assert(Tolmin>0 && Tolmax>0);*/
        assert(sum != 1.0);
    
        ## code ##
        ...
    
    }
    

    但这也不起作用。

    最佳答案

    我的猜测是您的代码中使用了一个值(如Tolmin或Tolmax),而该值不能以机器的数字格式表示。
    我什么意思好了,您可以轻松地想到哪些数字计算机无法完全按原样存储它们。计算机必须以有限数字的二进制格式存储数字,因此某些数字将不能完全按原样存储。这样想,我们可以想到数字(2/3)对吗?但是当我们必须用有限位数的十进制格式表示此数字时,我们必须将其舍入为:0.66666667,因此我们无法准确地按原样写入此数字。这种情况也可以在机器中产生,例如,我们不能以二进制格式将数字0.2存储在机器中,因为它的二进制代表数字是无限的,机器会将这些数字四舍五入到可以存储的最接近的数字。
    在您的情况下,您正在将转换后的二进制数与绝对值(1.0)进行比较,从逻辑上讲,即使它们彼此非常接近,它们也不相同。所以我的猜测是Tolmin和Tolmax的总和将非常接近1.0,但不完全是1.0。那么解决方案是什么?您应该检查sum是否已超过1.0的任意间隔。像这样:

    assert(abs(sum - 1.0) > 0.0001)
    

    更新:
    使用gcc和MSC++进行打印时,我无法重现您报告的行为,因此,我只能做一个较弱的猜测。生成代码时,编译器将在优化阶段对其进行修改。您需要在两个位置计算Tolmin+Tolmax,首先在cout中,其次在assert中,因此编译器将推断出该计算可以执行一次,然后再使用它的结果。当cout更改您要显示的数字时,该值非常接近1,它将被四舍五入并获得确切的值1,然后结果将在assert中重用。是否可以,我无法确认,因为我无法重现报告的行为。

    09-06 14:12