'assert' 函数:奇怪的行为
'assert' function : weird behavior
我正在使用 Qt Creator 在 C++ 中开发 Windows 7。
我也使用库 OpenCV
我遇到了函数 assert
的一个奇怪问题。
我开发了一个函数,可以对图像进行线性变换以获得更好的对比度,可以指定我们要处理的图像的区域 (x1,x2,y1,y2) 以及公差 (Tolmin和 Tolmax) :我们要忽略的直方图的百分位数。
我需要确保:
- 图片为16位灰度(img.type()=CV_16U && img.channels()=1)
- 区域坐标正确(正数,不要超过图像大小...)
- Tolmin,Tolmax positive and 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)。
可以肯定的是,我在 assert
调用之前打印了 Tolmin+Tolmax
。
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 中重复使用。是否如此,我无法确认,因为我无法重现报告的行为。
我正在使用 Qt Creator 在 C++ 中开发 Windows 7。 我也使用库 OpenCV
我遇到了函数 assert
的一个奇怪问题。
我开发了一个函数,可以对图像进行线性变换以获得更好的对比度,可以指定我们要处理的图像的区域 (x1,x2,y1,y2) 以及公差 (Tolmin和 Tolmax) :我们要忽略的直方图的百分位数。
我需要确保:
- 图片为16位灰度(img.type()=CV_16U && img.channels()=1)
- 区域坐标正确(正数,不要超过图像大小...)
- Tolmin,Tolmax positive and 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)。
可以肯定的是,我在 assert
调用之前打印了 Tolmin+Tolmax
。
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 中重复使用。是否如此,我无法确认,因为我无法重现报告的行为。