跳转至

基于RGB颜色空间的简单阈值肤色识别

在human skin color clustering for face detection一文中提出如下简单的判别算式:

R>95 And G>40 And B>20 And R>G And R>B And Max(R,G,B)-Min(R,G,B)>15 And Abs(R-G)>15

算法非常之简单,同样主要把复杂的判断条件放到后面去判断,能有效的降低程序的执行时间,代码实现如下:

Mat SkinDetection(Mat src) {
    int row = src.rows;
    int col = src.cols;
    int channels = src.channels();
    Mat dst(row, col, CV_8UC3);
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            int B = src.at<Vec3b>(i, j)[0];
            int G = src.at<Vec3b>(i, j)[1];
            int R = src.at<Vec3b>(i, j)[2];
            for (int k = 0; k < 3; k++) {
                dst.at<Vec3b>(i, j)[k] = src.at<Vec3b>(i, j)[k];
            }
            int maxx, minn;
            if (R > 95 && G > 40 && B > 20 && R > B && R > G && abs(R - G) > 15) {
                if (B >= G) {
                    maxx = B;
                    minn = G;
                }
                else {
                    maxx = G;
                    minn = B;
                }
                if (R > maxx)
                    maxx = R;
                else if (R < minn)
                    minn = R;
                if (maxx - minn > 15) {
                    for (int k = 0; k < 3; k++) {
                        dst.at<Vec3b>(i, j)[k] = 255;
                    }
                }

            }
        }
    }
    return dst;
}

效果

在这里插入图片描述在这里插入图片描述

基于YCbCr颜色空间的简单阈值肤色识别

该算法则更为简单,将图像转换到YCbCr颜色空间,然后按下述计算式判断是否属于皮肤区域: (Cb > 77 And Cb < 127) And (Cr > 133 And Cr < 173)

const float YCbCrYRF = 0.299F;              // RGB转YCbCr的系数(浮点类型)
const float YCbCrYGF = 0.587F;
const float YCbCrYBF = 0.114F;
const float YCbCrCbRF = -0.168736F;
const float YCbCrCbGF = -0.331264F;
const float YCbCrCbBF = 0.500000F;
const float YCbCrCrRF = 0.500000F;
const float YCbCrCrGF = -0.418688F;
const float YCbCrCrBF = -0.081312F;

const float RGBRYF = 1.00000F;            // YCbCr转RGB的系数(浮点类型)
const float RGBRCbF = 0.0000F;
const float RGBRCrF = 1.40200F;
const float RGBGYF = 1.00000F;
const float RGBGCbF = -0.34414F;
const float RGBGCrF = -0.71414F;
const float RGBBYF = 1.00000F;
const float RGBBCbF = 1.77200F;
const float RGBBCrF = 0.00000F;

const int Shift = 20;
const int HalfShiftValue = 1 << (Shift - 1);

const int YCbCrYRI = (int)(YCbCrYRF * (1 << Shift) + 0.5);         // RGB转YCbCr的系数(整数类型)
const int YCbCrYGI = (int)(YCbCrYGF * (1 << Shift) + 0.5);
const int YCbCrYBI = (int)(YCbCrYBF * (1 << Shift) + 0.5);
const int YCbCrCbRI = (int)(YCbCrCbRF * (1 << Shift) + 0.5);
const int YCbCrCbGI = (int)(YCbCrCbGF * (1 << Shift) + 0.5);
const int YCbCrCbBI = (int)(YCbCrCbBF * (1 << Shift) + 0.5);
const int YCbCrCrRI = (int)(YCbCrCrRF * (1 << Shift) + 0.5);
const int YCbCrCrGI = (int)(YCbCrCrGF * (1 << Shift) + 0.5);
const int YCbCrCrBI = (int)(YCbCrCrBF * (1 << Shift) + 0.5);

const int RGBRYI = (int)(RGBRYF * (1 << Shift) + 0.5);              // YCbCr转RGB的系数(整数类型)
const int RGBRCbI = (int)(RGBRCbF * (1 << Shift) + 0.5);
const int RGBRCrI = (int)(RGBRCrF * (1 << Shift) + 0.5);
const int RGBGYI = (int)(RGBGYF * (1 << Shift) + 0.5);
const int RGBGCbI = (int)(RGBGCbF * (1 << Shift) + 0.5);
const int RGBGCrI = (int)(RGBGCrF * (1 << Shift) + 0.5);
const int RGBBYI = (int)(RGBBYF * (1 << Shift) + 0.5);
const int RGBBCbI = (int)(RGBBCbF * (1 << Shift) + 0.5);
const int RGBBCrI = (int)(RGBBCrF * (1 << Shift) + 0.5);

Mat RGB2YCbCr(Mat src) {
    int row = src.rows;
    int col = src.cols;
    Mat dst(row, col, CV_8UC3);
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            int Blue = src.at<Vec3b>(i, j)[0];
            int Green = src.at<Vec3b>(i, j)[1];
            int Red = src.at<Vec3b>(i, j)[2];
            dst.at<Vec3b>(i, j)[0] = (int)((YCbCrYRI * Red + YCbCrYGI * Green + YCbCrYBI * Blue + HalfShiftValue) >> Shift);
            dst.at<Vec3b>(i, j)[1] = (int)(128 + ((YCbCrCbRI * Red + YCbCrCbGI * Green + YCbCrCbBI * Blue + HalfShiftValue) >> Shift));
            dst.at<Vec3b>(i, j)[2] = (int)(128 + ((YCbCrCrRI * Red + YCbCrCrGI * Green + YCbCrCrBI * Blue + HalfShiftValue) >> Shift));
        }
    }
    return dst;
}

Mat SkinDetection2(Mat src) {
    int row = src.rows;
    int col = src.cols;
    int channels = src.channels();
    Mat dst(row, col, CV_8UC3);
    Mat temp = RGB2YCbCr(src);
    for (int i = 0; i < row; i++) {
        for (int j = 0; j < col; j++) {
            for (int k = 0; k < 3; k++) {
                dst.at<Vec3b>(i, j)[k] = src.at<Vec3b>(i, j)[k];
            }
            int Y = temp.at<Vec3b>(i, j)[0];
            int Cb = temp.at<Vec3b>(i, j)[1];
            int Cr = temp.at<Vec3b>(i, j)[2];
            if (Cb > 77 && Cb < 127 && Cr > 133 && Cr < 173) {
                for (int k = 0; k < 3; k++) {
                    dst.at<Vec3b>(i, j)[k] = 255;
                }
            }
        }
    }
    return dst;
}

效果

在这里插入图片描述

在这里插入图片描述

这些肤色检测算法准确率很低,大家笑一笑就好了。

参考博客

https://www.cnblogs.com/Imageshop/p/3265353.html