Лучше всего иметь дело с изображением в цветовом пространстве HSV (см. здесь для преобразования rgb - hsv). Цвет кожи практически одинаков для всех рас, меняется только его насыщенность. Имея дело с изображением в HSV, вы можете просто искать цвет кожи.
Вы можете сделать это, просто посчитав количество пикселей в цветовом диапазоне, или вы можете выполнить область , растущую вокруг пикселя, чтобы вычислить размер областей цвета.
Редактировать: для работы с зернистыми изображениями вы можете сначала выполнить медианный фильтр на изображении, а затем уменьшить количество цветов, чтобы сначала сегментировать изображение, вам придется поиграться с настройки большого набора предварительно классифицированных (для взрослых или нет) изображений и посмотрите, как эти значения ведут себя для получения удовлетворительного уровня обнаружения.
РЕДАКТИРОВАТЬ: Вот некоторый код, который должен делать простой подсчет (не проверял его, это быстрый гибрид некоторого кода от здесь и rgb в hsl здесь )
Bitmap b = new Bitmap(_image);
BitmapData bData = b.LockBits(new Rectangle(0, 0, _image.Width, _image.Height), ImageLockMode.ReadWrite, b.PixelFormat);
byte bitsPerPixel = GetBitsPerPixel(bData.PixelFormat);
byte* scan0 = (byte*)bData.Scan0.ToPointer();
int count;
for (int i = 0; i < bData.Height; ++i)
{
for (int j = 0; j < bData.Width; ++j)
{
byte* data = scan0 + i * bData.Stride + j * bitsPerPixel / 8;
byte r = data[2];
byte g = data[1];
byte b = data[0];
byte max = (byte)Math.Max(r, Math.Max(g, b));
byte min = (byte)Math.Min(r, Math.Min(g, b));
int h;
if(max == min)
h = 0;
else if(r > g && r > b)
h = (60 * ((g - b) / (max - min))) % 360;
else if (g > r && g > b)
h = 60 * ((b - r)/max - min) + 120;
else if (b > r && b > g)
h = 60 * ((r - g) / max - min) + 240;
if(h > _lowerThresh && h < _upperThresh)
count++;
}
}
b.UnlockBits(bData);