Reputation: 33
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
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
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);
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
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