Accessing elements of a cv::Mat with atfloat(i, j). Is it (x,y) or (row,col)?
OpenCV, like may other libraries, treat matrices (and images) in row-major order. That means every access is defined as (row, column)
.
Notable exceptions from this general rule are Matlab and Eigen libraries.
Accessing a matrix element in the Mat object (not the CvMat object) in OpenCV C++
On the documentation:
http://docs.opencv.org/2.4/modules/core/doc/basic_structures.html#mat
It says:
(...) if you know the matrix element
type, e.g. it is float, then you can
use at<>() method
That is, you can use:
Mat M(100, 100, CV_64F);
cout << M.at<double>(0,0);
Maybe it is easier to use the Mat_
class. It is a template wrapper for Mat
. Mat_
has the operator()
overloaded in order to access the elements.
opencv multi channel element access
typedef struct elem_ {
float f1;
float f2;
} elem;
elem data[9] = { 0.0f };
CvMat mat = cvMat(3, 3, CV_32FC2, data );
float f1 = CV_MAT_ELEM(mat, elem, row, col).f1;
float f2 = CV_MAT_ELEM(mat, elem, row, col).f2;
CV_MAT_ELEM(mat, elem, row, col).f1 = 1212.0f;
CV_MAT_ELEM(mat, elem, row, col).f2 = 326.0f;
Update : for OpenCV2.0
1. choose one type to represent the element
Mat (or CvMat) has 3 dimensions: row, col, channel.
We can access one element (or pixel) in the matrix by specifying the row and col.
CV_32FC2
means the element is 32bit floating point value with 2 channels.
So elem in above code is one acceptable representation of CV_32FC2
.
You can use other representations you like. For example :
typedef struct elem_ { float val[2]; } elem;
typedef struct elem_ { float x;float y; } elem;
OpenCV2.0 adds some new types to represent the element in the matrix,like :
template<typename _Tp, int cn> class CV_EXPORTS Vec // cxcore.hpp (208)
So we can use Vec<float,2>
to represent CV_32FC2
, or use :
typedef Vec<float, 2> Vec2f; // cxcore.hpp (254)
See the source code to get more type that can represent your element.
Here we use Vec2f
2. access the element
The easiest and efficiant way to access the element in the Mat class is Mat::at.
It has 4 overloads :
template<typename _Tp> _Tp& at(int y, int x); // cxcore.hpp (868)
template<typename _Tp> const _Tp& at(int y, int x) const; // cxcore.hpp (870)
template<typename _Tp> _Tp& at(Point pt); // cxcore.hpp (869)
template<typename _Tp> const _Tp& at(Point pt) const; // cxcore.hpp (871)
// defineded in cxmat.hpp (454-468)
// we can access the element like this :
Mat m( Size(3,3) , CV_32FC2 );
Vec2f& elem = m.at<Vec2f>( row , col ); // or m.at<Vec2f>( Point(col,row) );
elem[0] = 1212.0f;
elem[1] = 326.0f;
float c1 = m.at<Vec2f>( row , col )[0]; // or m.at<Vec2f>( Point(col,row) );
float c2 = m.at<Vec2f>( row , col )[1];
m.at<Vec2f>( row, col )[0] = 1986.0f;
m.at<Vec2f>( row, col )[1] = 326.0f;
3. interact with old interface
Mat provides 2 conversion functions:
// converts header to CvMat; no data is copied // cxcore.hpp (829)
operator CvMat() const; // defined in cxmat.hpp
// converts header to IplImage; no data is copied
operator IplImage() const;
// we can interact a Mat object with old interface :
Mat new_matrix( ... );
CvMat old_matrix = new_matrix; // be careful about its lifetime
CV_MAT_ELEM(old_mat, elem, row, col).f1 = 1212.0f;
Accessing elements of cv::Mat
char value = mask.at<char>(pt);
OpenCV Error: Assertion failed / when visit the pixel of mat
You're doing two things wrong:
- You image is grayscale (
uchar
), so you need to access it with.at<uchar>(...)
You are accessing the image as
(col, row)
, while the OpenCV (and any matrix-related) convention is(row, col)
. You can also use mnemonics in your iteration:r
andc
for row and col respectively.for(int r=0; r<dst.rows; r++) {
for( c=0; c<dst.cols; c++){
dstSum += dst.at<uchar>(r, c);
}
}
You can also improve your code a little:
You can use
Mat1b
and access it likeat(i,j)
Mat1b dst = imread(...);
for(int r=0; r<dst.rows; r++) {
for( c=0; c<dst.cols; c++){
dstSum += dst(r, c);
}
}The new OpenCV name is
IMREAD_GRAYSCALE
:Mat1b dst = imread("path_to_image", IMREAD_GRAYSCALE);
You can use
cv::sum
to sum up all the pixels. The resulting improved code will be:Mat1b dst = imread("path_to_image", IMREAD_GRAYSCALE);
int dstSum = sum(dst)[0]; // take only first channel
opencv Mat memory access error
Um... Never mind. It turned out that the exception was real and not a problem with this code. I am using sample code from Point Grey. It converts from a Point Grey ImagePtr to a Mat using a Mat constructor that just copies the pointer to the data. The ImagePtr went out of scope, so the data was invalid when I attempted to use it. Mat.CopyTo() solved the problem. I highly recommend reading this if you need a fast way to solve a similar problem.
Convert Mat to Array/Vector in OpenCV
If the memory of the Mat mat
is continuous (all its data is continuous), you can directly get its data to a 1D array:
std::vector<uchar> array(mat.rows*mat.cols*mat.channels());
if (mat.isContinuous())
array = mat.data;
Otherwise, you have to get its data row by row, e.g. to a 2D array:
uchar **array = new uchar*[mat.rows];
for (int i=0; i<mat.rows; ++i)
array[i] = new uchar[mat.cols*mat.channels()];
for (int i=0; i<mat.rows; ++i)
array[i] = mat.ptr<uchar>(i);
UPDATE: It will be easier if you're using std::vector
, where you can do like this:
std::vector<uchar> array;
if (mat.isContinuous()) {
// array.assign(mat.datastart, mat.dataend); // <- has problems for sub-matrix like mat = big_mat.row(i)
array.assign(mat.data, mat.data + mat.total()*mat.channels());
} else {
for (int i = 0; i < mat.rows; ++i) {
array.insert(array.end(), mat.ptr<uchar>(i), mat.ptr<uchar>(i)+mat.cols*mat.channels());
}
}
p.s.: For cv::Mat
s of other types, like CV_32F
, you should do like this:
std::vector<float> array;
if (mat.isContinuous()) {
// array.assign((float*)mat.datastart, (float*)mat.dataend); // <- has problems for sub-matrix like mat = big_mat.row(i)
array.assign((float*)mat.data, (float*)mat.data + mat.total()*mat.channels());
} else {
for (int i = 0; i < mat.rows; ++i) {
array.insert(array.end(), mat.ptr<float>(i), mat.ptr<float>(i)+mat.cols*mat.channels());
}
}
UPDATE2: For OpenCV Mat data continuity, it can be summarized as follows:
- Matrices created by
imread()
,clone()
, or a constructor will always be continuous. - The only time a matrix will not be continuous is when it borrows data (except the data borrowed is continuous in the big matrix, e.g. 1. single row; 2. multiple rows with full original width) from an existing matrix (i.e. created out of an ROI of a big mat).
Please check out this code snippet for demonstration.
Related Topics
Generating One Class Member Per Variadic Template Argument
Glpixelstorei(Gl_Unpack_Alignment, 1) Disadvantages
Is It Safe to Read an Integer Variable That's Being Concurrently Modified Without Locking
How to Use Threads to Speed Up File Reading
Should C++ Eliminate Header Files
Large 2D Array Gives Segmentation Fault
Forcing MAChine to Use Dedicated Graphics Card
What Is a Good Easy to Use Profiler for C++ on Linux
Writing Python Bindings for C++ Code That Use Opencv
Findchessboardcorners Cannot Detect Chessboard on Very Large Images by Long Focal Length Lens
"Roll-Back" or Undo Any Manipulators Applied to a Stream Without Knowing What the Manipulators Were
Why Do Linked Lists Use Pointers Instead of Storing Nodes Inside of Nodes