Существует много способов выполнить пиксельный порог, чтобы отделить «пиксели кожи» от «не-скиновых пикселей», и есть документы, основанные практически на любом цветовом пространстве (даже с RGB). Таким образом, мой ответ просто основан на бумаге Face Segmentation с использованием карты цвета кожи в приложениях для видеофонов Chai и Ngan. Они работали с цветовым пространством YCbCr и получили неплохие результаты, в документе также упоминается порог, который хорошо подходит для них:
(Cb in [77, 127]) and (Cr in [133, 173])
The thresholds for the Y
channel are not specified, but there are papers that mention Y > 80
. For your single image, Y
in the whole range is fine, i.e. it doesn't matter for actually distinguishing skin.
Вот вход, двоичное изображение в соответствии с указанными порогами и результирующее изображение после отбрасывания небольших компонентов.

import sys
import numpy
import cv2
im = cv2.imread(sys.argv[1])
im_ycrcb = cv2.cvtColor(im, cv2.COLOR_BGR2YCR_CB)
skin_ycrcb_mint = numpy.array((0, 133, 77))
skin_ycrcb_maxt = numpy.array((255, 173, 127))
skin_ycrcb = cv2.inRange(im_ycrcb, skin_ycrcb_mint, skin_ycrcb_maxt)
cv2.imwrite(sys.argv[2], skin_ycrcb) # Second image
contours, _ = cv2.findContours(skin_ycrcb, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
for i, c in enumerate(contours):
area = cv2.contourArea(c)
if area > 1000:
cv2.drawContours(im, contours, i, (255, 0, 0), 3)
cv2.imwrite(sys.argv[3], im) # Final image
Наконец, есть довольно приличное количество бумаг, которые не полагаются на индивидуальную поэтапную классификацию для этой задачи. Вместо этого они начинаются с базы помеченных изображений, которые, как известно, содержат либо пиксели кожи, либо пиксели без кожи. Из этого они обучают, например, SVM, а затем различают другие входы, основанные на этом классификаторе.