Commit ac8035f9 authored by Guillaume HEUSCH's avatar Guillaume HEUSCH
Browse files

[doc] changed the test image, reformat the docstrings

parent 6cd0955d
#!/usr/bin/env python
# encoding: utf-8
# Guillaume HEUSCH <guillaume.heusch@idiap.ch>
# Tue 5 Apr 11:20:29 CEST 2016
"""Test Units
"""
import nose.tools
import numpy
import bob.ip.skincolorfilter as scf
skin_filter = scf.SkinColorFilter()
def test_circular_mask():
"""
Test the generation of the circular mask
"""
# limit case: the center of the image is located at (0,0)
# so it's considered as inside (x**2 + y**2) = 0 < 0.4
image = numpy.zeros((3, 1, 1))
skin_filter.generate_circular_mask(image)
assert numpy.all(skin_filter.circular_mask), "a 1x1 image should be True"
# easy case - the "cross" should be true
image = numpy.zeros((3, 3, 3))
skin_filter.generate_circular_mask(image)
assert skin_filter.circular_mask[0, 1], "middle-top should be inside"
assert numpy.all(skin_filter.circular_mask[1, :]), "the whole middle line should be inside"
assert skin_filter.circular_mask[2, 1], "middle-bottom should be inside"
# more realistic case - radius will be 0.4*15=6 pixels
image = numpy.zeros((3, 15, 15))
skin_filter.generate_circular_mask(image)
print skin_filter.circular_mask
# left
assert not(skin_filter.circular_mask[7, 1]), "(7,1) should not be inside"
assert skin_filter.circular_mask[7, 2], "(7,2) should be inside"
# top
assert not(skin_filter.circular_mask[1, 7]), "(1,7) should not be inside"
assert skin_filter.circular_mask[2, 7], "(2,7) should be inside"
# right
assert not(skin_filter.circular_mask[7, 13]), "(7,13) should not be inside"
assert skin_filter.circular_mask[7, 12], "(7,12) should be inside"
# bottom
assert not(skin_filter.circular_mask[13, 7]), "(13, 7) should not be inside"
assert skin_filter.circular_mask[12, 7], "(12, 7) should be inside"
def test_luma_mask():
"""
Test the generation of the luma mask
"""
# generate a greyish image
image = numpy.ones((3, 11, 11))*(numpy.random.standard_normal((3,11,11)) + 128)
image[:, 0, :] = 0 # first line is black
image[:, -1, :] = 255 # last line is white
# the circular mask (to compute mean and std luma)
skin_filter.generate_circular_mask(image)
skin_filter.remove_luma(image)
# the first and last line should be all False - extreme values
assert not(numpy.all(skin_filter.luma_mask[:, 0]))
assert not(numpy.all(skin_filter.luma_mask[:, -1]))
# there should be at least one True everywhere else
assert numpy.any(skin_filter.luma_mask)
def test_estimate_parameters():
"""
Test the ML estimation of the Gaussian parameters
"""
# a red image
image = numpy.zeros((3, 11, 11))
image[0, :, :] = 255
skin_filter.get_gaussian_parameters(image)
assert (skin_filter.mean == [1.0, 0.0]).all(), "mean for a red image is not OK"
assert (skin_filter.covariance == [[0.0, 0.0], [0.0, 0.0]]).all(), "covariance for red image is not OK"
# a green image
image = numpy.zeros((3, 11, 11))
image[1, :, :] = 255
skin_filter.get_gaussian_parameters(image)
assert (skin_filter.mean == [0.0, 1.0]).all(), "mean for a green image is not OK"
assert (skin_filter.covariance == [[0.0, 0.0], [0.0, 0.0]]).all(), "covariance for green image is not OK"
......@@ -245,7 +245,8 @@ autodoc_default_flags = ['members', 'undoc-members', 'inherited-members', 'show-
# For inter-documentation mapping:
from bob.extension.utils import link_documentation
intersphinx_mapping = link_documentation(['python', 'numpy', 'scipy', 'matplotlib', 'bob.db.verification.utils'])
#intersphinx_mapping = link_documentation(['python', 'numpy', 'scipy', 'matplotlib', 'bob.db.verification.utils'])
intersphinx_mapping = link_documentation(['bob.ip.facedetect'])
def setup(app):
......
......@@ -7,18 +7,23 @@
import bob.io.base.test_utils
import bob.io.image
import bob.ip.facedetect
from bob.ip.skincolorfilter.skin_color_filter import SkinColorFilter
import bob.ip.skincolorfilter
import pkg_resources
face_image = bob.io.base.load(bob.io.base.test_utils.datafile('001.png', 'bob.ip.skincolorfilter'))
face_image = bob.io.base.load(bob.io.base.test_utils.datafile('test-face.jpg', 'bob.ip.skincolorfilter'))
=============
Users Guide
User Guide
=============
This skin color filter relies on the result of face detection. The skin color values
are estimated from the center of the detected face area. The probability of a pixel
to be of skin color is modeled as a bivariate gaussian in the normalized rg colorspace
This skin color filter relies on the result of face detection, hence you might want to
use :py:mod:`bob.ip.facedetect` (and in particular :py:func:`bob.ip.facedetect.detect_single_face`)
to first detect a face in the image.
The skin color distribution is modeled as a bivariate gaussian in the normalised rg colorspace.
The parameters of the distribution are estimated from a circular region centered on the face,
where extreme luma values have been eliminated (see [taylor-spie-2014]_ for details).
Skin pixels detection in a single image
---------------------------------------
......@@ -29,21 +34,22 @@ Hence, to detect skin pixels inside a face image, you should do the following:
.. doctest::
>>> face_image = bob.io.base.load('001.png') # doctest: +SKIP
>>> face_image = bob.io.base.load('test-face.jpg') # doctest: +SKIP
>>> detection = bob.ip.facedetect.detect_single_face(face_image)
>>> bounding_box, quality = bob.ip.facedetect.detect_single_face(face_image)
>>> face = face_image[:, bounding_box.top:bounding_box.bottom, bounding_box.left:bounding_box.right]
>>> skin_filter = SkinColorFilter()
>>> skin_filter.get_gaussian_parameters(face)
>>> skin_mask = skin_filter.get_skin_pixels(face_image, 0.5)
>>> skin_filter = bob.ip.skincolorfilter.SkinColorFilter()
>>> skin_filter.estimate_gaussian_parameters(face)
>>> skin_mask = skin_filter.get_skin_mask(face_image, 0.5)
.. plot:: plot/detect_skin_pixels.py
:include-source: False
Picture taken from https://stocksnap.io/photo/W7GS1022QN
Skin pixels detection in videos
-------------------------------
To detect skin pixels in video, you don't need to re-init the gaussian parameters at each frame.
However, you can do it if you really want to by calling the appropriate function (i.e. get_gaussian_parameters).
To detect skin pixels in video, you do not need to re-estimate the gaussian parameters at each frame.
However, you can do it by calling :py:meth:`SkinColorFilter.estimate_gaussian_parameters`.
......@@ -5,25 +5,27 @@ import bob.io.base
import bob.io.base.test_utils
import bob.io.image
import bob.ip.facedetect
from bob.ip.skincolorfilter.skin_color_filter import SkinColorFilter
from bob.ip.skincolorfilter import SkinColorFilter
face_image = bob.io.base.load(bob.io.base.test_utils.datafile('001.png', 'bob.ip.skincolorfilter'))
face_image = bob.io.base.load(bob.io.base.test_utils.datafile('test-face.jpg', 'bob.ip.skincolorfilter'))
detection = bob.ip.facedetect.detect_single_face(face_image)
bounding_box, quality = bob.ip.facedetect.detect_single_face(face_image)
face = face_image[:, bounding_box.top:bounding_box.bottom, bounding_box.left:bounding_box.right]
skin_filter = SkinColorFilter()
skin_filter.get_gaussian_parameters(face)
skin_mask = skin_filter.get_skin_pixels(face_image, 0.5)
skin_filter.estimate_gaussian_parameters(face)
skin_mask = skin_filter.get_skin_mask(face_image, 0.5)
skin_image = numpy.copy(face_image)
skin_image[:, numpy.logical_not(skin_mask)] = 0
from matplotlib import pyplot
f, ax = pyplot.subplots(2, 1)
ax[0].set_title('Original Image')
ax[0].set_xticks([])
ax[0].set_yticks([])
ax[0].imshow(numpy.rollaxis(numpy.rollaxis(face_image, 2),2))
ax[1].set_title('Detected skin pixels')
ax[1].set_xticks([])
ax[1].set_yticks([])
ax[1].imshow(numpy.rollaxis(numpy.rollaxis(skin_image, 2),2))
f, ax = pyplot.subplots(1, 1)
ax.set_title('Original Image')
ax.set_xticks([])
ax.set_yticks([])
ax.imshow(numpy.rollaxis(numpy.rollaxis(face_image, 2),2))
f, ax = pyplot.subplots(1, 1)
ax.set_title('Detected skin pixels')
ax.set_xticks([])
ax.set_yticks([])
ax.imshow(numpy.rollaxis(numpy.rollaxis(skin_image, 2),2))
......@@ -2,5 +2,5 @@
Python API
============
.. automodule:: bob.ip.skincolorfilter.skin_color_filter
.. automodule:: bob.ip.skincolorfilter
:members:
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment