Выделение цвета кожи человека / Прикладные вопросы распознавания образов / Recog.ru - Распознавание образов для программистов


Выделение цвета кожи человека

Прочитал статью «A Real-Time Face Tracker» (http://www-prima.inrialpes.fr/perso/Tran/Documents/Articles/Divers/RTFaceTracker.pdf).
Вообще статья посвящена трекингу лица, однако меня она заинтересовала по другой причине – в ней представлена модель описания цвета кожи. Поэтому я опишу смысл этой модели.

Основная идея в том, что человек адаптируется к яркости изображения, и для того, чтобы распознать необходимо отбросить информацию о яркости. Используется понятие «чистого» цвета (хроматический), описанного в работе [G. Wyszecki and W.S. Styles. Color Science: Concepts and Methods, Quantitative Data and Formulae, Second Edition, John Wiley & Sons, New York, 1982].

«Чистый» цвет получается следующим образом:
r = R / (R + G + B),
g = G / (R + G + B).
Синий цвет лишний, поскольку после нормализации r+g+b =1.

При этом в данной работе было показано, что при использовании «чистого» цвета было определено, что кожа людей даже разной национальности находится в очень небольшом диапазоне по сравнению с ненормализованным цветом.
Распределение цвета может быть представлено 2D моделью Гаусса (по нашему двумерное нормальное распределение)


Попробуем применить данный подход к выделению лиц. Для этого я воспользуюсь той же программой (и теми же картинками), что и для вырезки лица:
http://recog.ru/blog/applied/52.html

Первоначально нам необходимо посчитать вместо среднего цвета, коэффициенты двумерного нормально распределения:

double *Color1 = new double[(1+int(5*Image24->height/8)-int(3*Image24->height/8))*(1+int(5*Image24->width/8)-int(3*Image24->width/8))];
double *Color2 = new double[(1+int(5*Image24->height/8)-int(3*Image24->height/8))*(1+int(5*Image24->width/8)-int(3*Image24->width/8))];
all=0;
for(i=3*Image24->height/8;i<=5*Image24->height/8;i++)
	for(j=3*Image24->width/8;j<=5*Image24->width/8;j++)
	{
		// "чистый" цвет
		Color1[all]=(double)ptr[i*Image24->widthStep+j*3]/(ptr[i*Image24->widthStep+j*3]+ptr[i*Image24->widthStep+j*3+1]+ptr[i*Image24->widthStep+j*3+2]);
		Color2[all]=(double)ptr[i*Image24->widthStep+j*3+1]/(ptr[i*Image24->widthStep+j*3]+ptr[i*Image24->widthStep+j*3+1]+ptr[i*Image24->widthStep+j*3+2]);
		all++;
	}
// Мат ожидание
double m1 = M_e(all,Color1);
double m2 = M_e(all,Color2);
// Среднее квадратичное отклонение
double q1 = sqrt(D_e(all,Color1,m1));
double q2 = sqrt(D_e(all,Color2,m2));
// Коэффициент корреляции
double q12 = D_e2(all,Color1,Color2,m1,m2)/(q1*q2);


Можно конечно для каждого пикселя считать вероятность, полученная при подстановке в формулу нормального распределения. Но мы сделаем проще.
Для того, чтобы определить попадает ли при анализе изображения нужный цвет в цвет лица будем смотреть на каком расстоянии от m1 и m2 будет чистый цвет, если возьмем расстояние равное среднему квадратичному отклонению – это обеспечит 68% попадание в наше распределение. Двойное среднее квадратичное отклонение – 95,4%.

// Выделяем пиксели лица
double Color1_;
double Color2_;
for(i=0;i<Image24->height;i++)
	for(j=0;j<Image24->width;j++)
	{
		Color1_=(double)ptr[i*Image24->widthStep+j*3]/(ptr[i*Image24->widthStep+j*3]+ptr[i*Image24->widthStep+j*3+1]+ptr[i*Image24->widthStep+j*3+2]);
		Color2_=(double)ptr[i*Image24->widthStep+j*3+1]/(ptr[i*Image24->widthStep+j*3]+ptr[i*Image24->widthStep+j*3+1]+ptr[i*Image24->widthStep+j*3+2]);
		if (abs(m1-Color1_)<2*q1 && abs(m2-Color2_)<2*q2){
			ptr_f[i*Image24_Face->widthStep+j*3]=255;
			ptr_f[i*Image24_Face->widthStep+j*3+1]=0;
			ptr_f[i*Image24_Face->widthStep+j*3+2]=0;
		}
		else{
			ptr_f[i*Image24_Face->widthStep+j*3]=0;
			ptr_f[i*Image24_Face->widthStep+j*3+1]=0;
			ptr_f[i*Image24_Face->widthStep+j*3+2]=0;
		}
	}


Вот результат для 68%-го попадания

И для 95,4%.

На рисунках видно достаточно качественно выделение лица

Комментарии (0)

RSS свернуть / развернуть

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.