Ask Your Question

converting 3-channel BGR pic to grayscale BY HAND

asked 2013-03-10 09:04:16 -0500

cz_asm7 gravatar image


I'm having this problem - I have to write a function which converts bgr picture to grayscale one-channel picture. Only things I can use are cv:Mat variables: rows, cols, data and step. I've been trying to solve it this way:

void bgr2gray( const Mat& bgr, Mat& gray )
    gray = Mat::zeros(bgr.rows, bgr.cols, CV_8UC1 );

     for (int y = 0; y < bgr.rows; y++) {
      for (int x = 0; x < bgr.cols; x++) {

         unsigned char blue =[3*bgr.cols*y + x]*0.114f; //0.114
         unsigned char green =[3*bgr.cols*y + x+sizeof(char)]*0.587f;
         unsigned char red =[3*bgr.cols*y + x+2*sizeof(char)]*0.299f;
[gray.cols*y+x] = red + green + blue;


But still this gives me wrong (not whole) picture with many white vertical lines. Do you know whre I'm mistaken in my thinking?

Thanks for the answer


edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted

answered 2013-03-10 10:49:11 -0500

Guanta gravatar image

Your indices are wrong, the correct way would be:

unsigned char blue =[3*bgr.cols*y + 3*x]*0.114;
unsigned char green =[3*bgr.cols*y + 3*x + 1]*0.587;
unsigned char red =[3*bgr.cols*y + 3*x+2]*0.299;

However, due to the individual casts you'll lose some precision, so either use float instead of unsigned char for your three lines or write it as a one-liner:<uchar>(y,x) =<Vec3b>(y,x)[0] * 0.114 +<Vec3b>(y,x)[1]*0.587 +<Vec3b>(y,x)[2]*0.299

Also note that your way of accessing the data-array only works for continuous data, this is normally true, but you never know.

Btw.: If you use the templated-matrices (i.e. Mat3b and Mat1b) you can omit the '.at<uchar>' and '.at<Vec3b>'

edit flag offensive delete link more

Question Tools


Asked: 2013-03-10 09:04:16 -0500

Seen: 2,092 times

Last updated: Mar 10 '13