RGB to CIE Lab skin color segmentation

1k views Asked by At

I got problem to convert RGB to CIE Lab to get skin-colored area, I did some calculations from RGB based on this, to XYZ and finally Lab with a help from this link.

Here's my code:

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

using namespace cv;
using namespace std;
Mat frame;
Mat temp_rgb, temp_ycbcr, temp_hsv, temp_lab;
Mat thres_ycbcr, thres_hsv, thres_lab;

bool R1(int R, int G, int B) {
    bool e1 = (R>95) && (G>40) && (B>20) && ((max(R,max(G,B)) - min(R, min(G,B)))>15) && (abs(R-G)>15) && (R>G) && (R>B);
    bool e2 = (R>220) && (G>210) && (B>170) && (abs(R-G)<=15) && (R>B) && (G>B);
    return (e1||e2);
}

Mat labThreshold(const Mat & frame)
{
        Mat abc = Mat::zeros(frame.rows, frame.cols, CV_8UC1);
        cvtColor(frame, temp_lab, CV_BGR2XYZ);
        for(int i = 0; i < frame.rows; i++) {
        for(int j = 0; j < frame.cols; j++) {
            // Get the pixel in BGR space: 
            Vec3b pix_bgr = frame.ptr<Vec3b>(i)[j];
            float B = pix_bgr.val[0];
            float G = pix_bgr.val[1];
            float R = pix_bgr.val[2];
            // And apply RGB rule:
            bool bgr = R1(R,G,B);

            float X = pix_bgr.val[2]*0.4124 + pix_bgr.val[1]* 0.3576 + pix_bgr.val[0]*0.1805;
            float Y = pix_bgr.val[2]*0.2127 + pix_bgr.val[1]* 0.7152 + pix_bgr.val[0]*0.0722;
            float Z = pix_bgr.val[2]*0.0193 + pix_bgr.val[1]* 0.1192 + pix_bgr.val[0]*0.9505;

            float Xn = X / 95.047;
            float Yn = Y / 100.00;
            float Zn = Z / 108.883;

            if(Xn > 0.008856)
                Xn = powf(Xn,(1/3));
            else
                Xn = (7.787 * Xn) + (16 /116);
            if(Yn > 0.008856)
                Yn = powf(Yn,(1/3));
            else
                Yn = (7.787 * Yn) + (16 /116);
            if(Zn > 0.008856)
                Zn = powf(Zn,(1/3));
            else
                Zn = (7.787 * Zn) + (16 /116);

            float L = (116 * Yn) - 16;
            float a = 500 * (Xn - Yn);
            float b = 200 * (Yn - Zn);
            // If not skin, then black 
           /* if(bgr) {
                abc.at<unsigned char>(i,j) = 255;
            }*/
        }
    }
    return abc;
}

int main()
{
    // Create a VideoCapture object to read from video file
    // 0 is the ID of the built-in laptop camera
    VideoCapture cap(1);

    //check if the file was opened
    if(!cap.isOpened())
    {
        cout << "Capture could not be opened succesfully" << endl;
        return -1;
    }
    cap.set(CV_CAP_PROP_FRAME_WIDTH,320);
    cap.set(CV_CAP_PROP_FRAME_HEIGHT,480);

    namedWindow("Video CIELAB",CV_WINDOW_NORMAL);
    namedWindow("CIELAB Segmentation",CV_WINDOW_NORMAL);

    while(char(waitKey(1)) != 'q' && cap.isOpened())
    {
        cap >> frame;
        // Check if the video is over
        if(frame.empty())
        {
            cout << "Video over" << endl;
            break;
        }
        Mat thres_lab = labThreshold(frame);

        /*morphologyEx(thres_lab, thres_lab, MORPH_OPEN,  getStructuringElement(MORPH_ELLIPSE, Size(9, 9), Point(-1,-1)));
        morphologyEx(thres_lab, thres_lab, MORPH_CLOSE,  getStructuringElement(MORPH_ELLIPSE, Size(10, 10), Point(-1,-1)));*/

    imshow("Video CIELAB", temp_lab);
        imshow("CIELAB Segmentation", thres_lab);

    }
    return 0;
    }

The result is nothing but black frame. There's no single color detected on binary image.

I know there is cvtColor for BGR2Lab, but I don't know the thresholding value, like Min(L,a,b) and Max(L,a,b). Is there something wrong in my code? Thanks in advance!

0

There are 0 answers