Search code examples
c++opencvmaskmatroi

OpenCV: Create a transparent mask?


What I'm currently doing is loading an image of a face into a Mat, setting the centre point X and Y coordinates of each eye, creating a circle around each of the eyes, setting the ROI to the circles around the eyes (using a Rect and setting a mask), and lowering the red value in the eye images.

My problem is around merging the corrected eye (with lowered red colour) back onto the original image because the corrected eyes have a black mask. I'm not sure how to get rid of the black mask.

I'm currently stuck on a bit of OpenCV code which has gotten me to this point:

Original image:

Extracted eye with black mask:

Corrected eye:

Current result displaying my problem:

This is a continuation from my thread here: Getting ROI from a Circle/Point

My understanding is that you cannot create a circular ROI, thus why I have gone with the Rect ROI and black mask. A normal Rect does not suffice.

Any advice is much appreciated!! Thank you.


Solution

  • you could use the masked roi image for testing pixels, but write into your real image:


     cv::Mat plotImage;
        int radius = 15;
        float threshold = 1.8;
    
        plotImage = cv::imread("C:/temp/debug.jpg", cv::IMREAD_COLOR);
    
        cv::Point leftEye(person.GetLeftEyePoint().X, person.GetLeftEyePoint().Y);
        cv::Point rightEye(person.GetRightEyePoint().X, person.GetRightEyePoint().Y);
    
        //get the Rect containing the circle
        cv::Rect r(leftEye.x-radius, leftEye.y-radius, radius*2, radius*2);
        //obtain the image ROI
        cv::Mat roi(plotImage, r);
        //make a black mask, same size
        cv::Mat mask(roi.size(), roi.type(), cv::Scalar::all(0));
        //with a white filled circle in it
        cv::circle(mask, cv::Point(radius, radius), radius, cv::Scalar::all(255), -1);
        //combine roi & mask
        cv::Mat croppedEye = roi&mask;
    
        //conduct red eye detection/removal on croppedEye
        int count = 0;
        for(int y=0;y<croppedEye.rows;y++)
        {
                for(int x=0;x<croppedEye.cols;x++)
                {
                        double b = croppedEye.at<cv::Vec3b>(y, x)[0];
                        double g = croppedEye.at<cv::Vec3b>(y, x)[1];
                        double r = croppedEye.at<cv::Vec3b>(y, x)[2];
    
                        double redIntensity = r / ((g + b) / 2);
    
                        //currently causes issues with non-red-eye images
                        if (redIntensity >= threshold)
                        {
                                double newRedValue = (g + b) / 2;
                                cv::Vec3b pixelColor(newRedValue,g,b);
                                //
                                // here's the trick now, just write back to the original image ;)
                                //
                                roi.at<cv::Vec3b>(cv::Point(x,y)) = pixelColor;
                                count++;
                        }
                }
        }
    
        cv::imwrite("C:\\temp\\test.jpg", plotImage);
    

    enter image description here