In the following code I would like to assign a values to elements of a Mat variable in a loop. I get the runtime error below.
pair<Mat, Mat> meshgrid(vector<int> x, vector<int> y) {
int sx = (int)x.size();
int sy = (int)y.size();
Mat xmat = Mat::ones(sy, sx, CV_16U);
Mat ymat = Mat::ones(sy, sy, CV_16U);
for (int i = 0; i < sx; i ) {
for (int j = 0; j < sy; j ) {
xmat.at<int>(i, j) = j; // <------- here is place of error.
cout << j << "\t";
}
cout << endl;
}
for (int i = 0; i < sx; i ) {
for (int j = 0; j < sy; j ) {
ymat.at<int>(i, j) = i; // <------- here is place of error.
cout << j << "\t";
}
cout << endl;
}
return make_pair(xmat, ymat);
}
This picture when debuging;
This is the run time error I get:
OpenCV(...) Error: Assertion failed
(((((sizeof(size_t)<<28)|0x8442211) >> ((traits::Depth<_Tp>::value) &
((1 << 3) - 1))*4) & 15) == elemSize1()) in cv::Mat::at, file
...\include\opencv2\core\mat.inl.hpp, line 1108
Thank you for your answers.
CodePudding user response:
I assume you meant to generate output similar to numpy.meshgrid
, and Matlab meshgrid
.
There are several errors in your code:
- The
cv::Mat
is initialized with type CV_16U (i.e. 16 bit unsigned value), but when you access the elements withat
you useint
(which is 32bit signed). You should change it toat<unsigned short>
(or change the type of thecv::Mat
to 32 bit signed -CV_32S
). - You initialized the
cv::Mat
with wrong sizes:xmat
has size of(sy, sx)
, butymat
has size of(sy, sy)
. - The indices (row, col) you used to access the mat elements were incorrect. To make it easier to use correctly, I changed the names of the dimentions to
rows
,cols
, and the loop indices toiRow
,iCol
. - The values in the matrices should come from the values in
x
andy
vectors (not the indices).
See updated code below (and the notes following it regarding the changes):
#include <opencv2/core/core.hpp>
#include <vector>
#include <iostream>
std::pair<cv::Mat, cv::Mat> meshgrid(std::vector<unsigned short> const & x, std::vector<unsigned short> const & y)
{
int cols = static_cast<int>(x.size());
int rows = static_cast<int>(y.size());
cv::Mat xmat(rows, cols, CV_16U);
cv::Mat ymat(rows, cols, CV_16U);
for (int iRow = 0; iRow < rows; iRow) {
auto * pRowData = xmat.ptr<unsigned short>(iRow);
for (int iCol = 0; iCol < cols; iCol) {
pRowData[iCol] = x[iCol];
std::cout << pRowData[iCol] << "\t";
}
std::cout << std::endl;
}
std::cout << std::endl;
for (int iRow = 0; iRow < rows; iRow) {
auto * pRowData = ymat.ptr<unsigned short>(iRow);
for (int iCol = 0; iCol < cols; iCol) {
pRowData[iCol] = y[iRow];
std::cout << pRowData[iCol] << "\t";
}
std::cout << std::endl;
}
return std::make_pair(std::move(xmat), std::move(ymat));
}
int main()
{
std::vector<unsigned short> xxx{ 1,2 };
std::vector<unsigned short> yyy{ 10,11,12 };
auto p = meshgrid(xxx, yyy);
return 0;
}
Output:
1 2
1 2
1 2
10 10
11 11
12 12
Some notes:
- I might have misunderstood which values you wanted to set in the
cv::Mat
's. But at least now you have code that does not crash. You can change the assigned values as you wish. - Using
at
to accesscv::Mat
elements one after the other is very inefficient, becauseat
contains some validations for every access. It's a lot more efficient to use thecv::Mat
methodptr
, that gives you a pointer to the data of a row. Then you can use this pointer to traverse the row more efficiently - see above - In any method, it is more efficient to traverse a
cv::Mat
one row after another (and not column by column). This causes you to access continous memory, and decrease the number of cache misses. - In your real code, it's better to separate calculations from I/O. Therefore it's better if your
meshgrid
function will only create the matrices. Print them outside if you need. - No need to initialize the
cv::Mat
s to ones, because immediatly afterwards we set the values for all elements. - In my code
x
andy
are passed to the function by const refernce. It is more efficient (avoid copy) and also forces the compiler to verify the vectors are not modified. - Better to avoid
using namespace std
- see here Why is "using namespace std;" considered bad practice?. From similar reasons I recomend to avoidusing namespace cv
as well.