在cv::Mat对象上循环时,内存位置出现cv::异常
cv::Exception at memory location while looping over cv::Mat object
我创建了一个零值的空矩阵hide_image
。尺寸正确-672x896。每个元素都应该填充值,我在循环中执行。但在(0, 299)
元素上,代码抛出了一个异常:
Unhandled exception at 0x00007FFD3C063C58 in stego.exe: Microsoft C++ exception: cv::Exception at memory location 0x000000D2B033E5F0. occurred
我调试了这个函数,发现异常取决于循环中的j值。我可以设置j<299和程序将毫无问题地工作,但我需要所有矩阵。在命令行中,我看到以下消息:
OpenCV Error: Assertion failed ((unsigned)(i1 * DataType<_Tp>::channels) <
(unsigned)(size.p[1] * channels())) in cv::Mat::at, file c:opencv-
3.3.1opencvbuildincludeopencv2coremat.inl.hpp, line 1095
这可能是因为矩阵初始化错误,但为什么会显示正确的维度?行是正确的数字,并且如果我设置j<298,循环结束于i=671。但是列数较少,而且数字299似乎不依赖于任何东西。
cv::Mat hide_image;
int hide_image_cols = 0, hide_image_rows = 0;
int i_current = 0, j_current = 15;
int curr_bit = 0;
get_img_dim(image, hide_image_cols, hide_image_rows);
hide_image = cv::Mat(hide_image_rows, hide_image_cols, CV_8U);
hide_image = cv::Mat::zeros(hide_image_rows, hide_image_cols, CV_8U);
std::cout << (hide_image.at<cv::Vec3b>(671, 299)) << std::endl; // exception
for (int i = 0; i < hide_image.rows; i++)
for (int j = 0; j < hide_image.cols; j++) {
//exception when j>298
std::cout << (hide_image.at<cv::Vec3b>(i, j)) << std::endl;
}
为什么会出现此异常?
您使用不同的类型来初始化和循环矩阵。。。
在初始化期间,您使用CV_8U
,它是一个8位像素表示(一个通道)。
hide_image = cv::Mat(hide_image_rows, hide_image_cols, CV_8U);
hide_image = cv::Mat::zeros(hide_image_rows, hide_image_cols, CV_8U);
然后使用Vec3b
,即每像素24位(相当于CV_8UC3
)。因此,它将以3倍的速度传导数据,然后你就没有数据了,势必会发生分割错误。
for (int i = 0; i < hide_image.rows; i++)
for (int j = 0; j < hide_image.cols; j++) {
//exception when j>298
std::cout << (hide_image.at<cv::Vec3b>(i, j)) << std::endl;
}
你能做什么:
用CV_8UC3
而不是CV_8U
初始化,或者用uchar
而不是Vec3b
初始化。
BTW,这条线路
hide_image = cv::Mat(hide_image_rows, hide_image_cols, CV_8U);
如果你做下一行
hide_image = cv::Mat::zeros(hide_image_rows, hide_image_cols, CV_8U);
问题在于矩阵数据类型和访问元素的方式。
初始化Mat
时,如果未指定通道数,则OpenCV默认为单个通道。这意味着,如果您指定了数据类型CV_8U
,那么hide_image
的类型将是CV_8UC1
。
在循环中,使用数据类型cv::Vec3b
访问矩阵元素,该数据类型假定矩阵为CV_8UC3
类型。因此,在您的情况下,通过一次跳3个字节而不是预期的1个字节来迭代矩阵。
在这种情况下,数字299
实际上在破坏代码方面起着重要作用。矩阵中的列数等于896。代码应该一直工作到索引298,因为298*3=894并且索引894对应于hide_image
的有效内存地址。当j
为299时,循环将尝试访问299*3=897,这将导致内存访问越界。
因此,该场景的解决方案是确保初始化和元素访问的数据类型相同。因此,以下任何一项都应该有效。
创建具有3个通道的输入矩阵。
hide_image = cv::Mat::zeros(hide_image_rows, hide_image_cols, CV_8UC3);
或
访问具有正确数据类型的单通道矩阵元素,如下所示:
std::cout << (hide_image.at<unsigned char>(i, j)) << std::endl;
正确答案不完整,即使初始化和元素访问的数据类型相同,如果使用以下代码,您仍将面临此问题
std::cout << (hide_image.at<cv::Vec3b>(i, j)) << std::endl;
但我们将不得不使用以下代码
std::cout << (hide_image.at<cv::Vec3b>(j,i)) << std::endl;
因此访问Mat值的正确方式是mat.at<data type>(column,row)
而不是mat.at<data type>(row,column)
- 将值指定给向量(2D)的向量中的某个位置
- 使用Unreal C++获取VR耳机的世界位置/方向
- 写入位置0x0000000C时发生访问冲突
- 将"打开的CV图像"中的"颜色"转换为整数格式
- 如何将两个不同矢量的同一位置的两个元素组合在一起
- GL_SHADERSTORAGE_BUFFER位置是否与其他着色器位置冲突
- 概念中的cv限定符需要表达式参数列表
- 如何使用cudaMallocManaged在指针位置初始化对象?(C++)
- 无法获取webot::PositionSensor对象中位置传感器的值
- 非常量变量只读位置的赋值
- 如何定义更改car类中car位置的方法
- 使用迭代器时如何访问对象在向量中的位置?
- 在旋转 cv::Mat 而不裁剪后,将 cv::RotatedRect 移动到相同的位置
- cv:内存位置的异常 - 运行 openCV 代码 Visual Studio 2013 & Visual Studio 2017 - Windows 7
- cv::内存位置出现异常错误
- 在cv::Mat对象上循环时,内存位置出现cv::异常
- 相机在世界坐标中的位置来自 cv::solvePnP
- 如何修改cv::Mat类(16UC1)中某个位置的值
- 当cv::minMaxLoc返回点(-1,-1)作为最小和最大位置时,这意味着什么?
- Opencv PCA Microsoft c++ exception: cv::内存位置异常