8

I have to capture skin colour independent of illumination. I used the following criteria(using hsv and rgb) but it ain't working:

int h = get_hue(...);
int s = get_saturation(...);
int r = get_red_component(...);
int g = get_green_component(...);
int b = get_blue_component(...);

if ((h<38)&&(h>6)&&(s>0.23)&&(s<0.68)){
    // skin color
}
else if ((r>95) && (g>40) && (b>20) && 
         ((maximum(r,g,b)-minimum(r,g,b))>15) && 
         (abs(r-g)>15)&&(r>g)&&(r>b)){
   // also skin color
}

It works in the morning when my skin is illuminated but by evening it does not work.

Any Help will be appreciated. Thanks in Advance. (PS -my skin ain't white.)

Roney Island
  • 453
  • 1
  • 4
  • 13
  • 2
    Could you provide sample pictures, and maybe describe desired output a little better? Do you want to "classify" image pixels in to non-skin and skin classes? Also, could you try and justify your criteria, maybe it is not so bad but it would help us in improving it if we understood how you came up with it. – penelope Jun 05 '12 at 14:43
  • 2
    This might help (i.e. for removing effects of illumination first): http://dsp.stackexchange.com/a/459/35 – datageist Jun 05 '12 at 15:13
  • these two criteria I just obtained from googling and yes I've to distinguish skin from non skin areas – Roney Island Jun 05 '12 at 16:16
  • 1
    here is an old question of mine, maybe it could help: http://dsp.stackexchange.com/questions/1625/basic-hsb-skin-detection-neon-illumination – nkint Jun 19 '12 at 09:46
  • by the way, i've got a trial with some other methods: histogram backprojection, mahalanoise distance on hsv, euclidean distance on rgb, for all using haar face detection (viola jones) for get train skin sample (it works on gray image so all kind of skin are good). i didn't managed to get perfect skin segmentation, but i'm interested in get better result! – nkint Jun 19 '12 at 09:51
  • I found this http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.96.652&rep=rep1&type=pdf – Roney Island Jun 06 '12 at 03:06
  • Link from other answer http://stackoverflow.com/a/14756351/1463143. – Eric Johnson Jul 14 '23 at 06:26

3 Answers3

4

In my experience best method for this is converting it to Lab color space. L represents the light, and a and b are light independent. OpenCV supports Lab color scale conversion.

  • I've seen the same remark in the Face recognition handbook (Springer). Lab should be a better color space. – sansuiso Mar 07 '13 at 07:40
2

try this:

''' Detect human skin tone and draw a boundary around it.
Useful for gesture recognition and motion tracking.

Inspired by: http://stackoverflow.com/a/14756351/1463143

Date: 08 June 2013
'''

# Required moduls
import cv2
import numpy

# Constants for finding range of skin color in YCrCb
min_YCrCb = numpy.array([0,133,77],numpy.uint8)
max_YCrCb = numpy.array([255,173,127],numpy.uint8)

# Create a window to display the camera feed
cv2.namedWindow('Camera Output')

# Get pointer to video frames from primary device
videoFrame = cv2.VideoCapture(0)

# Process the video frames
keyPressed = -1 # -1 indicates no key pressed

while(keyPressed < 0): # any key pressed has a value >= 0

    # Grab video frame, decode it and return next video frame
    readSucsess, sourceImage = videoFrame.read()

    # Convert image to YCrCb
    imageYCrCb = cv2.cvtColor(sourceImage,cv2.COLOR_BGR2YCR_CB)

    # Find region with skin tone in YCrCb image
    skinRegion = cv2.inRange(imageYCrCb,min_YCrCb,max_YCrCb)

    # Do contour detection on skin region
    contours, hierarchy = cv2.findContours(skinRegion, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

    # Draw the contour on the source image
    for i, c in enumerate(contours):
        area = cv2.contourArea(c)
        if area > 1000:
            cv2.drawContours(sourceImage, contours, i, (0, 255, 0), 3)

    # Display the source image
    cv2.imshow('Camera Output',sourceImage)

    # Check for user input to close program
    keyPressed = cv2.waitKey(1) # wait 1 milisecond in each iteration of while loop

# Close window and camera after exiting the while loop
cv2.destroyWindow('Camera Output')
videoFrame.release()
samkhan13
  • 121
  • 3
2

For this special case, I recommend reading up on LAB Color model.

And in regard to the LAB Color model, read up on Delta E. The distance between 2 colors. More details about color space can be found here: http://www.codeproject.com/Articles/613798/Colorspaces-and-Conversions

I have never attempted the LAB color model via OpenCV as it's is a hassle to convert from RGB to LAB and back(requires an immediate step).

But I have explored Delta E on MatLab to great success. You have to select the skin first, draw a small ROI on the video/picture and the program will find all the exact same color tone as the skin you selected via the ROI.

Another option is also look into the texture. A short preview here: http://books.google.com.sg/books?id=bRlk_WjfITIC&pg=PA598&lpg=PA598&dq=skin+thresholding+from+texture&source=bl&ots=28fE0livyh&sig=8EeQTLFCc-JB979_-ccyrhDJlqA&hl=en&sa=X&ei=aAuFUsHhJoWJrQfpkoCgBg&ved=0CDUQ6AEwAQ#v=onepage&q=skin%20thresholding%20from%20texture&f=false

This is basically training a image database. Comment here if you need help to training the image database or conversion of ColorSpace. A little busy, so the answer is just suggestions that you can do. Cheers.

rockinfresh
  • 216
  • 1
  • 3