OpenCV get pixel channel value from Mat image - c++

Maybe I'm not looking hard enough, but everything seems to want me to use an array. Thus, how do I get the channel value for a particular pixel for foo if foo is something like Mat foo = imread("bar.png")?

Assuming the type is CV_8UC3 you would do this:
for(int i = 0; i < foo.rows; i++)
{
for(int j = 0; j < foo.cols; j++)
{
Vec3b bgrPixel = foo.at<Vec3b>(i, j);
// do something with BGR values...
}
}
Here is the documentation for Vec3b. Also, don't forget OpenCV stores things internally as BGR not RGB.
EDIT :
For performance reasons, you may want to use direct access to the data buffer in order to process the pixel values:
Here is how you might go about this:
uint8_t* pixelPtr = (uint8_t*)foo.data;
int cn = foo.channels();
Scalar_<uint8_t> bgrPixel;
for(int i = 0; i < foo.rows; i++)
{
for(int j = 0; j < foo.cols; j++)
{
bgrPixel.val[0] = pixelPtr[i*foo.cols*cn + j*cn + 0]; // B
bgrPixel.val[1] = pixelPtr[i*foo.cols*cn + j*cn + 1]; // G
bgrPixel.val[2] = pixelPtr[i*foo.cols*cn + j*cn + 2]; // R
// do something with BGR values...
}
}
Or alternatively:
int cn = foo.channels();
Scalar_<uint8_t> bgrPixel;
for(int i = 0; i < foo.rows; i++)
{
uint8_t* rowPtr = foo.row(i);
for(int j = 0; j < foo.cols; j++)
{
bgrPixel.val[0] = rowPtr[j*cn + 0]; // B
bgrPixel.val[1] = rowPtr[j*cn + 1]; // G
bgrPixel.val[2] = rowPtr[j*cn + 2]; // R
// do something with BGR values...
}
}

The below code works for me, for both accessing and changing a pixel value.
For accessing pixel's channel value :
for (int i = 0; i < image.cols; i++) {
for (int j = 0; j < image.rows; j++) {
Vec3b intensity = image.at<Vec3b>(j, i);
for(int k = 0; k < image.channels(); k++) {
uchar col = intensity.val[k];
}
}
}
For changing a pixel value of a channel :
uchar pixValue;
for (int i = 0; i < image.cols; i++) {
for (int j = 0; j < image.rows; j++) {
Vec3b &intensity = image.at<Vec3b>(j, i);
for(int k = 0; k < image.channels(); k++) {
// calculate pixValue
intensity.val[k] = pixValue;
}
}
}
`
Source : Accessing pixel value

The pixels array is stored in the "data" attribute of cv::Mat. Let's suppose that we have a Mat matrix where each pixel has 3 bytes (CV_8UC3).
For this example, let's draw a RED pixel at position 100x50.
Mat foo;
int x=100, y=50;
Solution 1:
Create a macro function that obtains the pixel from the array.
#define PIXEL(frame, W, x, y) (frame+(y)*3*(W)+(x)*3)
//...
unsigned char * p = PIXEL(foo.data, foo.rols, x, y);
p[0] = 0; // B
p[1] = 0; // G
p[2] = 255; // R
Solution 2:
Get's the pixel using the method ptr.
unsigned char * p = foo.ptr(y, x); // Y first, X after
p[0] = 0; // B
p[1] = 0; // G
p[2] = 255; // R

Related

Copying R8G8B8A8 image to R8G8B8

I'm trying to convert an R8G8B8A8 image to R8G8B8 image, what I get right now is an image, but with a lot of scan lines, I have byters per pixels is 4 bytes, 32bit.
The image buffer is of type unsigned char [width*height*4] that's the source and the destination is unsigned char [width*height*3].
int j = 0;
int i = 0;
for (int k = 0; k < (width*height); k++)
{
for(int b = 0; b < 3; b++)
{
dst[i + b] = src[j + b];
}
i+=3;
j+=4;
}
Probably the destination image requires lines aligned on a 4 bytes boundary:
for(unsigned int y(0); y != height; ++y)
{
unsigned int sourceStart(y * width * 4);
unsigned int destStart(y * ((width * 3 + 3) & 0xfffffffc) ); // align on 4 bytes
for(unsigned int x(0); x != width; ++x)
{
for(unsigned int color(0); color != 3; ++color)
{
dst[destStart++] = src[sourceStart++];
}
++sourceStart; // account for 4th byte in source
}
}
You can do this:
for (int k = 0; k < width*height; k++)
{
for(int b = 0; b < 3; b++)
{
dst[k*3 + b] = src[k*4 + b];
}
}

variance of sliding window in image

I work on traffic sign detection, firstly I am applied a segmentation on RGB image to obtain red channel image as it is illustrated in image 1:
Secondely I try to find homogeneous region to eliminate not interested region (not a traffic sign) by calculating the variance of sliding window above the image
I use this code but I have always exception
int main(int argc, char** argv)
{
IplImage *image1;
if ((image1 = cvLoadImage("segmenter1/00051.jpg", 0)) == 0)
return NULL;
int rows = image1->width;
int cols = image1->height;
Mat image = Mat::zeros(cols, rows, CV_32FC1);
double x = 0;
double temp = 0;
for (int i = 0; i < rows; i++){
for (int j = 0; j < cols; j++){
temp = cvGet2D(image1, j, i).val[0];
x = temp / 255;
image.at<float>(j, i) = x;
x = image.at<float>(j, i);
}
}
int k = 16;
double seuil = 0.0013;
CvScalar blanc;//pixel blanc
blanc.val[0] = 255;
cv::Scalar mean, stddev; //0:1st channel, 1:2nd channel and 2:3rd channel
for (int j = 0; j < rows - k; j++)
{
for (int i = 0; i < cols - k; i++)
{
double som = 0;
double var = 0;
double t = 0;
for (int jj = j; jj < k+j; jj++)
{
for (int ii = i; ii < k+i; ii++)
{
t = image.at<float>(jj, ii);
som = som + t;
t = t*t;
var =var+ t;
}
}
som = som / (k*k);
if (som>0.18){
var = (var / (k*k)) - (som*som);
if (var < seuil)
cvSet2D(image1, j, i, blanc);
}
}
}
char stsave[80];
cvSaveImage("variance/00051.jpg", image1);
cv::waitKey(0);
return 0;
}
Without the specific exception, I can only guess it is out_of_range. According to opencv docs, cvGet2D and cvSet2D parameters are image, y, x which effectively translates to image, rows, cols. You have flipped the definition of rows, cols and have conflicting usage between the two loops. Maybe fix these and try again.

Alpha-trimmed filter troubles

I am trying to make an alphatrimmed filter in openCV library. My code is not working properly and the resultant image is not looking as image after filtering.
The filter should work in the following way.
Chossing some (array) of pixels in my example it is 9 pixels '3x3' window.
Ordering them in increasing way.
Cutting our 'array' both sides for alpha-2.
calculating arithmetic mean of remaining pixels and inserting them in proper place.
int alphatrimmed(Mat img, int alpha)
{
Mat img9 = img.clone();
const int start = alpha/2 ;
const int end = 9 - (alpha/2);
//going through whole image
for (int i = 1; i < img.rows - 1; i++)
{
for (int j = 1; j < img.cols - 1; j++)
{
uchar element[9];
Vec3b element3[9];
int k = 0;
int a = 0;
//selecting elements for window 3x3
for (int m = i -1; m < i + 2; m++)
{
for (int n = j - 1; n < j + 2; n++)
{
element3[a] = img.at<Vec3b>(m*img.cols + n);
a++;
for (int c = 0; c < img.channels(); c++)
{
element[k] += img.at<Vec3b>(m*img.cols + n)[c];
}
k++;
}
}
//comparing and sorting elements in window (uchar element [9])
for (int b = 0; b < end; b++)
{
int min = b;
for (int d = b + 1; d < 9; d++)
{
if (element[d] < element[min])
{
min = d;
const uchar temp = element[b];
element[b] = element[min];
element[min] = temp;
const Vec3b temporary = element3[b];
element3[b] = element3[min];
element3[min] = temporary;
}
}
}
// index in resultant image( after alpha-trimmed filter)
int result = (i - 1) * (img.cols - 2) + j - 1;
for (int l = start ; l < end; l++)
img9.at<Vec3b>(result) += element3[l];
img9.at<Vec3b>(result) /= (9 - alpha);
}
}
namedWindow("AlphaTrimmed Filter", WINDOW_AUTOSIZE);
imshow("AlphaTrimmed Filter", img9);
return 0;
}
Without actual data, it's somewhat of a guess, but an uchar can't hold the sum of 3 channels. It works modulo 256 (at least on any platform OpenCV supports).
The proper solution is std::sort with a proper comparator for your Vec3b :
void L1(Vec3b a, Vec3b b) { return a[0]+a[1]+a[2] < b[0]+b[1]+b[2]; }

OpenCV Mat to array access

I have problem with access to data from Mat.data. I perform operations on picture and I need access to every pixel separately.
I have to necessairly operate on simple types (float, int etc).
The way I am accesing data is like below:
for (int idx = 0; idx < image.rows; idx++) {
for (int idy = 0; idy < image.cols; idy++) {
int color_tid = idx * image.cols * image.channels() + idy * image.channels();
uint8_t blue = image.data[color_tid];
uint8_t green = image.data[color_tid + 1];
uint8_t red = image.data[color_tid + 2];
float pixelVal = (int) blue + (int) green + (int) red;
(...)
}
}
This approach is working correctly only to square images (NxN pixels), but for NxM there are anomalies outside the square area (smaller edge).
Do anyone know any other way to acces data of the picture Mat?
Example image (correct result):
anomalies (my problem)
I recommend to follow the data layout in a Mat
so your loop becomes:
for (int r = 0; r < img.rows; ++r)
{
for (int c = 0; c < img.cols; ++c)
{
uchar* ptr = img.data + img.step[0] * r + img.step[1] * c;
uchar blue = ptr[0];
uchar green = ptr[1];
uchar red = ptr[2];
float pixelVal = blue + green + red;
}
}
You can eventually perform a little less operations like:
for (int r = 0; r < img.rows; ++r)
{
uchar* pt = img.data + img.step[0] * r;
for (int c = 0; c < img.cols; ++c)
{
uchar* ptr = pt + img.step[1] * c;
uchar blue = ptr[0];
uchar green = ptr[1];
uchar red = ptr[2];
float pixelVal = blue + green + red;
}
}
The code in your question contains a few flaws:
rows and columns are swapped (row is Y, column is X)
step size between rows (aka "stride") does not always equal to the number of columns
Using Mat::at<> makes the code much simpler:
for(int row = 0; row < image.rows; ++row)
{
for(int col = 0; col < image.cols; ++col)
{
const Vec3b& pt = image.at<Vec3b>(row, col);
float pixelVal = pt[0] + pt[1] + pt[2];
...
}
}

Convert RGB image in Mat to BYTE * in MFC

Sorry for putting it out here but opencv site is down or something i cannot access the topic there. I am reading a RGB image in Mat and than trying to convert in into BYTE* using the following function but it is not giving me the exact image but distorted part of some of the image. Please can anyone help me out here where i am mistaking it. Thank you.
BYTE *change_to_BYTE(Mat matrix_value)
{
BYTE* v_char_new = new BYTE[matrix_value.rows * matrix_value.cols * 3]();
vector<byte> v_char;
for(int i = 0; i < matrix_value.rows; i++)
{
for(int j = 0; j < matrix_value.cols; j++)
{
v_char_new[((i*matrix_value.cols+j) * 3)+0] = (*(uchar*)((matrix_value.data+ i*matrix_value.step + j + 0)));
v_char_new[((i*matrix_value.cols+j) * 3)+1] = (*(uchar*)((matrix_value.data+ i*matrix_value.step + j +1)));
v_char_new[((i*matrix_value.cols+j) * 3)+2] = (*(uchar*)((matrix_value.data+ i*matrix_value.step + j +2)));
}
}
return v_char_new;
}
After checking it out in different ways this was the one that worked for me.
BYTE *Ctest_face_projectDlg::change_to_BYTE(Mat matrix_value)
{
BYTE* v_char_new = new BYTE[matrix_value.rows * matrix_value.cols * 3]();
for(int i = 0; i < matrix_value.rows; i++)
{
for(int j = 0; j < matrix_value.cols; j++)
{
Vec3b bgrPixel = matrix_value.at<Vec3b>(i, j);
v_char_new[((i*matrix_value.cols+j)*3)+0] = bgrPixel.val[0];
v_char_new[((i*matrix_value.cols+j)*3)+1] = bgrPixel.val[1];
v_char_new[((i*matrix_value.cols+j)*3)+2] = bgrPixel.val[2];
// do something with BGR values...
}
}
}