提交 51acc6e0 编写于 作者: A Adam Geitgey

pre-release fixes

上级 db0e44d0
......@@ -7,4 +7,10 @@ Authors
Thanks
------
Many thanks to dlib and
* Many, many thanks to Davis King (@nulhom)
for creating dlib and for providing the trained facial feature detection and face encoding models
used in this library.
* Thanks to everyone who works on all the awesome Python data science libraries like numpy, scipy, scikit-image,
pillow, etc, etc that makes this kind of stuff so easy and fun in Python.
* Thanks to Cookiecutter and the audreyr/cookiecutter-pypackage project template
for making Python project packaging way more tolerable.
......@@ -51,23 +51,21 @@ lint: ## check style with flake8
flake8 face_recognition tests
test: ## run tests quickly with the default Python
python3 setup.py test
test-all: ## run tests on every Python version with tox
tox
coverage: ## check code coverage quickly with the default Python
coverage run --source face_recognition setup.py test
coverage report -m
coverage html
$(BROWSER) htmlcov/index.html
docs: ## generate Sphinx HTML documentation, including API docs
rm -f docs/face_recognition.rst
rm -f docs/modules.rst
sphinx-apidoc -o docs/ face_recognition
$(MAKE) -C docs clean
$(MAKE) -C docs html
......
# Face Recognition
The world's simplest face recognition and face manipulation library.
Recognize and manipulate faces from Python or from the command line with
the world's simplest face recognition library.
Built using [dlib](http://dlib.net/)'s state-of-the-art deep learning face recognition.
Built using [dlib](http://dlib.net/)'s state-of-the-art face recognition
built with deep learning. The model has an accuracy of 99.38% on the
[Labeled Faces in the Wild](http://vis-www.cs.umass.edu/lfw/) benchmark.
This also provides a simple `face_recognition` command line tool that lets
you do face recognition on a folder of images from the command line!
![](https://img.shields.io/pypi/v/face_recognition.svg)
![](https://travis-ci.org/ageitgey/face_recognition)
Recognize and manipulate faces from Python or from the command line
Free software, MIT license.
## Features
#### Find faces in pictures
Find all the faces that appear in a picture.
Find all the faces that appear in a picture:
![](https://cloud.githubusercontent.com/assets/896692/23582662/3891b65c-00e4-11e7-848e-0007bca850df.png)
![](https://cloud.githubusercontent.com/assets/896692/23625227/42c65360-025d-11e7-94ea-b12f28cb34b4.png)
```python
import face_recognition
image = face_recognition.load_image_file("your_file.jpg")
face_locations = face_recognition.face_locations(image)
```
#### Find and manipulate facial features in pictures
Get the locations and outlines of each person's eyes, nose, mouth and chin.
![](https://cloud.githubusercontent.com/assets/896692/23582665/3bbf323c-00e4-11e7-83f9-d42ede9ead2d.png)
![](https://cloud.githubusercontent.com/assets/896692/23625282/7f2d79dc-025d-11e7-8728-d8924596f8fa.png)
```python
import face_recognition
image = face_recognition.load_image_file("your_file.jpg")
face_landmarks_list = face_recognition.face_landmarks(image)
```
Finding facial features is super useful for lots of important stuff. But you can also use for really stupid stuff
like applying [digital make-up](https://github.com/ageitgey/face_recognition/blob/master/examples/digital_makeup.py) (think 'Meitu'):
![f3](https://cloud.githubusercontent.com/assets/896692/23582667/3cf969c4-00e4-11e7-82e6-add45ae3992f.png)
![](https://cloud.githubusercontent.com/assets/896692/23625283/80638760-025d-11e7-80a2-1d2779f7ccab.png)
#### Identify faces in pictures
Recognize who appears in each photo.
![f4](https://cloud.githubusercontent.com/assets/896692/23582670/405a5268-00e4-11e7-879f-b4de9f727096.png)
![](https://cloud.githubusercontent.com/assets/896692/23625229/45e049b6-025d-11e7-89cc-8a71cf89e713.png)
```python
import face_recognition
known_image = face_recognition.load_image_file("biden.jpg")
unknown_image = face_recognition.load_image_file("unknown.jpg")
biden_encoding = face_recognition.face_encodings(known_image)[0]
unknown_encoding = face_recognition.face_encodings(unknown_image)
results = face_recognition.compare_faces([biden_encoding], unknown_encoding)
```
## Installation
Python 3 is fully supported. Python 2 should also work. Only macOS and
Linux are tested. I have no idea if this will work on Windows.
You can install this module from pypi using `pip3` (or `pip2` for Python 2):
```bash
$ pip3 install face_recognition
```
It's very likely that you will run into problems when pip tries to compile
the `dlib` dependency. If that happens, check out this guide to installing
dlib from source instead to fix the error:
[How to install dlib from source](https://gist.github.com/ageitgey/629d75c1baac34dfa5ca2a1928a7aeaf)
After manually installing `dlib`, try running `pip3 install face_recognition`
again.
## Usage
......@@ -82,13 +127,13 @@ unknown_person
```
#### Python API
API Docs: [https://face-recognition.readthedocs.io](https://face-recognition.readthedocs.io).
#### Python Module
You can import the `face_recognition` module and then easily manipulate
faces with just a couple of lines of code. It's super easy!
API Docs: [https://face-recognition.readthedocs.io](https://face-recognition.readthedocs.io).
##### Automatically find all the faces in an image
```python
......@@ -145,7 +190,7 @@ See [this example](https://github.com/ageitgey/face_recognition/blob/master/exam
to try it out.
## Examples
## Python Code Examples
All the examples are available [here](https://github.com/ageitgey/face_recognition/tree/master/examples).
......@@ -154,11 +199,17 @@ All the examples are available [here](https://github.com/ageitgey/face_recogniti
* [Apply (horribly ugly) digital make-up](https://github.com/ageitgey/face_recognition/blob/master/examples/digital_makeup.py)
* [Find and recognize unknown faces in a photograph based on photographs of known people](https://github.com/ageitgey/face_recognition/blob/master/examples/recognize_faces_in_pictures.py)
## Caveats
* The face recognition model is trained on adults does not work very well on children. It tends to mix
up children quite easy using the default comparison threshold of 0.6.
## Thanks
* Many, many thanks to [Davis King](https://github.com/davisking) ([@nulhom](https://twitter.com/nulhom))
for creating dlib and for providing the trained facial feature detection and face encoding models
used in this library.
used in this library. For more information on the ResNet the powers the face encodings, check out
his [blog post](http://blog.dlib.net/2017/02/high-quality-face-recognition-with-deep.html).
* Everyone who works on all the awesome Python data science libraries like numpy, scipy, scikit-image,
pillow, etc, etc that makes this kind of stuff so easy and fun in Python.
* [Cookiecutter](https://github.com/audreyr/cookiecutter) and the
......
face_recognition package
========================
Submodules
----------
face_recognition.api module
---------------------------
.. automodule:: face_recognition.api
:members:
:undoc-members:
:show-inheritance:
face_recognition.cli module
---------------------------
.. automodule:: face_recognition.cli
:members:
:undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: face_recognition
.. automodule:: face_recognition.api
:members:
:undoc-members:
:show-inheritance:
......@@ -9,6 +9,7 @@ Contents:
readme
installation
usage
modules
contributing
authors
history
......
......@@ -5,3 +5,37 @@ Usage
To use Face Recognition in a project::
import face_recognition
See the examples in the /examples folder on github for how to use each function.
You can also check the API docs for the 'face_recognition' module to see the possible paramters for each function.
The basic idea is that first you load an image::
import face_recognition
image = face_recognition.load_image_file("your_file.jpg")
That loads the image into a numpy array. If you already have an image in a numpy array, you can skip this step.
Then you can perform operations on the image, like finding faces, identifying facial features or finding face encodings::
# Find all the faces in the image
face_locations = face_recognition.face_locations(image)
# Or maybe find the facial features in the image
face_landmarks_list = face_recognition.face_landmarks(image)
# Or you could get face encodings for each face in the image:
list_of_face_encodings = face_recognition.face_encodings(image)
Face encodings can be compared against each other to see if the faces are a match. Note: Finding the encoding for a face
is a bit slow, so you might want to save the results for each image in a database or cache if you need to refer back to
it later.
But once you have the encodings for faces, you can compare them like this::
# results is an array of True/False telling if the unknown face matched anyone in the known_faces array
results = face_recognition.compare_faces(known_face_encodings, a_single_unknown_face_encoding)
It's that simple! Check out the examples for more details.
# -*- coding: utf-8 -*-
import skimage.io
import scipy.misc
import dlib
import numpy as np
from pkg_resources import resource_filename
......@@ -12,28 +12,31 @@ face_recognition_model = resource_filename(__name__, "models/dlib_face_recogniti
face_encoder = dlib.face_recognition_model_v1(face_recognition_model)
def rect_to_css(rect):
def _rect_to_css(rect):
"""
Convert a dlib 'rect' object to a plain tuple in (top, right, bottom, left) order
:param rect: a dlib 'rect' object
:return: a plain tuple representation of the rect in (top, right, bottom, left) order
"""
return rect.top(), rect.right(), rect.bottom(), rect.left()
def css_to_rect(css):
def _css_to_rect(css):
"""
Convert a tuple in (top, right, bottom, left) order to a dlib `rect` object
:param css: plain tuple representation of the rect in (top, right, bottom, left) order
:return: a dlib `rect` object
"""
return dlib.rectangle(css[3], css[0], css[1], css[2])
def face_distance(faces, face_to_compare):
def _face_distance(faces, face_to_compare):
"""
Given a list of face encodings, compared them to a known face encoding and get a euclidean distance
for each comparison face.
:param faces: List of face encodings to compare
:param face_to_compare: A face encoding to compare against
:return: A list with the distance for each face in the same order as the 'faces' array
......@@ -44,15 +47,17 @@ def face_distance(faces, face_to_compare):
def load_image_file(filename):
"""
Loads an image file (.jpg, .png, etc) into a numpy array
:param filename: image file to load
:return: image contents as numpy array
"""
return skimage.io.imread(filename)
return scipy.misc.imread(filename)
def raw_face_locations(img, number_of_times_to_upsample=1):
def _raw_face_locations(img, number_of_times_to_upsample=1):
"""
Returns an array of bounding boxes of human faces in a image
:param img: An image (as a numpy array)
:param number_of_times_to_upsample: How many times to upsample the image looking for faces. Higher numbers find smaller faces.
:return: A list of dlib 'rect' objects of found face locations
......@@ -64,18 +69,19 @@ def raw_face_locations(img, number_of_times_to_upsample=1):
def face_locations(img, number_of_times_to_upsample=1):
"""
Returns an array of bounding boxes of human faces in a image
:param img: An image (as a numpy array)
:param number_of_times_to_upsample: How many times to upsample the image looking for faces. Higher numbers find smaller faces.
:return: A list of tuples of found face locations in css (top, right, bottom, left) order
"""
return [rect_to_css(face) for face in raw_face_locations(img, number_of_times_to_upsample)]
return [_rect_to_css(face) for face in _raw_face_locations(img, number_of_times_to_upsample)]
def raw_face_landmarks(face_image, face_locations=None):
def _raw_face_landmarks(face_image, face_locations=None):
if face_locations is None:
face_locations = raw_face_locations(face_image)
face_locations = _raw_face_locations(face_image)
else:
face_locations = [css_to_rect(face_location) for face_location in face_locations]
face_locations = [_css_to_rect(face_location) for face_location in face_locations]
return [pose_predictor(face_image, face_location) for face_location in face_locations]
......@@ -83,14 +89,15 @@ def raw_face_landmarks(face_image, face_locations=None):
def face_landmarks(face_image, face_locations=None):
"""
Given an image, returns a dict of face feature locations (eyes, nose, etc) for each face in the image
:param face_image: image to search
:param face_locations: Optionally provide a list of face locations to check.
:return: A list of dicts of face feature locations (eyes, nose, etc)
"""
landmarks = raw_face_landmarks(face_image, face_locations)
landmarks = _raw_face_landmarks(face_image, face_locations)
landmarks_as_tuples = [[(p.x, p.y) for p in landmark.parts()] for landmark in landmarks]
# For a definition of each point, see https://cdn-images-1.medium.com/max/1600/1*AbEg31EgkbXSQehuNJBlWg.png
# For a definition of each point index, see https://cdn-images-1.medium.com/max/1600/1*AbEg31EgkbXSQehuNJBlWg.png
return [{
"chin": points[0:14],
"left_eyebrow": points[17:22],
......@@ -104,15 +111,27 @@ def face_landmarks(face_image, face_locations=None):
} for points in landmarks_as_tuples]
def face_encodings(face_image, known_face_locations=None, raw_landmarks=None, num_jitters=1):
if known_face_locations is None:
known_face_locations = face_locations(face_image)
def face_encodings(face_image, known_face_locations=None, num_jitters=1):
"""
Given an image, return the 128-dimension face encoding for each face in the image.
if raw_landmarks is None:
raw_landmarks = raw_face_landmarks(face_image, known_face_locations)
:param face_image: The image that contains one or more faces
:param known_face_locations: Optional - the bounding boxes of each face if you already know them.
:param num_jitters: How many times to re-sample the face when calculating encoding. Higher is more accurate, but slower (i.e. 100 is 100x slower)
:return: A list of 128-dimentional face encodings (one for each face in the image)
"""
raw_landmarks = _raw_face_landmarks(face_image, known_face_locations)
return [np.array(face_encoder.compute_face_descriptor(face_image, raw_landmark_set, num_jitters)) for raw_landmark_set in raw_landmarks]
def compare_faces(known_face_encodings, face_encoding_to_check, tolerance=0.6):
return list(face_distance(known_face_encodings, face_encoding_to_check) <= tolerance)
"""
Compare a list of face encodings against a candidate encoding to see if they match.
:param known_face_encodings: A list of known face encodings
:param face_encoding_to_check: A single face encoding to compare against the list
:param tolerance: How much distance between faces to consider it a match. Lower is more strict. 0.6 is typical best performance.
:return: A list of True/False values indicating which known_face_encodings match the face encoding to check
"""
return list(_face_distance(known_face_encodings, face_encoding_to_check) <= tolerance)
......@@ -7,7 +7,7 @@ import skimage.transform
import skimage.util
import skimage.io
import warnings
import api as face_recognition
import face_recognition.api as face_recognition
def scan_known_people(known_people_folder):
......
......@@ -13,7 +13,7 @@ requirements = [
'Click>=6.0',
'dlib>=19.3.0',
'numpy',
'scikit-image'
'scipy'
]
test_requirements = [
......
......@@ -26,7 +26,7 @@ class Test_face_recognition(unittest.TestCase):
def test_raw_face_locations(self):
img = api.load_image_file(os.path.join(os.path.dirname(__file__), "test_images", "obama.jpg"))
detected_faces = api.raw_face_locations(img)
detected_faces = api._raw_face_locations(img)
assert len(detected_faces) == 1
assert detected_faces[0].top() == 142
......@@ -41,7 +41,7 @@ class Test_face_recognition(unittest.TestCase):
def test_raw_face_landmarks(self):
img = api.load_image_file(os.path.join(os.path.dirname(__file__), "test_images", "obama.jpg"))
face_landmarks = api.raw_face_landmarks(img)
face_landmarks = api._raw_face_landmarks(img)
example_landmark = face_landmarks[0].parts()[10]
assert len(face_landmarks) == 1
......@@ -87,9 +87,6 @@ class Test_face_recognition(unittest.TestCase):
def test_command_line_interface(self):
runner = CliRunner()
result = runner.invoke(cli.main)
assert result.exit_code == 0
assert 'face_recognition.cli.main' in result.output
help_result = runner.invoke(cli.main, ['--help'])
assert help_result.exit_code == 0
assert '--help Show this message and exit.' in help_result.output
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册