How to access individual pixels in OpenCV 2.3 using C++?
For my U8C3 image I tried this:
Scalar col = I.at<Scalar>(i, j);
and
p = I.ptr<uchar>(i);
First is throwing an exception, the second one is returning some unrelated data. Also all examples I was able to find are for old IIPimage(?) for C version of OpenCV.
All I need is to get color of pixel at given coordinates.
The type you call cv::Mat::at with needs to match the type of the individual pixels. Since cv::Scalar is basically a cv::Vec<double,4>, this won't work for a U8C3 image (it would work for a F64C4 image, of course).
In your case you need a cv::Vec3b, which is a typedef for cv::Vec<uchar,3>:
Vec3b col = I.at<Vec3b>(i, j);
You can then convert this into a cv::Scalar if you really need to, but the type of the cv::Mat::at instantiation must match the type of your image, since it just casts the image data without any conversions.
Your second code snippet returns a pointer to the ith row of the image. It is no unrelated data, but just a pointer to single uchar values. So in case of a U8C3 image, every consecutive 3 elements in the data returned to p should represent one pixel. Again, to get every pixel as a single element use
Vec3b *p = I.ptr<Vec3b>(i);
which again does nothing more than an appropriate cast of the row pointer before returning it.
EDIT: If you want to do many pixel accesses on the image, you can also use the cv::Mat_ convenience type. This is nothing more than a typed thin wrapper around the image data, so that all accesses to image pixels are appropriately typed:
Mat_<Vec3b> &U = reinterpret_cast<Mat_<Vec3b>&>(I);
You can then freely use U(i, j) and always get a 3-tuple of unsigned chars and therefore pixels, again without any copying, just type casts (and therefore at the same performance as I.at<Vec3b>(i, j)).
Related
Hi the context in which I need help is as follows. I construct a vector of rgb values (one rgb value is an UInt32) and i want to put them as fast as possible in a QImage preferably without setPixel as it is very slow. To take the first rgb value and put it at [0,0] in the image, next value at [0,1] and so on. Can anyone help me with this?
This QImage constructor is what you need. The trick is only in choosing right Format. I guess in your case it would be QImage::Format_RGB32.
So try:
std::vector<int32_t> pixels{/*init or fill-up your data*/};
int width = 42, height = 42; // your valid values here
// what you're interesting in
auto image(Qimage((uchar *)pixels.data(), width, height, QImage::Format_RGB32));
This approach is the fastest possible way - the pixels will not be copied, but original buffer will be used internally by QImage.
If you're going to render your image later with QPainter::drawImage, don't forget to pass Qt::NoFormatConversion as a flag - this will improve your app performance.
Currently I am trying to understand the OpenCV's face detection API DetectionBasedTracker. Inside the code, I found the definition
#define CALC_SUM_(p0, p1, p2, p3, offset) \
((p0)[offset] - (p1)[offset] - (p2)[offset] + (p3)[offset])
I can't figure out the followings
(1)p0, p1, p2, p3 are integer values. What is the return value of (p0)[offset] and what does it do?
(2)Actually offset is the number of integers in one row of image matrix. Say if image matrix is 480 x 640. There are 640 integer values in one row of image data. Say for the second row, offset = 640. It is calculated as offset = pt.y * ((int)image.step/sizeof(int)) + pt.x; By changing the offset value, how (p0)[offset]has effect?
My guess is that p0 is not an integer, but rather a one-dimensional array.
If that is correct, the macro would be calculating the "sum" of the offsetth items in arrays p0, p1, p2, and p3, except that it's a strange sum because of all those - signs.
Edited: having now looked at the code in question
I find the code hard to follow, but let's try anyway:
My conclusion is that p0[offset] is a pointer to a pixel in an image (an integer value). That pixel is one corner of a rectangle in the image. p1[offset], p2[offset], and p3[offset] are pointers to the pixels at the other corners of the same rectangle.
In more detail...
CALC_SUM_ is called by CALC_SUM which is called in a lot of places, such as in HaarEvaluator::Feature :: calc.
In that calc function, CALC_SUM is called with p[0] as an argument. p is defined in struct Feature as const int* p[RECT_NUM][4], so p[0] is an array of four pointers to ints.
What might these four ints be? Well, they are undefined immediately after the Feature constructor is called, since the pointers are set to be NULL.
But assuming HaarEvaluator::Feature :: updatePtrs has been called at some point, the pointers are updated by the CV_TILTED_PTRS or CV_SUM_PTRS macros.
Both of those macros take a pointer to a matrix of values, which I assume is a matrix of pixels in an image (given the task at hand, which is finding a feature in an image). That pointer is called titled or sum. Let's work with sum. The four pointers in p[0] are set by CV_SUM_PTRS to point to four corners of a rectangle within sum.
When the calc function is called, the four pointers (p[0] contains the four pointers to corners p[0][0]-p[0][3]) are passed in along with an offset. This offset is effectively added to each of the four pointers, using array notation, which shifts the rectangle around the image.
The actual sum looks like it could be doing the fast computation described here.
A Mat can be CV_8UC3, CV_8UC1, CV_32FC3 and etc. For example, for a Mat which is CV_8UC3, I can set a pointer: Vec3b *p to the Mat. However, If I only know the Mat's datatype which can be obtained using Mat.type(), How can I set a proper pointer?
The sad answer is: you can't. The type of data should be set in compilation time. But in your example actual type will be decided only during run time. You will have to put switch somewhere in your code. i.e. you will need to have different implementations of your algorithm for all possible types. Note however that you can prevent code duplication by using templates.
If you do know type of data, and the only thing you don't know is number of channels, then the problem is a bit simpler. For example if your image contains unsigned char you can write
uchar* p = img.ptr<uchar>();
And it doesn't matter whether your image have one channel or three. Of course when it comes to actually working with the pixels you do need this information.
Use a void pointer. Void pointers can point to any data type.
http://www.learncpp.com/cpp-tutorial/613-void-pointers/
If you know a type, you can set a pointer to the first element of the first row of cv::Mat using ptr (documentation)
cv::Mat matrix = cv::Mat::zeros(3, 3, CV_32F);
float* firstElement = matrix.ptr<float>(0);
I am translating some matlab code to c++ using opencv. I want to get the values of a Matrix which satisfies a condition. I created a mask for this and when I apply it to the original Matrix I get the same size of the original matrix but with 0 values which are not there in the mask. But my question is how can I get only the values that are non-zero in the matrix and assign it to a different matrix.
My matlab code is:
for i= 1:size(no,1)
mask= labels==i;
op = orig(mask, :); //op only contains the values from the orig matrix which are in the mask. So orig size and op size is not the same
.....
end
The c++ translation that I have now is:
for (int i=0; i<n.rows; i++)
{
Mat mask;
compare(labels,i,mask,CMP_EQ);
Mat op;
orig.copyTo(op,mask); //Here the orig size and the op size is always same but values which are not in the mask are 0
}
So, how can I create a matrix which only has the values that the mask satisfies???
You might try to make use of cv::SparseMat (http://docs.opencv.org/modules/core/doc/basic_structures.html#sparsemat), which only keeps non-zero values in a hash.
When you assign a regular cv::Mat to a cv::SparseMat, it automatically captures the non-zero values. From that point, you can iterate through the non-zero values and manipulate them as you'd like.
Hope I got question correctly and it helps!
OpenCv does support Matrix Expresions like A > B or A <= Band so on.
This is stated in the Documentation off cv::Mat
If you're simply wanting to store values, the Mat object is probably not the best way, since it has been made for the purpose of containing images.
In that case, use an std::vector object instead of the cv::Mat object, and you can use the .push_back handle whenever you find an element that is non-zero, which will dynamically resize the vector.
If you're trying to create a new image, then you have to be specific about what kind of image you want to see, because if you don't know how many nonzero elements there are, how can you set the width and height? Also you might end up with an odd number of elements.
I faced one time in an opencv code this expression:
Mat bimage = image >= sliderPos;
Known that sliderPos is an integer.
What does that mean please.
Thanks in advance
ADDITION: of course the type of image is cv::Mat
It is hard to tell without knowing the type of image, but according to the OpenCV documentation, I think this line converts image into a black and white image, using sliderPos as a threshold to determine which pixels will be black.
From the OpenCV documentation about matrices:
Comparison: A cmpop B, A cmpop alpha, alpha cmpop A, where cmpop is
one of : >, >=, ==, !=, <=, <. The result of comparison is an 8-bit
single channel mask whose elements are set to 255 (if the particular
element or pair of elements satisfy the condition) or 0.
The expression
Mat bimage = image >= sliderPos;
tests whether image is larger or equal to sliderPos (which usually yields a bool) and assigns the result of the test to the newly created variable bimage of type Mat.
If the >= operator is overloaded for (decltype(image), int), it might not yield a bool. If this is the case, look in the documentation of the type of image for details. In any case, it yields something, from wich a Mat can be constructed.