学习《OpenCV应用开发:入门、进阶与工程化实践》一书
做真正的OpenCV开发者,从入门到入职,一步到位!
引言:
今天有个课程学员跟我说OpenCV中的Mat遍历访问像素的方法,说他没有检查越界一样可以用,问我是不是OpenCV的Mat有自动的像素越界检查,我印象中是没有的,但是又不敢太肯定,所以就测试了一下。
索引方式遍历测试
使用at方式根据行跟列的索引遍历访问每个像素点,然后我故意从负数开始遍历,我要看看at给我的结果到底是什么?测试代码如下:
std::cout << "height: " << image.rows << " width: " << image.cols << std::endl;
for (int row = 0; row < 1000; row++) {
for (int col = -1; col < 1000; col++) {
cv::Vec3b bgr = image.at<cv::Vec3b>(row, col);
if (col < 1) {
std::cout << " col index: " << col << " bgr ( " << bgr << std::endl;
}
}
}
输入图像时512x512大小,我故意写成1000x1000,发现是可以执行的,而且不报任何错误跟提示,运行结果如下:

但是我发现当我把代码改成下面这个样子的时候,它会给我报错:

说明通过at获取像素的时候,行号负数,它就崩溃了。但是超过图像边界大小并不会导致程序崩溃,只是会获取一堆乱七八糟的像素值。 然后把代码改成下面这个样子,不光是遍历访问像素值,还赋值给对应的像素点,这个时候行跟列索引超过512的时候,它就直接崩溃了,图示如下:

指针方式遍历测试
使用行指针方式遍历像素,获取每个像素点像素值,同样我也故意在遍历的时候多遍历一行与一列,要看看指针数据给我输出的到底是什么?测试代码如下:
std::cout << "height: " << image.rows << " width: " << image.cols << std::endl;
for (int row = 0; row < image.rows; row++) {
uchar* rowData = image.ptr<uchar>(row);
for (int col = 0; col < image.cols+1; col++) {
cv::Vec3b bgr = image.at<cv::Vec3b>(row, col);
int b = *rowData++;
int g = *rowData++;
int r = *rowData++;
if (col >= image.cols) {
std::cout <<"out boundary width: "<<col<<" >> "<< b << " , " << g << " , " << r << std::endl;
}
image.at<cv::Vec3b>(row, col) = cv::Vec3b(255 - b, 255 - g, 255 - r);
}
}
代码运行结果如下:

可以看出越界访问并不影响并不影响赋值,最后我发现其实row跟col超过索引 一样可以赋值,而且不会出错,但是当遇到这种值得时候它会随机挂,原因我也没有琢磨清楚,我猜测可能越界访问,然后有内存地址访问得冲突导致,因为看像素值还正常。


结论
千万不要指望OpenCV中得Mat来给你做任何越界检查,这些你都必须自己完成!用OpenCV开发得算法,一旦莫名其妙毫无理由得崩溃,首先查找越界问题。
学习《OpenCV应用开发:入门、进阶与工程化实践》一书
做真正的OpenCV开发者,从入门到入职,一步到位!
2138

被折叠的 条评论
为什么被折叠?



