shikailun的日志

C#肤色检测

上篇有提到BabyMaker项目需要提取照片中人的肤色,我对于图像处理一直停留在零经验,在翻阅数篇论文依旧毫无思路准备放弃之际,看到了一个大牛用C#写的肤色检测算法,算法可以去除图片中和皮肤无关的信息,仅保留皮肤。

下面就是经过处理以后的图片了

效果非常明显,这样就只剩下皮肤信息了,最简单方法(我能想到的唯一方法…)的当就是取出每个像素点的颜色然后取个平均。

public static Color getAverageColor(Bitmap bmp)
{
    int width = bmp.Width;
    int height = bmp.Height;
    int sum = 0; //总像素点
    int r = 0, g = 0, b = 0, a = 0;
    Color c = Color.Empty;
    for (int i = 0; i < width; i++)
    {
        for (int j = 0; j < height; j++)
        {
            c = bmp.GetPixel(i, j);
            if (c.R + c.G + c.B != 0)  //排除黑色
            {
                r += c.R;
                g += c.G;
                b += c.B;
                a += c.A;
                sum++;
            }
        }
    }
    if (sum != 0) //防止碰到黑人.....
    {
        r = r / sum;
        g = g / sum;
        b = b / sum;
        a = a / sum;
    }
    c = Color.FromArgb(a, r, g, b);
    return c;
}

很多人说C#的setpixel和getpixel操作效率非常点,想想也是,这么大一张图片,一个一个像素遍历,可以考虑使用BitmapData用指针直接在内存中操作图片颜色,速度提升明显,不过需要用unsafe围起来,附上大牛的算法(完全看不懂)。

public static Bitmap skinDetect(Bitmap a)
{
    Rectangle rect = new Rectangle(0, 0, a.Width, a.Height);
    BitmapData bmpData = a.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
    int stride = bmpData.Stride;
    unsafe
    {
        byte* pIn = (byte*)bmpData.Scan0.ToPointer();
        byte* P;
        int R, G, B;
        double r, g, Fupr, Flor, Wrg;
        for (int y = 0; y < a.Height; y++)
        {
            for (int x = 0; x < a.Width; x++)
            {
                P = pIn;
                B = P[0];
                G = P[1];
                R = P[2];
                if (R + G + B == 0)
                {
                    r = 0;
                    g = 0;
                }
                else
                {
                    r = (R / (R + G + B));
                    g = (G / (R + G + B));
                }
                Fupr = (1.0743 * r + 0.1452 - 1.3767 * r * r);
                Flor = (0.5601 * r + 0.1766 - 0.776 * r * r);
                Wrg = (r - 0.33) * (r - 0.33) + (g - 0.33) * (g - 0.33);
                if ((R - G >= 45) && ((R > G) && (G > B)) && (Fupr > g) && (Wrg >= 0.0004))
                {
                    P[0] = (byte)B;
                    P[1] = (byte)G;
                    P[2] = (byte)R;
                }
                else
                {
                    P[0] = 0;
                    P[1] = 0;
                    P[2] = 0;
                }
                pIn += 3;
            }
            pIn += stride - a.Width * 3;
        }
    }
    a.UnlockBits(bmpData);
    return a;
}
Posted on
This entry was posted in technology  and tagged CSharp  图像处理  BabyMaker