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!