Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
sayef committed Dec 8, 2020
0 parents commit 7ed647a
Show file tree
Hide file tree
Showing 16 changed files with 36,351 additions and 0 deletions.
138 changes: 138 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

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

# 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/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/
22 changes: 22 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
## Crop eye pair from face image using HAAR cascade and/or MTCNN
-------------

### How to run?
1. Clone this repository.
2. Install requirements: `pip install -r requirements.txt`
3. If input face images are in directory `example/input/dir` and output direcotry `example/output/dir` then run the following command which will preserve input directory structure for further tasks.

```
python crop_eye_pair.py --input_dir 'example/input/dir' --output_dir 'example/output/dir' --method 'mtcnn' --device 'cuda'
```
4. Supported `method` options: `haar-cascade` and `mtcnn`
5. Supported `device` options: `cpu` and `cuda`.
Notes: Setting device to `cuda` has no effect while using `haar-cascade` method.
## Credits
1. MTCNN code borrowed from https://github.com/ipazc/mtcnn
2. HAAR Cascade code inspired from https://github.com/zekeriyafince/EyePair
99 changes: 99 additions & 0 deletions crop_eye_pair.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import numpy as np
import cv2
import glob
import argparse
import os
import re
import logging
import tqdm

# global variable for mtcnn detector
mtcnn_detector = None

# global variables for cascade detector
face_cascade = None
eye_pair_cascade = None

def get_eye_pair_mtcnn(image):

image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
result = mtcnn_detector.detect_faces(image_rgb)

if not result: return (False, False)

bounding_box = result[0]['box']
keypoints = result[0]['keypoints']

left_eye = keypoints['left_eye']
right_eye = keypoints['right_eye']

y_start = min(left_eye[1], right_eye[1])
y_end = max(left_eye[1], right_eye[1])

x_start = min(left_eye[0], right_eye[0])
x_end = max(left_eye[0], right_eye[0])

image = image[y_start-15:y_end+15, x_start-10:x_end+10]

return (True, image)

def get_eye_pair_opencv(image):

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(gray, 1.3, 5)

for x, y, w, h in faces: # face points
roi_gray = gray[y:y + h, x:x + w]
roi_color = image[y:y + h, x:x + w]
eye_pairs = eye_pair_cascade.detectMultiScale(roi_gray)

for (ex, ey, ew, eh) in eye_pairs: # eye_pair points
roi_eyes = roi_color[ex:min(roi_color.shape[0], ex+ew*2), max(0, ey-eh//2):min(roi_color.shape[1], ey+eh)]
return (True, roi_eyes)

return (False, False)

def save_eye_pair(input_path, output_path, method='mtcnn'):
image = cv2.imread(input_path)
if method == 'mtcnn':
found, pair = get_eye_pair_mtcnn(image)
else:
found, pair = get_eye_pair_opencv(image)

if found:
os.makedirs(os.path.split(output_path)[0], exist_ok = True)
cv2.imwrite(output_path, pair)

def main(args):

if args.device == 'cuda':
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
else:
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"

if args.method == 'mtcnn':
global mtcnn_detector
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' # ERROR
logging.getLogger('tensorflow').setLevel(logging.ERROR)
from mtcnn import MTCNN
mtcnn_detector = MTCNN()
else:
global face_cascade, eye_pair_cascade
face_cascade = cv2.CascadeClassifier('./haar-cascade/haarcascade_frontalface_default.xml') # face
eye_pair_cascade = cv2.CascadeClassifier('./haar-cascade/haarcascades_haarcascade_mcs_eyepair_big.xml') #eye_pair

for input_path in tqdm.tqdm(glob.glob(args.input_dir + "/**/*.jpg", recursive=True)):
save_eye_pair(input_path, os.path.join(args.output_dir, re.sub('^' + args.input_dir, '', input_path)), method=args.method)
break


# python crop_eye_pair.py --input_dir images/ --output_dir eye_pair_images/ --method mtcnn
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='crop eye pair from face image')
parser.add_argument('--input_dir', default='', type=str, help='')
parser.add_argument('--output_dir', default='', type=str, help='')
parser.add_argument('--method', default='mtcnn', type=str, help='mtcnn or cascade')
parser.add_argument('--device', default='cpu', type=str, help='cuda or cpu')
args = parser.parse_args()

main(args)
Loading

0 comments on commit 7ed647a

Please sign in to comment.