Skip to content
This repository has been archived by the owner on Nov 8, 2021. It is now read-only.

Commit

Permalink
Initial version for Python SDK v0.1.
Browse files Browse the repository at this point in the history
  • Loading branch information
huxuan committed Aug 21, 2016
1 parent bee6a78 commit 342372a
Show file tree
Hide file tree
Showing 21 changed files with 1,555 additions and 2 deletions.
93 changes: 93 additions & 0 deletions .gitignore
@@ -0,0 +1,93 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# IPython Notebook
.ipynb_checkpoints

# pyenv
.python-version

# celery beat schedule file
celerybeat-schedule

# dotenv
.env

# virtualenv
venv/
ENV/

# Spyder project settings
.spyderproject

# Rope project settings
.ropeproject

# Custom
*.swp
config.py
9 changes: 9 additions & 0 deletions .pylintrc
@@ -0,0 +1,9 @@
[MESSAGES CONTROL]

# Use Python 3 style print for both support 2 and 3.
disable=superfluous-parens

[SIMILARITIES]

# Minimum lines number of a similarity.
min-similarity-lines=8
4 changes: 4 additions & 0 deletions MANIFEST.in
@@ -0,0 +1,4 @@
include CONTRIBUTING.md
include LICENSE-IMAGE.md
include LICENSE.md
include ThirdPartyNotices.txt
27 changes: 27 additions & 0 deletions Makefile
@@ -0,0 +1,27 @@
.PHONY: clean deps install lint pep8 pyflakes pylint test

clean:
find . -name '*.pyc' -print0 | xargs -0 rm -f
find . -name '*.swp' -print0 | xargs -0 rm -f
find . -name '__pycache__' -print0 | xargs -0 rm -rf
-rm -rf build dist *.egg-info

deps:
pip install -r requirements.txt

install:
python setup.py install

lint: pep8 pyflakes pylint

pep8:
-pep8 --statistics --count cognitive_face setup.py

pyflakes:
-pyflakes cognitive_face setup.py

pylint:
-pylint --rcfile=.pylintrc cognitive_face setup.py

test:
python setup.py test
40 changes: 38 additions & 2 deletions README.md
@@ -1,9 +1,45 @@
# Microsoft Face API: Jupyter Notebook
This [Jupyter Notebook](<http://jupyter.org/>) demonstrates how to use Python with the Microsoft Face API, an offering within [Microsoft Cognitive Services](https://www.microsoft.com/cognitive-services), formerly known as Project Oxford.
# Cognitive Face API: Python SDK
This repo contains the Python SDK for the Cognitive Face API, an offering within [Microsoft Cognitive Services](https://www.microsoft.com/cognitive-services), formerly known as Project Oxford.

* [Learn about the Face API](https://www.microsoft.com/cognitive-services/en-us/face-api)
* [Read the documentation](https://www.microsoft.com/cognitive-services/en-us/face-api/documentation/overview)
* [Find more SDKs & Samples](https://www.microsoft.com/cognitive-services/en-us/SDK-Sample?api=face)

## Installation

```bash
pip install cognitive_face
```

## Installation from Source Code

```bash
python setup.py install
```

## Unittests

```bash
python setup.py test
```

## Minimal Usage

```python
import cognitive_face as CF

KEY = 'subscription key' # Replace with a valid Subscription Key here.
CF.Key.set(KEY)

img_url = 'https://raw.githubusercontent.com/Microsoft/Cognitive-Face-Windows/master/Data/detection1.jpg'
result = cf.face.detect(url)
print result
```

## TODO

- More robust unittests (Only test the most basic functionality currently).
- Add native support for json response by adding some models like `Face`, `FaceList`, `Person` and `PersonGroup`.

## Contributing
We welcome contributions. Feel free to file issues and pull requests on the repo and we'll address them as we can. Learn more about how you can help on our [Contribution Rules & Guidelines](</CONTRIBUTING.md>).
Expand Down
14 changes: 14 additions & 0 deletions cognitive_face/__init__.py
@@ -0,0 +1,14 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
File: __init__.py
Description: Python SDK of the Cognitive Face API.
"""

from . import face
from . import face_list
from . import person
from . import person_group
from . import util
from .util import CognitiveFaceException
from .util import Key
166 changes: 166 additions & 0 deletions cognitive_face/face.py
@@ -0,0 +1,166 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
File: face.py
Description: Face section of the Cognitive Face API.
"""
from . import util


def detect(image, face_id=True, landmarks=False, attributes=''):
"""Detect human faces in an image and returns face locations, and
optionally with `face_id`s, landmarks, and attributes.
Args:
image: A URL or a file path or a file-like object represents an image.
face_id: Optional parameter. Return `face_id`s of the detected faces or
not. The default value is `True`.
landmarks: Optional parameter. Return face landmarks of the detected
faces or not. The default value is `False`.
attributes: Optional parameter. Analyze and return the one or more
specified face attributes in the comma-separated string like
`age,gender`. Supported face attributes include age, gender,
headPose, smile, facialHair, and glasses. Note that each face
attribute analysis has additional computational and time cost.
Returns:
An array of face entries ranked by face rectangle size in descending
order. An empty response indicates no faces detected. A face entry may
contain the corresponding values depending on input parameters.
"""
url = 'detect'
headers, data, json = util.parse_image(image)
params = {
'returnFaceId': face_id and 'true' or 'false',
'returnFaceLandmarks': landmarks and 'true' or 'false',
'returnFaceAttributes': attributes,
}

return util.request('POST', url, headers=headers, params=params, json=json,
data=data)


def find_similars(face_id, face_list_id=None, face_ids=None, max_candidates=20,
mode='matchPerson'):
"""Given query face's `face_id`, to search the similar-looking faces from a
`face_id` array or a `face_list_id`.
Parameter `face_list_id` and `face_ids` should not be provided at the same
time.
Args:
face_id: `face_id` of the query face. User needs to call `face.detect`
first to get a valid `face_id`. Note that this `face_id` is not
persisted and will expire in 24 hours after the detection call.
face_list_id: An existing user-specified unique candidate face list,
created in `face_list.create`. Face list contains a set of
`persisted_face_ids` which are persisted and will never expire.
face_ids: An array of candidate `face_id`s. All of them are created by
`face.detect` and the `face_id`s will expire in 24 hours after the
detection call. The number of `face_id`s is limited to 1000.
max_candidates: Optional parameter. The number of top similar faces
returned. The valid range is [1, 1000]. It defaults to 20.
mode: Optional parameter. Similar face searching mode. It can be
"matchPerson" or "matchFace". It defaults to "matchPerson".
Returns:
An array of the most similar faces represented in `face_id` if the
input parameter is `face_ids` or `persisted_face_id` if the input
parameter is `face_list_id`.
"""
url = 'findsimilars'
json = {
'faceId': face_id,
'faceListId': face_list_id,
'faceIds': face_ids,
'maxNumOfCandidatesReturned': max_candidates,
'mode': mode,
}

return util.request('POST', url, json=json)


def group(face_ids):
"""Divide candidate faces into groups based on face similarity.
Args:
face_ids: An array of candidate `face_id`s created by `face.detect`.
The maximum is 1000 faces.
Returns:
one or more groups of similar faces (ranked by group size) and a
messyGroup.
"""
url = 'group'
json = {
'faceIds': face_ids,
}

return util.request('POST', url, json=json)


def identify(face_ids, person_group_id, max_candidates=1, threshold=None):
"""Identify unknown faces from a person group.
Args:
face_ids: An array of query `face_id`s, created by the `face.detect`.
Each of the faces are identified independently. The valid number of
`face_ids` is between [1, 10].
person_group_id: `person_group_id` of the target person group, created
by `person_group.create`.
max_candidates: Optional parameter. The range of `max_candidates` is
between 1 and 5 (default is 1).
threshold: Optional parameter. Confidence threshold of identification,
used to judge whether one face belongs to one person. The range of
confidence threshold is [0, 1] (default specified by algorithm).
Returns:
The identified candidate person(s) for each query face(s).
"""
url = 'identify'
json = {
'personGroupId': person_group_id,
'faceIds': face_ids,
'maxNumOfCandidatesReturned': max_candidates,
'confidenceThreshold': threshold,
}

return util.request('POST', url, json=json)


def verify(face_id, another_face_id=None, person_group_id=None,
person_id=None):
"""Verify whether two faces belong to a same person or whether one face
belongs to a person.
For face to face verification, only `face_id` and `another_face_id` is
necessary. For face to person verification, only `face_id`,
`person_group_id` and `person_id` is needed.
Args:
face_id: `face_id` of one face, comes from `face.detect`.
another_face_id: `face_id` of another face, comes from `face.detect`.
person_group_id: Using existing `person_group_id` and `person_id` for
fast loading a specified person. `person_group_id` is created in
`person_group.create`.
person_id: Specify a certain person in a person group. `person_id` is
created in `person.create`.
Returns:
The verification result.
"""
url = 'verify'
json = {}
if another_face_id:
json.update({
'faceId1': face_id,
'faceId2': another_face_id,
})
else:
json.update({
'faceId': face_id,
'personGroupId': person_group_id,
'personId': person_id,
})

return util.request('POST', url, json=json)

0 comments on commit 342372a

Please sign in to comment.