我正在使用Qt Creator在C++的Windows 7上进行开发。
我也使用库OpenCV
我遇到了一个奇怪的问题assert
函数。
我开发了一个函数,可以对图像进行线性变换以获得更好的对比度,并可以指定我们要处理的图像区域(x1,x2,y1,y2)以及公差(Tolmin和Tolmax):我们要忽略的直方图的百分位数。
我需要确保:
我使用了功能
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中重用。是否可以,我无法确认,因为我无法重现报告的行为。