我使用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
时,断言也不会停止执行,因此程序崩溃(除以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 ##
...
}
显示&#34; Tolmin + Tolmax = 1&#34;,这次,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 ##
...
}
但它也不起作用。
答案 0 :(得分:3)
我的猜测是您的代码中使用的值(如Tolmin或Tolmax)无法以机器的数字格式表示。 我的意思是什么?那么有些数字你可以很容易地想到计算机无法完全按照它们存储它们。计算机必须以有限数字二进制格式存储数字,因此某些数字将不会完全按原样存储。想一想,我们可以想到数字(2/3)吧?但是当我们必须以有限数字的十进制格式表示这个数字时,我们必须将它舍入为:0.66666667因此我们无法准确地写出这个数字。这种情况也可以在机器中累积,例如我们不能将数字0.2存储在二进制格式的机器中,因为它的二进制代表数字是无限的,机器将这些数字四舍五入到它可以存储的最接近的数字。 在您的情况下,您将转换为二进制数与绝对值(1.0)进行比较,从逻辑上讲它们并不相同,即使它们彼此非常接近。所以我的猜测是Tolmin和Tolmax的总和将非常接近1.0而不是1.0。那么解决方案是什么?你应该检查总和是否已经通过任意间隔为1.0。像这样:
assert(abs(sum - 1.0) > 0.0001)
<强>更新强>
在使用gcc和MSC ++进行打印时,我无法重现您报告的行为,所以我所能做的只是一个微弱的猜测。构建代码时,编译器将在优化阶段对其进行修改。您要求在两个位置计算Tolmin+Tolmax
,首先在cout中,第二个在assert中,因此编译器将推断此计算可以执行一次,然后重用它的结果。当cout改变你要显示的数字,并且值非常接近1时,它将被舍入并获得精确值1,然后结果将在断言中重用。可能是这种情况,我无法确认,因为我无法重现报告的行为。