Search code examples
c++opencvimage-processingpixel

OpenCV: Calculating new red pixel value


I'm currently aiming to adjust the red pixels in an image (more specifically, an eye region to remove red eyes caused by flash), and this works well, but the issue I'm getting is sometimes green patches appear on the skin.

This is a good result (before and after):

I realize why this is happening, but when I go to adjust the threshold to a higher a value (meaning the red intensity must be stronger), less red pixels are picked up and changed, i.e.:

The lower the threshold, the more green shows up on the skin.

I was wondering if there was an alternate method to what I'm currently doing to change the red pixels?

int lcount = 0;
for(int y=0;y<lcroppedEye.rows;y++)
{
    for(int x=0;x<lcroppedEye.cols;x++)
    {
        double b = lcroppedEye.at<cv::Vec3b>(y, x)[0];
        double g = lcroppedEye.at<cv::Vec3b>(y, x)[1];
        double r = lcroppedEye.at<cv::Vec3b>(y, x)[2];

        double redIntensity = r / ((g + b) / 2);

        //currently causes issues with non-red-eye images
        if (redIntensity >= 1.8)
        {
            double newRedValue = (g + b) / 2;
            cv::Vec3b pixelColor(newRedValue,g,b);
            lroi.at<cv::Vec3b>(cv::Point(x,y)) = pixelColor;
            lcount++;
        }
    }
}

EDIT: I can possibly add in a check to ensure the new RGB values are low enough, and so R, G, B values are similar/close values so black/grey pixels are written out only... or have a range of RGB values (greenish) which aren't allowed... would that work?


Solution

  • Adjusting color in RGB space has caveats like this greenish areas you faced. Convert the R,G,B values to a better color space, like HSV or LUV.

    I suggest you go for HSV to detect and change the red-eye colors. R/(G+B) is not a good way for calculating red intensity. This means you are calling (R=10,G=1,B=0) a very red color, but it is deadly black. Take a look at the comparison below:

    colors

    So, you'd better check if Saturation and Value are high values which is the case for a red-eye color. If you encounter other high intensity colors, you may check the Hue is in the range of something like [0-20] and [340-359]. But without this, you are still safe against the white itself, as it has a very low saturation and you won't select white areas anyway.

    That was for selecting, for changing the color, it is again better to not use RGB, as changing in that space is not linear as we perceive colors. Looking at the image above, you can see that lowering both the saturation and value would be a good start. But you may experiment with it and see what looks better. Maybe you'll be fine with a dark gray always, that would mean set Saturation to zero, and lower the Value a bit. You may think a dark brown would be better, go for a low saturation and value but set Hue to something about 30 degrees.

    References that may help you:

    1. Converting color values in OpenCV
    2. An online tool to experiment with RGB and HSV colors