la Gorda
la Gorda

Reputation: 33

cv::Exception at memory location while looping over cv::Mat object

I create an empty matrix hide_image with zero values. Dimentions are right - 672x896. Each element should be filled with value, I do it in loop. But on (0, 299) element code throw an exception:

Unhandled exception at 0x00007FFD3C063C58 in stego.exe: Microsoft C++ exception: cv::Exception at memory location 0x000000D2B033E5F0. occurred

I debugged the function and found out that exceptions depend of j value in loop. I can set j<299 and program will work without problems, but I need all matrix. In command line I see this message:

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

May be it happens because of wrong matrix initialisation, but why there's shown right dimentions? Rows are right number and if I set j<298, loop ends on i=671. But columns are less and it seems that number 299 does not depend on anything.

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;
}

Why this exception occurs?

Upvotes: 3

Views: 897

Answers (3)

Shaikh Chili
Shaikh Chili

Reputation: 109

Correct answer is not complete,even if the data types of initialization and element access are same still you will face this issue if you are using the following code

std::cout << (hide_image.at<cv::Vec3b>(i, j)) << std::endl;

but instead we will have to use following code

std::cout << (hide_image.at<cv::Vec3b>(j,i)) << std::endl;

so correct way of accessing values for Mat is mat.at<data type>(column,row) not mat.at<data type>(row,column)

Upvotes: 0

sgarizvi
sgarizvi

Reputation: 16796

The problem is with the matrix data-type and the way you are accessing the elements.

When initializing the Mat, if number of channels is not specified, OpenCV assumes single channel by default. It means that if you have specified data-type CV_8U, then hide_image will be of type CV_8UC1.

In the loop, matrix elements are being accessed using data-type cv::Vec3b which assumes that the matrix is of type CV_8UC3. So in your case, you are iterating over the matrix by jumping 3 bytes at a time instead of the intended 1 byte.

In this scenario, the number 299 does in-fact play an important role in crashing the code. The number of columns in the matrix is equal to 896. The code should work up-to index 298 because 298 * 3 = 894 and index 894 corresponds to a valid memory address for hide_image. When j is 299, the loop will try to access 299 * 3 = 897 which will result in out-of-bound memory access.

So the solution for this scenario will be to make sure the data types of initialization and element access are same. So either of the following should work.

Create the input matrix with 3 channels.

hide_image = cv::Mat::zeros(hide_image_rows, hide_image_cols, CV_8UC3);

OR

Access the elements with correct data-type for single channel matrix like this:

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

Upvotes: 2

api55
api55

Reputation: 11420

You are using different types to initialize and loop through the matrix...

During initialization you use CV_8U which is an 8 bit pixel representation (one channel).

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);

Then you use Vec3b which is a 24 bit per pixel (equivalent to CV_8UC3). So it will condume the data 3 times faster, and then you are out of data and a segmentation error is bound to happen.

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;
  }

What can you do:

Initialize with CV_8UC3 instead of CV_8U or use uchar instead of Vec3b.

BTW, this line

hide_image = cv::Mat(hide_image_rows, hide_image_cols, CV_8U);

is unnecessary if you do the next line

hide_image = cv::Mat::zeros(hide_image_rows, hide_image_cols, CV_8U);

Upvotes: 3

Related Questions