1

I am working with OpenCV using C++. I would like to create an image with 3 colors: red, white and black. In detail, I want the background red and then a part white and a part black based on some conditions.

The problem that I have is that when I set a color to white it becomes BLUE.

Could someone know why this happen and how to solve it?

This is my code:

    //initial image total red

    cv::Mat image(Size(w, h), CV_8UC3, cv::Scalar(0, 0, 255));          

    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            int pixel_v = (int)imggray.at<uchar>(i,j);
            if (pixel_v < 200) {                
                int pixel_bl = (int)imgBool.at<uchar>(i, j);
                if (pixel_bl > 200) {
                    //HERE A WANT WHITE PIXELS, but they are blue
                    image.at<Vec3b>(i, j) = (255, 255, 255);                        
                }
                else {
                    //black: this works
                    image.at<Vec3b>(i, j) = (0, 0, 0);

                }
            }


        }
    }
GPPK
  • 6,546
  • 4
  • 32
  • 57
simona2012
  • 21
  • 3
  • 1
    OpenCV displays the right color but you feed it the wrong values. – Swordfish Feb 26 '19 at 14:36
  • 3
    Try: image.at(i, j) = cv::Vec3b(255, 255, 255); – Nuzhny Feb 26 '19 at 14:38
  • nuzhny: Yes, it is called because I change the color of those pixels! They became blue instead of white @Swordfish: It could be. What is the right value for white in opencv? isn´t (255,255,255)? – simona2012 Feb 26 '19 at 14:39
  • 1
    `(255, 255, 255)` does not do what you think it does (see [comma operator](https://stackoverflow.com/questions/52550/what-does-the-comma-operator-do).) It evaluates to just `255`. – Salem Feb 26 '19 at 14:40
  • I misread what you were setting `(255, 255, 255);` is wrong. – drescherjm Feb 26 '19 at 14:40
  • Read here https://stackoverflow.com/questions/23001512/c-and-opencv-get-and-set-pixel-color-to-mat The other commenters are eluding to this being the problem – GPPK Feb 26 '19 at 14:43
  • @Moira and why it works for the other colors? So, if it is how you are saying what should I do to set the color to white? – simona2012 Feb 26 '19 at 14:44

2 Answers2

2

OpenCV uses the image format BGR (Blue, Green Red)

When you write this line:

 image.at<Vec3b>(i, j) = (255, 255, 255);             

it is equivilent to:

image.at<Vec3b>(i, j) = (255);             

(See this SO answer to explain why.)

Which only sets the first channel, to max and that happens to be blue.

What you need to do is edit the whole pixel, like this:

    // get pixel
    Vec3b color = image.at<Vec3b>(Point(x,y));

    color[0] = 255;
    color[1] = 255;
    color[2] = 255;

    // set pixel
    image.at<Vec3b>(Point(x,y)) = color;

Borrowed from this answer

So your code would need to look like this:

cv::Mat image(Size(w, h), CV_8UC3, cv::Scalar(0, 0, 255));          

for (int i = 0; i < h; i++) {
    for (int j = 0; j < w; j++) {
        int pixel_v = (int)imggray.at<uchar>(i,j);
        if (pixel_v < 200) {                
            int pixel_bl = (int)imgBool.at<uchar>(i, j);
            if (pixel_bl > 200) {
                //HERE A WANT WHITE PIXELS, but they are blue
                Vec3b color = image.at<Vec3b>(Point(i,j));
                color[0] = 255;
                color[1] = 255;
                color[2] = 255;
                image.at<Vec3b>(Point(i,j)) = color;                   
            }
            else {
                image.at<Vec3b>(i, j) = (0, 0, 0);

            }
        }
    }
}
GPPK
  • 6,546
  • 4
  • 32
  • 57
  • It works but in this way Vec3b color; color[0] = 255; color[1] = 255; color[2] = 255; image.at(i, j) = color; Thank you very much for the explanation about the first channel. – simona2012 Feb 26 '19 at 15:21
  • 1
    That's great, yes you don't need to read out the color to start with. You could even move the Vec3b color definition outside the loop to save creating a new object each time and it will be quicker. – GPPK Feb 26 '19 at 16:56
-1

The kind of images I'm getting.

I'm using opencv with C++. I recieve an image from java and then make it into a buffer using this method:

private fun YUV_420_888_dataToBuffer(image: Image): ByteArray? {
     try {
   val imageWidth = image.width
   val imageHeight = image.height
   val planes = image.planes
   val data = ByteArray(imageWidth * imageHeight *  ImageFormat.getBitsPerPixel(ImageFormat.YUV_420_888) / 8 )
   var offset = 0
   for (plane in planes.indices) {
       val buffer = planes[plane].buffer
       val rowStride = planes[plane].rowStride

       val pixelStride = planes[plane].pixelStride
       val planeWidth = if (plane == 0) imageWidth else imageWidth / 2
       val planeHeight = if (plane == 0) imageHeight else imageHeight / 2
       if (pixelStride == 1 && rowStride == planeWidth) {
           // Copy whole plane from buffer into |data| at once.
           buffer[data, offset, planeWidth * planeHeight]
           offset += planeWidth * planeHeight
       } else {
           // Copy pixels one by one respecting pixelStride and rowStride.
           val rowData = ByteArray(rowStride)
           for (row in 0 until planeHeight - 1) {
               buffer[rowData, 0, rowStride]
               for (col in 0 until planeWidth) {
                   data[offset++] = rowData[col * pixelStride]
               }
           } 
           buffer[rowData, 0, Math.min(rowStride, buffer.remaining())]
           for (col in 0 until planeWidth) {
               data[offset++] = rowData[col * pixelStride]
           }
       }
   }
   return data
  } catch (e: Exception) {
   return null
 }
    }

On the c++ side I'm creating a Mat from the byte array like this:

 Mat * myuv = new Mat(width, height, CV_8UC1, (unsigned char *)  data);

 cvtColor(*myuv, *myuv, COLOR_YUV420sp2RGBA, 4);

What is going wrong here?

d12
  • 53
  • 1
  • 8