cv ::在循环cv :: Mat对象时在内存位置的异常

时间:2017-11-09 09:11:18

标签: c++ opencv

我创建一个零值的空矩阵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.1\opencv\build\include\opencv2\core\mat.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;
}

为什么会发生此异常?

3 个答案:

答案 0 :(得分:3)

您正在使用不同类型初始化并循环遍历矩阵...

在初始化期间,您使用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);

答案 1 :(得分:2)

问题在于矩阵数据类型和访问元素的方式。

初始化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);

OR

使用正确的数据类型访问单个通道矩阵的元素,如下所示:

std::cout << (hide_image.at<unsigned char>(i, j)) << std::endl;

答案 2 :(得分:0)

正确的答案还是不完整的,即使初始化和元素访问的数据类型相同,如果使用以下代码,您仍然会遇到此问题

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)

相关问题