updated
|
@ -0,0 +1,54 @@
|
||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
env/
|
||||||
|
bin/
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.coverage
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
|
||||||
|
# Mr Developer
|
||||||
|
.mr.developer.cfg
|
||||||
|
.project
|
||||||
|
.pydevproject
|
||||||
|
|
||||||
|
# Rope
|
||||||
|
.ropeproject
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
This implements a face alignment method, as preprocessing to tasks such as age and gender estimation,
|
||||||
|
and face recognition as described in [1] and [2].
|
||||||
|
|
||||||
|
The code calls an executable of facial landmarks detection, by X.Zhu and D. Ramanan, implementing the algorithm described in [3].
|
||||||
|
|
||||||
|
(The rest of this text is a quotation from their code: Copyright (C) 2012 Xiangxin Zhu, Deva Ramanan)
|
||||||
|
|
||||||
|
It includes pre-trained face models.
|
||||||
|
|
||||||
|
Much of the detection code is built on top of part-based model implementation of [4].
|
||||||
|
|
||||||
|
The training code implements a quadratic program (QP) solver described in [5].
|
||||||
|
|
||||||
|
In the training code, we use the positive samples from MultiPIE dataset (available at www.multipie.org) and the negative images from the INRIAPerson dataset [6] (included in the package).
|
||||||
|
|
||||||
|
Acknowledgements: We graciously thank the authors of the previous code releases and image benchmarks for making them publicly available.
|
||||||
|
|
||||||
|
References
|
||||||
|
==========
|
||||||
|
|
||||||
|
[1] E. Eidinger, R. Enbar, T. Hassner, Age and Gender Estimation of Unfiltered Faces, submitted to IEEE TRANSACTIONS ON INFORMATION FORENSICS AND SECURITY, 2014
|
||||||
|
|
||||||
|
[2] http://www.openu.ac.il/home/hassner/Adience/links.html
|
||||||
|
|
||||||
|
[3] X. Zhu, D. Ramanan. Face Detection, Pose Estimation and Landmark Localization in the Wild. CVPR 2012.
|
||||||
|
|
||||||
|
[4] P. Felzenszwalb, R. Girshick, D. McAllester. Discriminatively Trained Deformable Part Models. http://people.cs.uchicago.edu/~pff/latent.
|
||||||
|
|
||||||
|
[5] D. Ramanan. Dual Coordinate Descent Solvers for Large Structured Prediction Problems. UCI Technical Report, to appear.
|
||||||
|
|
||||||
|
[6] N. Dalal, B. Triggs. Histograms of Oriented Gradients for Human Detection. CVPR 2005.
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
Copyright (C) 2014 Adience SER Ltd. (www.adience.com)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
adience_align
|
||||||
|
========
|
||||||
|
|
||||||
|
This project provides alignment tools for faces, to be used as a preprocessing step before computer vision tasks on face images.
|
||||||
|
|
||||||
|
Homepage for the project: http://www.openu.ac.il/home/hassner/Adience/
|
||||||
|
|
||||||
|
|
||||||
|
See the test for example usage.
|
||||||
|
|
||||||
|
Specificaly, the "pipeline" test, shows how to use the full process (just remember to change the location of the model files to where you stor the *.xml and other model files)
|
||||||
|
|
||||||
|
Installation
|
||||||
|
=========
|
||||||
|
in the root of the repository:
|
||||||
|
|
||||||
|
```
|
||||||
|
python setup.py sdist
|
||||||
|
sudo pip install dist/adience-<version_number>.tar.gz
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
CopyRight
|
||||||
|
=========
|
||||||
|
(contact: Eran Eidinger (eran@adience.com), Roee Enbar (roee.e@adience.com))
|
||||||
|
|
||||||
|
See the LICENSE.txt file (basically, an MIT license).
|
||||||
|
|
||||||
|
|
||||||
|
With any publication that uses this alignment code, or it's derivative, we kindly ask that you cite the paper:
|
||||||
|
E. Eidinger, R. Enbar, and T. Hassner, Age and Gender Estimation of Unfiltered Faces, Transactions on Information Forensics and Security (IEEE-TIFS), special issue on Face Recognition in the Wild
|
||||||
|
|
||||||
|
For more details, please see:
|
||||||
|
http://www.openu.ac.il/home/hassner/Adience/publications.html
|
||||||
|
|
||||||
|
Compilation notes
|
||||||
|
========
|
||||||
|
1. The shared objects were compiled for linux 64bit on Ubuntu 13.10
|
||||||
|
2. The SO uses boost-1.53, so make sure it is installed on your system and available at /usr/local/, or use LD_LIBRARY_PATH="yourpath" to point it at the right place. Alternatively, place "libboost_system.so.1.53.0" and "libboost_filesystem.so.1.53.0". at the "adiencealign/resources/" subfolder
|
||||||
|
3. For landmarks detection, we use the file libPartsBasedDetector.so, compiled from the project https://github.com/wg-perception/PartsBasedDetector. You can either compile it yourselves, or use the version under "resources" subfolder, compiled with boost 1.53, on a linux ubuntu 14.04 machine.
|
||||||
|
|
||||||
|
We will release the source code for the shared object in the near future
|
||||||
|
|
||||||
|
Running the test
|
||||||
|
========
|
||||||
|
1. run ```./clear_test.sh``` to delete results of old tests.
|
||||||
|
2. run ```python test_pipeline.py```
|
||||||
|
3. results are in the "outputs" subfolder
|
|
@ -0,0 +1,20 @@
|
||||||
|
'''
|
||||||
|
Created on May 7, 2014
|
||||||
|
|
||||||
|
@author: eran
|
||||||
|
'''
|
||||||
|
from adiencealign.common.landmarks import fidu_transform, shift_vector,\
|
||||||
|
WEIGHTS3
|
||||||
|
|
||||||
|
class AffineAligner(object):
|
||||||
|
def __init__(self, fidu_model_file, ):
|
||||||
|
|
||||||
|
self.shift = ( 0.25, 0.25 )
|
||||||
|
fidu_model = [(int(x.split(',')[1]),int(x.split(',')[2])) for x in file(fidu_model_file,'r')]
|
||||||
|
self.fidu_model = shift_vector(fidu_model, self.shift)
|
||||||
|
self.WEIGHTS3 = WEIGHTS3
|
||||||
|
|
||||||
|
def align(self, img, fidu_points):
|
||||||
|
# create bs1 image
|
||||||
|
funneled_img, R = fidu_transform(self.fidu_model, fidu_points, WEIGHTS3, img, self.shift)
|
||||||
|
return funneled_img, R
|
|
@ -0,0 +1,354 @@
|
||||||
|
'''
|
||||||
|
Created on May 7, 2014
|
||||||
|
|
||||||
|
@author: eran
|
||||||
|
'''
|
||||||
|
import cv2
|
||||||
|
import pickle
|
||||||
|
import numpy as np
|
||||||
|
from shapely.geometry.polygon import Polygon
|
||||||
|
import math
|
||||||
|
from adiencealign.common.files import make_path, expand_path
|
||||||
|
from adiencealign.common.images import pad_image_for_rotation
|
||||||
|
|
||||||
|
class CascadeDetector(object):
|
||||||
|
'''
|
||||||
|
This is a haar cascade classifier capable of detecting in multiple angles
|
||||||
|
'''
|
||||||
|
def __init__(self, cascade_file = './resources/haarcascade_frontalface_default.xml',
|
||||||
|
min_size = (10, 10),
|
||||||
|
min_neighbors = 20,
|
||||||
|
scale_factor = 1.04,
|
||||||
|
angles = [0],
|
||||||
|
thr = 0.4,
|
||||||
|
cascade_type = 'haar'):
|
||||||
|
'''
|
||||||
|
cascade_type - is a string defining the type of cascade
|
||||||
|
'''
|
||||||
|
print(expand_path('.'))
|
||||||
|
self.cascade_file = cascade_file.rsplit('/',1)[1]
|
||||||
|
self._cascade_classifier = cv2.CascadeClassifier(cascade_file)
|
||||||
|
self.scale_factor = scale_factor
|
||||||
|
self.min_neighbors = min_neighbors
|
||||||
|
self.min_size = min_size
|
||||||
|
self.cascade_type = cascade_type
|
||||||
|
self.angles = angles
|
||||||
|
self.thr = thr
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return ''.join([str(x) for x in ['cascade_file:',self.cascade_file,
|
||||||
|
',scale_factor:',self.scale_factor,
|
||||||
|
',min_neighbors:',self.min_neighbors,
|
||||||
|
',min_neighbors:',self.min_neighbors,
|
||||||
|
',cascade_type:',self.cascade_type
|
||||||
|
]])
|
||||||
|
|
||||||
|
def save_configuration(self, target_file):
|
||||||
|
file_path = target_file.rsplit('/',1)[0]
|
||||||
|
make_path(file_path)
|
||||||
|
config = {'min_size':self.min_size, 'min_neighbours':self.min_neighbors, 'scale_factor':self.scale_factor, 'cascade_file':self.cascade_file}
|
||||||
|
pickle.dump(obj=config, file = open(target_file,'w'), protocol = 2)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def load_configuration(target_file):
|
||||||
|
return pickle.load(open(target_file,'r'))
|
||||||
|
|
||||||
|
def detectMultiScaleWithScores(self, img, scaleFactor = None, minNeighbors = None, minSize = None, flags = 4):
|
||||||
|
scaleFactor = self.scale_factor if not scaleFactor else scaleFactor
|
||||||
|
minNeighbors = self.min_neighbors if not minNeighbors else minNeighbors
|
||||||
|
minSize = self.min_size if not minSize else minSize
|
||||||
|
return self._cascade_classifier.detectMultiScale(img,
|
||||||
|
scaleFactor = scaleFactor,
|
||||||
|
minNeighbors = minNeighbors,
|
||||||
|
minSize = minSize,
|
||||||
|
flags = flags)
|
||||||
|
|
||||||
|
def detectWithAngles(self, img, angels = None, resolve = True, thr = None ):
|
||||||
|
'''
|
||||||
|
angles - a list of angles to test. If None, default to the value created at the constructor (which defaults to [0])
|
||||||
|
resolve - a boolean flag, whether or not to cluster the boxes, and resolve cluster by highest score.
|
||||||
|
thr - the maximum area covered with objects, before we break from the angles loop
|
||||||
|
|
||||||
|
returns - a list of CascadeResult() objects
|
||||||
|
'''
|
||||||
|
|
||||||
|
if thr == None:
|
||||||
|
thr = self.thr
|
||||||
|
|
||||||
|
original_size = img.shape[0] * img.shape[0]
|
||||||
|
if angels == None:
|
||||||
|
angels = self.angles
|
||||||
|
|
||||||
|
results = []
|
||||||
|
total_area = 0
|
||||||
|
for angle in angels:
|
||||||
|
|
||||||
|
# the diagonal of the image is the diameter of the rotated image, so the big_image needs to bound this circle
|
||||||
|
# by being that big
|
||||||
|
|
||||||
|
big_image, x_shift, y_shift, diag, rot_center = pad_image_for_rotation(img)
|
||||||
|
|
||||||
|
# find the rotation and the inverse rotation matrix, to allow translations between old and new coordinates and vice versa
|
||||||
|
rot_mat = cv2.getRotationMatrix2D(rot_center, angle, scale = 1.0)
|
||||||
|
inv_rot_mat = cv2.invertAffineTransform(rot_mat)
|
||||||
|
|
||||||
|
# rotate the image by the desired angle
|
||||||
|
rot_image = cv2.warpAffine(big_image, rot_mat, (big_image.shape[1],big_image.shape[0]), flags=cv2.INTER_CUBIC)
|
||||||
|
faces = self.detectMultiScaleWithScores(rot_image, scaleFactor = 1.03, minNeighbors = 20, minSize = (15,15), flags = 4)
|
||||||
|
for face in faces:
|
||||||
|
xp = face[0]
|
||||||
|
dx = face[2]
|
||||||
|
yp = face[1]
|
||||||
|
dy = face[3]
|
||||||
|
score = 1
|
||||||
|
dots = np.matrix([[xp,xp+dx,xp+dx,xp], [yp,yp,yp+dy,yp+dy], [1, 1, 1, 1]])
|
||||||
|
# these are the original coordinates in the "big_image"
|
||||||
|
# print dots
|
||||||
|
originals_in_big = inv_rot_mat * dots
|
||||||
|
# print originals_in_big
|
||||||
|
shifter = np.matrix([[x_shift]*4, [y_shift]*4])
|
||||||
|
# print shifter
|
||||||
|
# these are the original coordinate in the original image
|
||||||
|
originals = originals_in_big - shifter
|
||||||
|
# print originals
|
||||||
|
points = np.array(originals.transpose())
|
||||||
|
x = points[0,0]
|
||||||
|
y = points[0,1]
|
||||||
|
box_with_score = ([x,y,dx,dy], score)
|
||||||
|
|
||||||
|
cascade_result = CascadeResult.from_polygon_points(points, score, self.cascade_type)
|
||||||
|
# print cascade_result
|
||||||
|
|
||||||
|
results.append(cascade_result)
|
||||||
|
|
||||||
|
#################
|
||||||
|
# test and see, if we found enough objects, break out and don't waste our time
|
||||||
|
total_area += cascade_result.area
|
||||||
|
|
||||||
|
if resolve:
|
||||||
|
return resolve_angles(results, width = img.shape[1], height = img.shape[0])
|
||||||
|
else:
|
||||||
|
return results
|
||||||
|
|
||||||
|
class BoxInImage(object):
|
||||||
|
def __init__(self, originals, dx, dy, score = None, angle = 0):
|
||||||
|
self.originals = originals
|
||||||
|
self.dx = dx
|
||||||
|
self.dy = dy
|
||||||
|
self.score = score
|
||||||
|
self.angle = angle
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return ",".join([str(x) for x in [self.originals, self.dx, self.dy, self.score, self.angle]])
|
||||||
|
|
||||||
|
def resolve_angles(list_of_results, width, height, thr = 0.3):
|
||||||
|
'''
|
||||||
|
we want to cluster the boxes into clusters, and then choose the best box in each cluster by score
|
||||||
|
* thr - decides what the maximum distance is for a box to join a cluster, in the sense of how much of it's area is covered by the best box in the cluster
|
||||||
|
note, that two squares, centered, with 45 degrees rotation, will overlap on 77% of their area (thr == 0.22)
|
||||||
|
'''
|
||||||
|
clusters = []
|
||||||
|
for box in list_of_results:
|
||||||
|
# total_polygon = Polygon([(0,0), (width,0), (width,height), (0,height)])
|
||||||
|
# if box.polygon.intersection(total_polygon).area < box.area:
|
||||||
|
# # this means the box is outside the image somehow
|
||||||
|
# continue
|
||||||
|
|
||||||
|
area = box.area
|
||||||
|
closest_cluster = None
|
||||||
|
dist_to_closest_cluster = 1.0
|
||||||
|
for n,cluster in enumerate(clusters):
|
||||||
|
dist = 1.0
|
||||||
|
for cluster_box in cluster:
|
||||||
|
local_dist = 1.0 - box.overlap(cluster_box)/area
|
||||||
|
dist = min(dist, local_dist)
|
||||||
|
if dist < dist_to_closest_cluster:
|
||||||
|
dist_to_closest_cluster = dist
|
||||||
|
closest_cluster = n
|
||||||
|
if closest_cluster == None or dist_to_closest_cluster > thr:
|
||||||
|
# no good cluster was found, open a new cluster
|
||||||
|
clusters.append([box])
|
||||||
|
else:
|
||||||
|
clusters[n].append(box)
|
||||||
|
|
||||||
|
centroids = []
|
||||||
|
for cluster in clusters:
|
||||||
|
centroids.append(sorted(cluster,key=lambda x: x.score)[-1])
|
||||||
|
|
||||||
|
return centroids
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_boxes(dict_of_list_of_cascade_results, min_overlap = 0.7):
|
||||||
|
'''
|
||||||
|
Say you tried two different cascades to detect faces.
|
||||||
|
enter a dictionary (the key is a string describing a cascade type) of detected objects
|
||||||
|
This function returns a unified results list, where it resolves overlapping boxes, and chooses one of them.
|
||||||
|
|
||||||
|
The bigger boxes are selected instead of smaller ones, whether they contain them, or enough of them, determined by min_overlap
|
||||||
|
|
||||||
|
'''
|
||||||
|
final_faces = []
|
||||||
|
for cascade_str, faces in dict_of_list_of_cascade_results.items():
|
||||||
|
# go through each cascade type
|
||||||
|
for face in faces:
|
||||||
|
if type(face) == CascadeResult:
|
||||||
|
new_res = face
|
||||||
|
else:
|
||||||
|
new_res = CascadeResult(face,cascade_type = cascade_str)
|
||||||
|
to_add = True
|
||||||
|
for old_index,old_res in enumerate(final_faces):
|
||||||
|
ratio = new_res.area / old_res.area
|
||||||
|
if ratio >1.0:
|
||||||
|
# new_box is bigger
|
||||||
|
if new_res.overlap(old_res)/old_res.area > min_overlap:
|
||||||
|
# the new box contains the old one, we want to replace it:
|
||||||
|
final_faces[old_index] = new_res
|
||||||
|
to_add = False
|
||||||
|
break
|
||||||
|
if ratio <=1.0:
|
||||||
|
# the new_box is smaller
|
||||||
|
if new_res.overlap(old_res)/new_res.area > min_overlap:
|
||||||
|
# the old box contains the new one, we therefore dont need to add the new box:
|
||||||
|
to_add = False
|
||||||
|
break
|
||||||
|
if to_add:
|
||||||
|
# if there was no hit, this is a new face, we can add it
|
||||||
|
final_faces.append(new_res)
|
||||||
|
return final_faces
|
||||||
|
|
||||||
|
def most_centered_box( cascade_results, xxx_todo_changeme ):
|
||||||
|
( rows, cols ) = xxx_todo_changeme
|
||||||
|
best_err = 1e10
|
||||||
|
for i, cascade in enumerate( cascade_results ):
|
||||||
|
err = ( cascade.x + cascade.dx / 2 - cols / 2 ) ** 2 + ( cascade.y + cascade.dy / 2 - rows / 2 ) ** 2
|
||||||
|
if err < best_err:
|
||||||
|
index = i
|
||||||
|
return cascade_results[ index ]
|
||||||
|
|
||||||
|
class CascadeResult(object):
|
||||||
|
def __init__(self, box_with_score, cascade_type = None, angle = 0):
|
||||||
|
self.x = box_with_score[0][0]
|
||||||
|
self.y = box_with_score[0][1]
|
||||||
|
self.dx = box_with_score[0][2]
|
||||||
|
self.dy = box_with_score[0][3]
|
||||||
|
self.score = box_with_score[1]
|
||||||
|
self.cascade_type = cascade_type
|
||||||
|
self.angle = angle
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_polygon_points(points, score, cascade_type = None):
|
||||||
|
'''
|
||||||
|
an alternative generator, allows giving the polygon points instead of [x,y,dx,dy]
|
||||||
|
'''
|
||||||
|
x = points[0,0]
|
||||||
|
y = points[0,1]
|
||||||
|
top = points[1,] - points[0,]
|
||||||
|
left = points[3,] - points[0,]
|
||||||
|
dx = math.sqrt(sum([i*i for i in top]))
|
||||||
|
dy = math.sqrt(sum([i*i for i in left]))
|
||||||
|
angle = math.atan(float(top[1])/top[0]) * 180 / math.pi if top[0] != 0 else (970 if top[1] >0 else -90)
|
||||||
|
return CascadeResult(([x,y,dx,dy],score), cascade_type, angle)
|
||||||
|
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return ''.join([str(x) for x in ['center:',self.center,
|
||||||
|
',\nx:',self.x,
|
||||||
|
',\ny:',self.y,
|
||||||
|
',\ndx:',self.dx,
|
||||||
|
',\ndy:',self.dy,
|
||||||
|
',\nscore:',self.score,
|
||||||
|
',\nangle:',self.angle,
|
||||||
|
',\ncascade_type:',self.cascade_type,
|
||||||
|
',\npoints_int:\n',self.points_int
|
||||||
|
]])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def points(self):
|
||||||
|
x = self.x
|
||||||
|
y = self.y
|
||||||
|
dx = self.dx
|
||||||
|
dy = self.dy
|
||||||
|
a = self.angle/180.0*math.pi
|
||||||
|
dots = np.matrix([[x,y,1],[x+dx,y,1],[x+dx,y+dy,1],[x,y+dy,1]])
|
||||||
|
dots = dots.transpose()
|
||||||
|
rot_mat = cv2.getRotationMatrix2D((dots[0,0],dots[1,0]), -self.angle, scale = 1.0)
|
||||||
|
points = rot_mat * dots
|
||||||
|
points = points.transpose()
|
||||||
|
return points
|
||||||
|
|
||||||
|
@property
|
||||||
|
def center(self):
|
||||||
|
return tuple(int(x) for x in (self.points.sum(0)/4.0).tolist()[0])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def points_int(self):
|
||||||
|
return self.points.astype(int)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def score_with_type(self):
|
||||||
|
if self.cascade_type:
|
||||||
|
return self.cascade_type + ' ' + str(self.score)
|
||||||
|
else:
|
||||||
|
return str(self.score)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def filename_encode(self):
|
||||||
|
|
||||||
|
return '_'.join([str(x) for x in ['loct'] + self.cvformat_result[0] + ['ang', int(self.angle),self.cascade_type, self.score]])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cvformat_coords(self):
|
||||||
|
if self.angle == 0:
|
||||||
|
return [int(x) for x in [self.x, self.y, self.dx, self.dy]]
|
||||||
|
else:
|
||||||
|
raise Exception('cannot return [x,y,dx,dy] for a box with angle, use cvformat_result() instead')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cvformat_result(self):
|
||||||
|
return ([int(x) for x in [self.x, self.y, self.dx, self.dy]], self.score, self.angle)
|
||||||
|
|
||||||
|
# @property
|
||||||
|
# def rot_matrix(self):
|
||||||
|
# return array([[cos(math.radians(self.angle)), -sin(math.radians(self.angle))],
|
||||||
|
# [sin(math.radians(self.angle)), cos(math.radians(self.angle))]])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def top_left(self):
|
||||||
|
return tuple(self.points[0,].tolist()[0])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def top_right(self):
|
||||||
|
return tuple(self.points[1,].tolist()[0])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def bottom_right(self):
|
||||||
|
return tuple(self.points[2,].tolist()[0])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def bottom_left(self):
|
||||||
|
return tuple(self.points[3,].tolist()[0])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def polygon(self):
|
||||||
|
return Polygon([self.top_left, self.top_right, self.bottom_right, self.bottom_left])
|
||||||
|
|
||||||
|
def overlap(self, otherRect):
|
||||||
|
return float(self.polygon.intersection(otherRect.polygon).area)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def area(self):
|
||||||
|
return float(self.polygon.area)
|
||||||
|
|
||||||
|
def __gt__(self,b):
|
||||||
|
return self.area>b.area
|
||||||
|
def __ge__(self,b):
|
||||||
|
return self.area>=b.area
|
||||||
|
def __lt__(self,b):
|
||||||
|
return self.area<b.area
|
||||||
|
def __le__(self,b):
|
||||||
|
return self.area<=b.area
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,353 @@
|
||||||
|
'''
|
||||||
|
Created on May 7, 2014
|
||||||
|
|
||||||
|
@author: eran
|
||||||
|
'''
|
||||||
|
import cv2
|
||||||
|
import pickle
|
||||||
|
import numpy as np
|
||||||
|
from shapely.geometry.polygon import Polygon
|
||||||
|
import math
|
||||||
|
from adiencealign.common.files import make_path, expand_path
|
||||||
|
from adiencealign.common.images import pad_image_for_rotation
|
||||||
|
|
||||||
|
class CascadeDetector(object):
|
||||||
|
'''
|
||||||
|
This is a haar cascade classifier capable of detecting in multiple angles
|
||||||
|
'''
|
||||||
|
def __init__(self, cascade_file = './resources/haarcascade_frontalface_default.xml',
|
||||||
|
min_size = (10, 10),
|
||||||
|
min_neighbors = 20,
|
||||||
|
scale_factor = 1.04,
|
||||||
|
angles = [0],
|
||||||
|
thr = 0.4,
|
||||||
|
cascade_type = 'haar'):
|
||||||
|
'''
|
||||||
|
cascade_type - is a string defining the type of cascade
|
||||||
|
'''
|
||||||
|
print expand_path('.')
|
||||||
|
self.cascade_file = cascade_file.rsplit('/',1)[1]
|
||||||
|
self._cascade_classifier = cv2.CascadeClassifier(cascade_file)
|
||||||
|
self.scale_factor = scale_factor
|
||||||
|
self.min_neighbors = min_neighbors
|
||||||
|
self.min_size = min_size
|
||||||
|
self.cascade_type = cascade_type
|
||||||
|
self.angles = angles
|
||||||
|
self.thr = thr
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return ''.join([str(x) for x in ['cascade_file:',self.cascade_file,
|
||||||
|
',scale_factor:',self.scale_factor,
|
||||||
|
',min_neighbors:',self.min_neighbors,
|
||||||
|
',min_neighbors:',self.min_neighbors,
|
||||||
|
',cascade_type:',self.cascade_type
|
||||||
|
]])
|
||||||
|
|
||||||
|
def save_configuration(self, target_file):
|
||||||
|
file_path = target_file.rsplit('/',1)[0]
|
||||||
|
make_path(file_path)
|
||||||
|
config = {'min_size':self.min_size, 'min_neighbours':self.min_neighbors, 'scale_factor':self.scale_factor, 'cascade_file':self.cascade_file}
|
||||||
|
pickle.dump(obj=config, file = open(target_file,'w'), protocol = 2)
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def load_configuration(target_file):
|
||||||
|
return pickle.load(open(target_file,'r'))
|
||||||
|
|
||||||
|
def detectMultiScaleWithScores(self, img, scaleFactor = None, minNeighbors = None, minSize = None, flags = 4):
|
||||||
|
scaleFactor = self.scale_factor if not scaleFactor else scaleFactor
|
||||||
|
minNeighbors = self.min_neighbors if not minNeighbors else minNeighbors
|
||||||
|
minSize = self.min_size if not minSize else minSize
|
||||||
|
return self._cascade_classifier.detectMultiScale(img,
|
||||||
|
scaleFactor = scaleFactor,
|
||||||
|
minNeighbors = minNeighbors,
|
||||||
|
minSize = minSize,
|
||||||
|
flags = flags)
|
||||||
|
|
||||||
|
def detectWithAngles(self, img, angels = None, resolve = True, thr = None ):
|
||||||
|
'''
|
||||||
|
angles - a list of angles to test. If None, default to the value created at the constructor (which defaults to [0])
|
||||||
|
resolve - a boolean flag, whether or not to cluster the boxes, and resolve cluster by highest score.
|
||||||
|
thr - the maximum area covered with objects, before we break from the angles loop
|
||||||
|
|
||||||
|
returns - a list of CascadeResult() objects
|
||||||
|
'''
|
||||||
|
|
||||||
|
if thr == None:
|
||||||
|
thr = self.thr
|
||||||
|
|
||||||
|
original_size = img.shape[0] * img.shape[0]
|
||||||
|
if angels == None:
|
||||||
|
angels = self.angles
|
||||||
|
|
||||||
|
results = []
|
||||||
|
total_area = 0
|
||||||
|
for angle in angels:
|
||||||
|
|
||||||
|
# the diagonal of the image is the diameter of the rotated image, so the big_image needs to bound this circle
|
||||||
|
# by being that big
|
||||||
|
|
||||||
|
big_image, x_shift, y_shift, diag, rot_center = pad_image_for_rotation(img)
|
||||||
|
|
||||||
|
# find the rotation and the inverse rotation matrix, to allow translations between old and new coordinates and vice versa
|
||||||
|
rot_mat = cv2.getRotationMatrix2D(rot_center, angle, scale = 1.0)
|
||||||
|
inv_rot_mat = cv2.invertAffineTransform(rot_mat)
|
||||||
|
|
||||||
|
# rotate the image by the desired angle
|
||||||
|
rot_image = cv2.warpAffine(big_image, rot_mat, (big_image.shape[1],big_image.shape[0]), flags=cv2.INTER_CUBIC)
|
||||||
|
faces = self.detectMultiScaleWithScores(rot_image, scaleFactor = 1.03, minNeighbors = 20, minSize = (15,15), flags = 4)
|
||||||
|
for face in faces:
|
||||||
|
xp = face[0]
|
||||||
|
dx = face[2]
|
||||||
|
yp = face[1]
|
||||||
|
dy = face[3]
|
||||||
|
score = 1
|
||||||
|
dots = np.matrix([[xp,xp+dx,xp+dx,xp], [yp,yp,yp+dy,yp+dy], [1, 1, 1, 1]])
|
||||||
|
# these are the original coordinates in the "big_image"
|
||||||
|
# print dots
|
||||||
|
originals_in_big = inv_rot_mat * dots
|
||||||
|
# print originals_in_big
|
||||||
|
shifter = np.matrix([[x_shift]*4, [y_shift]*4])
|
||||||
|
# print shifter
|
||||||
|
# these are the original coordinate in the original image
|
||||||
|
originals = originals_in_big - shifter
|
||||||
|
# print originals
|
||||||
|
points = np.array(originals.transpose())
|
||||||
|
x = points[0,0]
|
||||||
|
y = points[0,1]
|
||||||
|
box_with_score = ([x,y,dx,dy], score)
|
||||||
|
|
||||||
|
cascade_result = CascadeResult.from_polygon_points(points, score, self.cascade_type)
|
||||||
|
# print cascade_result
|
||||||
|
|
||||||
|
results.append(cascade_result)
|
||||||
|
|
||||||
|
#################
|
||||||
|
# test and see, if we found enough objects, break out and don't waste our time
|
||||||
|
total_area += cascade_result.area
|
||||||
|
|
||||||
|
if resolve:
|
||||||
|
return resolve_angles(results, width = img.shape[1], height = img.shape[0])
|
||||||
|
else:
|
||||||
|
return results
|
||||||
|
|
||||||
|
class BoxInImage(object):
|
||||||
|
def __init__(self, originals, dx, dy, score = None, angle = 0):
|
||||||
|
self.originals = originals
|
||||||
|
self.dx = dx
|
||||||
|
self.dy = dy
|
||||||
|
self.score = score
|
||||||
|
self.angle = angle
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return ",".join([str(x) for x in [self.originals, self.dx, self.dy, self.score, self.angle]])
|
||||||
|
|
||||||
|
def resolve_angles(list_of_results, width, height, thr = 0.3):
|
||||||
|
'''
|
||||||
|
we want to cluster the boxes into clusters, and then choose the best box in each cluster by score
|
||||||
|
* thr - decides what the maximum distance is for a box to join a cluster, in the sense of how much of it's area is covered by the best box in the cluster
|
||||||
|
note, that two squares, centered, with 45 degrees rotation, will overlap on 77% of their area (thr == 0.22)
|
||||||
|
'''
|
||||||
|
clusters = []
|
||||||
|
for box in list_of_results:
|
||||||
|
# total_polygon = Polygon([(0,0), (width,0), (width,height), (0,height)])
|
||||||
|
# if box.polygon.intersection(total_polygon).area < box.area:
|
||||||
|
# # this means the box is outside the image somehow
|
||||||
|
# continue
|
||||||
|
|
||||||
|
area = box.area
|
||||||
|
closest_cluster = None
|
||||||
|
dist_to_closest_cluster = 1.0
|
||||||
|
for n,cluster in enumerate(clusters):
|
||||||
|
dist = 1.0
|
||||||
|
for cluster_box in cluster:
|
||||||
|
local_dist = 1.0 - box.overlap(cluster_box)/area
|
||||||
|
dist = min(dist, local_dist)
|
||||||
|
if dist < dist_to_closest_cluster:
|
||||||
|
dist_to_closest_cluster = dist
|
||||||
|
closest_cluster = n
|
||||||
|
if closest_cluster == None or dist_to_closest_cluster > thr:
|
||||||
|
# no good cluster was found, open a new cluster
|
||||||
|
clusters.append([box])
|
||||||
|
else:
|
||||||
|
clusters[n].append(box)
|
||||||
|
|
||||||
|
centroids = []
|
||||||
|
for cluster in clusters:
|
||||||
|
centroids.append(sorted(cluster,key=lambda x: x.score)[-1])
|
||||||
|
|
||||||
|
return centroids
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def resolve_boxes(dict_of_list_of_cascade_results, min_overlap = 0.7):
|
||||||
|
'''
|
||||||
|
Say you tried two different cascades to detect faces.
|
||||||
|
enter a dictionary (the key is a string describing a cascade type) of detected objects
|
||||||
|
This function returns a unified results list, where it resolves overlapping boxes, and chooses one of them.
|
||||||
|
|
||||||
|
The bigger boxes are selected instead of smaller ones, whether they contain them, or enough of them, determined by min_overlap
|
||||||
|
|
||||||
|
'''
|
||||||
|
final_faces = []
|
||||||
|
for cascade_str, faces in dict_of_list_of_cascade_results.iteritems():
|
||||||
|
# go through each cascade type
|
||||||
|
for face in faces:
|
||||||
|
if type(face) == CascadeResult:
|
||||||
|
new_res = face
|
||||||
|
else:
|
||||||
|
new_res = CascadeResult(face,cascade_type = cascade_str)
|
||||||
|
to_add = True
|
||||||
|
for old_index,old_res in enumerate(final_faces):
|
||||||
|
ratio = new_res.area / old_res.area
|
||||||
|
if ratio >1.0:
|
||||||
|
# new_box is bigger
|
||||||
|
if new_res.overlap(old_res)/old_res.area > min_overlap:
|
||||||
|
# the new box contains the old one, we want to replace it:
|
||||||
|
final_faces[old_index] = new_res
|
||||||
|
to_add = False
|
||||||
|
break
|
||||||
|
if ratio <=1.0:
|
||||||
|
# the new_box is smaller
|
||||||
|
if new_res.overlap(old_res)/new_res.area > min_overlap:
|
||||||
|
# the old box contains the new one, we therefore dont need to add the new box:
|
||||||
|
to_add = False
|
||||||
|
break
|
||||||
|
if to_add:
|
||||||
|
# if there was no hit, this is a new face, we can add it
|
||||||
|
final_faces.append(new_res)
|
||||||
|
return final_faces
|
||||||
|
|
||||||
|
def most_centered_box( cascade_results, ( rows, cols ) ):
|
||||||
|
best_err = 1e10
|
||||||
|
for i, cascade in enumerate( cascade_results ):
|
||||||
|
err = ( cascade.x + cascade.dx / 2 - cols / 2 ) ** 2 + ( cascade.y + cascade.dy / 2 - rows / 2 ) ** 2
|
||||||
|
if err < best_err:
|
||||||
|
index = i
|
||||||
|
return cascade_results[ index ]
|
||||||
|
|
||||||
|
class CascadeResult(object):
|
||||||
|
def __init__(self, box_with_score, cascade_type = None, angle = 0):
|
||||||
|
self.x = box_with_score[0][0]
|
||||||
|
self.y = box_with_score[0][1]
|
||||||
|
self.dx = box_with_score[0][2]
|
||||||
|
self.dy = box_with_score[0][3]
|
||||||
|
self.score = box_with_score[1]
|
||||||
|
self.cascade_type = cascade_type
|
||||||
|
self.angle = angle
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def from_polygon_points(points, score, cascade_type = None):
|
||||||
|
'''
|
||||||
|
an alternative generator, allows giving the polygon points instead of [x,y,dx,dy]
|
||||||
|
'''
|
||||||
|
x = points[0,0]
|
||||||
|
y = points[0,1]
|
||||||
|
top = points[1,] - points[0,]
|
||||||
|
left = points[3,] - points[0,]
|
||||||
|
dx = math.sqrt(sum([i*i for i in top]))
|
||||||
|
dy = math.sqrt(sum([i*i for i in left]))
|
||||||
|
angle = math.atan(float(top[1])/top[0]) * 180 / math.pi if top[0] != 0 else (970 if top[1] >0 else -90)
|
||||||
|
return CascadeResult(([x,y,dx,dy],score), cascade_type, angle)
|
||||||
|
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return ''.join([str(x) for x in ['center:',self.center,
|
||||||
|
',\nx:',self.x,
|
||||||
|
',\ny:',self.y,
|
||||||
|
',\ndx:',self.dx,
|
||||||
|
',\ndy:',self.dy,
|
||||||
|
',\nscore:',self.score,
|
||||||
|
',\nangle:',self.angle,
|
||||||
|
',\ncascade_type:',self.cascade_type,
|
||||||
|
',\npoints_int:\n',self.points_int
|
||||||
|
]])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def points(self):
|
||||||
|
x = self.x
|
||||||
|
y = self.y
|
||||||
|
dx = self.dx
|
||||||
|
dy = self.dy
|
||||||
|
a = self.angle/180.0*math.pi
|
||||||
|
dots = np.matrix([[x,y,1],[x+dx,y,1],[x+dx,y+dy,1],[x,y+dy,1]])
|
||||||
|
dots = dots.transpose()
|
||||||
|
rot_mat = cv2.getRotationMatrix2D((dots[0,0],dots[1,0]), -self.angle, scale = 1.0)
|
||||||
|
points = rot_mat * dots
|
||||||
|
points = points.transpose()
|
||||||
|
return points
|
||||||
|
|
||||||
|
@property
|
||||||
|
def center(self):
|
||||||
|
return tuple(int(x) for x in (self.points.sum(0)/4.0).tolist()[0])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def points_int(self):
|
||||||
|
return self.points.astype(int)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def score_with_type(self):
|
||||||
|
if self.cascade_type:
|
||||||
|
return self.cascade_type + ' ' + str(self.score)
|
||||||
|
else:
|
||||||
|
return str(self.score)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def filename_encode(self):
|
||||||
|
|
||||||
|
return '_'.join([str(x) for x in ['loct'] + self.cvformat_result[0] + ['ang', int(self.angle),self.cascade_type, self.score]])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cvformat_coords(self):
|
||||||
|
if self.angle == 0:
|
||||||
|
return [int(x) for x in [self.x, self.y, self.dx, self.dy]]
|
||||||
|
else:
|
||||||
|
raise Exception('cannot return [x,y,dx,dy] for a box with angle, use cvformat_result() instead')
|
||||||
|
|
||||||
|
@property
|
||||||
|
def cvformat_result(self):
|
||||||
|
return ([int(x) for x in [self.x, self.y, self.dx, self.dy]], self.score, self.angle)
|
||||||
|
|
||||||
|
# @property
|
||||||
|
# def rot_matrix(self):
|
||||||
|
# return array([[cos(math.radians(self.angle)), -sin(math.radians(self.angle))],
|
||||||
|
# [sin(math.radians(self.angle)), cos(math.radians(self.angle))]])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def top_left(self):
|
||||||
|
return tuple(self.points[0,].tolist()[0])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def top_right(self):
|
||||||
|
return tuple(self.points[1,].tolist()[0])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def bottom_right(self):
|
||||||
|
return tuple(self.points[2,].tolist()[0])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def bottom_left(self):
|
||||||
|
return tuple(self.points[3,].tolist()[0])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def polygon(self):
|
||||||
|
return Polygon([self.top_left, self.top_right, self.bottom_right, self.bottom_left])
|
||||||
|
|
||||||
|
def overlap(self, otherRect):
|
||||||
|
return float(self.polygon.intersection(otherRect.polygon).area)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def area(self):
|
||||||
|
return float(self.polygon.area)
|
||||||
|
|
||||||
|
def __gt__(self,b):
|
||||||
|
return self.area>b.area
|
||||||
|
def __ge__(self,b):
|
||||||
|
return self.area>=b.area
|
||||||
|
def __lt__(self,b):
|
||||||
|
return self.area<b.area
|
||||||
|
def __le__(self,b):
|
||||||
|
return self.area<=b.area
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,153 @@
|
||||||
|
'''
|
||||||
|
Created on May 7, 2014
|
||||||
|
|
||||||
|
@author: eran
|
||||||
|
'''
|
||||||
|
from adiencealign.common.images import extract_box
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
from adiencealign.cascade_detection.cascade_detector import CascadeDetector,\
|
||||||
|
resolve_boxes, CascadeResult
|
||||||
|
import cv2
|
||||||
|
import csv
|
||||||
|
'''
|
||||||
|
Created on Dec 18, 2013
|
||||||
|
|
||||||
|
@author: eran
|
||||||
|
'''
|
||||||
|
'''
|
||||||
|
Created on Nov 26, 2013
|
||||||
|
|
||||||
|
@author: eran
|
||||||
|
'''
|
||||||
|
|
||||||
|
class CascadeFaceFinder(object):
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
min_size = 32,
|
||||||
|
drawn_target_res = 360*360,
|
||||||
|
hangles = [0, -22, 22],
|
||||||
|
langles = [0,-45,-22,22,45],
|
||||||
|
haar_file = 'haarcascade_frontalface_default.xml',
|
||||||
|
lbp_file = 'lbpcascade_frontalface.xml'):
|
||||||
|
'''
|
||||||
|
finder = CascadeFaceFinder(min_size = 32, drawn_target_res = 360*360, hangles = [0], langles = [0,-45,-22,22,45], parts_threshold = 0)
|
||||||
|
|
||||||
|
finder.get_faces_in_folder(input_folder, output_dir, drawn_folder, is_small_drawn)
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
finder.get_faces_in_photo(full_file, output_dir, drawn_folder, is_small_drawn)
|
||||||
|
'''
|
||||||
|
self.min_size = (min_size,min_size)
|
||||||
|
self.drawn_target_res = drawn_target_res
|
||||||
|
self._hangles = hangles
|
||||||
|
self._langles = langles
|
||||||
|
self.recalc_detectors(haar_file, lbp_file)
|
||||||
|
|
||||||
|
# self.funnel = FaceFunnel()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def hangles(self):
|
||||||
|
return self._hangles
|
||||||
|
|
||||||
|
@hangles.setter
|
||||||
|
def hangles(self,hangles):
|
||||||
|
self._hangles = hangles
|
||||||
|
self.recalc_detectors()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def langles(self):
|
||||||
|
return self._langles
|
||||||
|
|
||||||
|
@langles.setter
|
||||||
|
def langles(self,langles):
|
||||||
|
self._langles = langles
|
||||||
|
self.recalc_detectors()
|
||||||
|
|
||||||
|
def recalc_detectors(self, haar_file, lbp_file):
|
||||||
|
self.haar_dtct = CascadeDetector(cascade_file = haar_file,
|
||||||
|
min_size = self.min_size,
|
||||||
|
min_neighbors = 20,
|
||||||
|
scale_factor = 1.03,
|
||||||
|
cascade_type = 'haar',
|
||||||
|
thr = 0.4,
|
||||||
|
angles = self.hangles)
|
||||||
|
|
||||||
|
self.lbp_dtct = CascadeDetector(cascade_file = lbp_file,
|
||||||
|
min_size = self.min_size,
|
||||||
|
min_neighbors = 15,
|
||||||
|
scale_factor = 1.04,
|
||||||
|
cascade_type = 'lbp',
|
||||||
|
thr = 0.4,
|
||||||
|
angles = self.langles)
|
||||||
|
|
||||||
|
|
||||||
|
def get_faces_list_in_photo(self, img):
|
||||||
|
if self.hangles:
|
||||||
|
haar_faces = self.haar_dtct.detectWithAngles(img, resolve = True)
|
||||||
|
else:
|
||||||
|
haar_faces = []
|
||||||
|
lbp_faces = self.lbp_dtct.detectWithAngles(img, resolve = True)
|
||||||
|
faces = resolve_boxes({'haar':haar_faces, 'lbp':lbp_faces}, min_overlap = 0.6)
|
||||||
|
|
||||||
|
return faces
|
||||||
|
|
||||||
|
def create_faces_file(self, fname, is_overwrite = False, target_file = None):
|
||||||
|
'''
|
||||||
|
Runs facial detection on fname (say a.jpg, or a.png), and creates a results file (a.faces.txt)
|
||||||
|
|
||||||
|
target_file - override, and specify a specific target file
|
||||||
|
is_overwrite - allow overwriting an existing results file
|
||||||
|
'''
|
||||||
|
faces = self.get_faces_list_in_photo(cv2.imread(fname))
|
||||||
|
results_file = fname.rsplit('.',1)[0] + '.faces.txt' if target_file is None else target_file
|
||||||
|
|
||||||
|
if os.path.exists(results_file) and not is_overwrite:
|
||||||
|
print("Warning, faces result file", results_file, "exists")
|
||||||
|
else:
|
||||||
|
with open(results_file,'w') as csvfile:
|
||||||
|
csv_writer = csv.writer(csvfile, delimiter=',')
|
||||||
|
header = ['x', 'y','dx','dy', 'score', 'angle', 'type']
|
||||||
|
csv_writer.writerow(header)
|
||||||
|
for face in faces:
|
||||||
|
csv_writer.writerow([str(i) for i in [int(face.x), int(face.y), int(face.dx), int(face.dy), face.score, face.angle, face.cascade_type]])
|
||||||
|
return results_file
|
||||||
|
|
||||||
|
def get_sub_images_from_file(self,original_image_file, faces_file):
|
||||||
|
'''
|
||||||
|
extracts all the face sub-images from an image file, based on the results in a faces file
|
||||||
|
|
||||||
|
returns - the list of face images (numpy arrays)
|
||||||
|
'''
|
||||||
|
img = cv2.imread(original_image_file)
|
||||||
|
faces_reader = csv.reader(open(faces_file))
|
||||||
|
next(faces_reader) # discard the headings
|
||||||
|
padded_face_images = []
|
||||||
|
for line in faces_reader:
|
||||||
|
x, y, dx, dy, score, angle, cascade_type = line
|
||||||
|
[x,y,dx,dy,score, angle] = [int(float(i)) for i in [x,y,dx,dy,score, angle]]
|
||||||
|
face = CascadeResult(([x,y,dx,dy], score), cascade_type, angle)
|
||||||
|
padded_face, bounding_box_in_padded_face, _, _ = extract_box(img, face, padding_factor = 0.25)
|
||||||
|
padded_face_images.append(padded_face)
|
||||||
|
return padded_face_images
|
||||||
|
|
||||||
|
def create_sub_images_from_file(self, original_image_file, faces_file, target_folder = None, img_type = 'png'):
|
||||||
|
'''
|
||||||
|
reads a faces file, created by "self.create_faces_file" and extracts padded faces from the original image
|
||||||
|
The faces will be created in the same folder as the faces file, unless specified otherwise by "target_folder"
|
||||||
|
|
||||||
|
returns - the list of face files (strings)
|
||||||
|
'''
|
||||||
|
target_folder = os.path.split(faces_file)[0] if target_folder is None else target_folder
|
||||||
|
padded_face_images = self.get_sub_images_from_file(original_image_file, faces_file)
|
||||||
|
|
||||||
|
base_image_name = os.path.split(faces_file)[1].split('.')[0]
|
||||||
|
face_files = []
|
||||||
|
for n_face, face_img in enumerate(padded_face_images):
|
||||||
|
face_file = os.path.join(target_folder, base_image_name + '_face_%d.%s' %(n_face, img_type))
|
||||||
|
cv2.imwrite( face_file , face_img )
|
||||||
|
face_files.append(face_file)
|
||||||
|
return face_files
|
||||||
|
|
|
@ -0,0 +1,153 @@
|
||||||
|
'''
|
||||||
|
Created on May 7, 2014
|
||||||
|
|
||||||
|
@author: eran
|
||||||
|
'''
|
||||||
|
from adiencealign.common.images import extract_box
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
from adiencealign.cascade_detection.cascade_detector import CascadeDetector,\
|
||||||
|
resolve_boxes, CascadeResult
|
||||||
|
import cv2
|
||||||
|
import csv
|
||||||
|
'''
|
||||||
|
Created on Dec 18, 2013
|
||||||
|
|
||||||
|
@author: eran
|
||||||
|
'''
|
||||||
|
'''
|
||||||
|
Created on Nov 26, 2013
|
||||||
|
|
||||||
|
@author: eran
|
||||||
|
'''
|
||||||
|
|
||||||
|
class CascadeFaceFinder(object):
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
min_size = 32,
|
||||||
|
drawn_target_res = 360*360,
|
||||||
|
hangles = [0, -22, 22],
|
||||||
|
langles = [0,-45,-22,22,45],
|
||||||
|
haar_file = 'haarcascade_frontalface_default.xml',
|
||||||
|
lbp_file = 'lbpcascade_frontalface.xml'):
|
||||||
|
'''
|
||||||
|
finder = CascadeFaceFinder(min_size = 32, drawn_target_res = 360*360, hangles = [0], langles = [0,-45,-22,22,45], parts_threshold = 0)
|
||||||
|
|
||||||
|
finder.get_faces_in_folder(input_folder, output_dir, drawn_folder, is_small_drawn)
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
finder.get_faces_in_photo(full_file, output_dir, drawn_folder, is_small_drawn)
|
||||||
|
'''
|
||||||
|
self.min_size = (min_size,min_size)
|
||||||
|
self.drawn_target_res = drawn_target_res
|
||||||
|
self._hangles = hangles
|
||||||
|
self._langles = langles
|
||||||
|
self.recalc_detectors(haar_file, lbp_file)
|
||||||
|
|
||||||
|
# self.funnel = FaceFunnel()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def hangles(self):
|
||||||
|
return self._hangles
|
||||||
|
|
||||||
|
@hangles.setter
|
||||||
|
def hangles(self,hangles):
|
||||||
|
self._hangles = hangles
|
||||||
|
self.recalc_detectors()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def langles(self):
|
||||||
|
return self._langles
|
||||||
|
|
||||||
|
@langles.setter
|
||||||
|
def langles(self,langles):
|
||||||
|
self._langles = langles
|
||||||
|
self.recalc_detectors()
|
||||||
|
|
||||||
|
def recalc_detectors(self, haar_file, lbp_file):
|
||||||
|
self.haar_dtct = CascadeDetector(cascade_file = haar_file,
|
||||||
|
min_size = self.min_size,
|
||||||
|
min_neighbors = 20,
|
||||||
|
scale_factor = 1.03,
|
||||||
|
cascade_type = 'haar',
|
||||||
|
thr = 0.4,
|
||||||
|
angles = self.hangles)
|
||||||
|
|
||||||
|
self.lbp_dtct = CascadeDetector(cascade_file = lbp_file,
|
||||||
|
min_size = self.min_size,
|
||||||
|
min_neighbors = 15,
|
||||||
|
scale_factor = 1.04,
|
||||||
|
cascade_type = 'lbp',
|
||||||
|
thr = 0.4,
|
||||||
|
angles = self.langles)
|
||||||
|
|
||||||
|
|
||||||
|
def get_faces_list_in_photo(self, img):
|
||||||
|
if self.hangles:
|
||||||
|
haar_faces = self.haar_dtct.detectWithAngles(img, resolve = True)
|
||||||
|
else:
|
||||||
|
haar_faces = []
|
||||||
|
lbp_faces = self.lbp_dtct.detectWithAngles(img, resolve = True)
|
||||||
|
faces = resolve_boxes({'haar':haar_faces, 'lbp':lbp_faces}, min_overlap = 0.6)
|
||||||
|
|
||||||
|
return faces
|
||||||
|
|
||||||
|
def create_faces_file(self, fname, is_overwrite = False, target_file = None):
|
||||||
|
'''
|
||||||
|
Runs facial detection on fname (say a.jpg, or a.png), and creates a results file (a.faces.txt)
|
||||||
|
|
||||||
|
target_file - override, and specify a specific target file
|
||||||
|
is_overwrite - allow overwriting an existing results file
|
||||||
|
'''
|
||||||
|
faces = self.get_faces_list_in_photo(cv2.imread(fname))
|
||||||
|
results_file = fname.rsplit('.',1)[0] + '.faces.txt' if target_file is None else target_file
|
||||||
|
|
||||||
|
if os.path.exists(results_file) and not is_overwrite:
|
||||||
|
print "Warning, faces result file", results_file, "exists"
|
||||||
|
else:
|
||||||
|
with open(results_file,'w') as csvfile:
|
||||||
|
csv_writer = csv.writer(csvfile, delimiter=',')
|
||||||
|
header = ['x', 'y','dx','dy', 'score', 'angle', 'type']
|
||||||
|
csv_writer.writerow(header)
|
||||||
|
for face in faces:
|
||||||
|
csv_writer.writerow([str(i) for i in [int(face.x), int(face.y), int(face.dx), int(face.dy), face.score, face.angle, face.cascade_type]])
|
||||||
|
return results_file
|
||||||
|
|
||||||
|
def get_sub_images_from_file(self,original_image_file, faces_file):
|
||||||
|
'''
|
||||||
|
extracts all the face sub-images from an image file, based on the results in a faces file
|
||||||
|
|
||||||
|
returns - the list of face images (numpy arrays)
|
||||||
|
'''
|
||||||
|
img = cv2.imread(original_image_file)
|
||||||
|
faces_reader = csv.reader(open(faces_file))
|
||||||
|
faces_reader.next() # discard the headings
|
||||||
|
padded_face_images = []
|
||||||
|
for line in faces_reader:
|
||||||
|
x, y, dx, dy, score, angle, cascade_type = line
|
||||||
|
[x,y,dx,dy,score, angle] = [int(float(i)) for i in [x,y,dx,dy,score, angle]]
|
||||||
|
face = CascadeResult(([x,y,dx,dy], score), cascade_type, angle)
|
||||||
|
padded_face, bounding_box_in_padded_face, _, _ = extract_box(img, face, padding_factor = 0.25)
|
||||||
|
padded_face_images.append(padded_face)
|
||||||
|
return padded_face_images
|
||||||
|
|
||||||
|
def create_sub_images_from_file(self, original_image_file, faces_file, target_folder = None, img_type = 'png'):
|
||||||
|
'''
|
||||||
|
reads a faces file, created by "self.create_faces_file" and extracts padded faces from the original image
|
||||||
|
The faces will be created in the same folder as the faces file, unless specified otherwise by "target_folder"
|
||||||
|
|
||||||
|
returns - the list of face files (strings)
|
||||||
|
'''
|
||||||
|
target_folder = os.path.split(faces_file)[0] if target_folder is None else target_folder
|
||||||
|
padded_face_images = self.get_sub_images_from_file(original_image_file, faces_file)
|
||||||
|
|
||||||
|
base_image_name = os.path.split(faces_file)[1].split('.')[0]
|
||||||
|
face_files = []
|
||||||
|
for n_face, face_img in enumerate(padded_face_images):
|
||||||
|
face_file = os.path.join(target_folder, base_image_name + '_face_%d.%s' %(n_face, img_type))
|
||||||
|
cv2.imwrite( face_file , face_img )
|
||||||
|
face_files.append(face_file)
|
||||||
|
return face_files
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
'''
|
||||||
|
Created on May 7, 2014
|
||||||
|
|
||||||
|
@author: eran
|
||||||
|
'''
|
||||||
|
import cv2
|
||||||
|
from adiencealign.cascade_detection.cascade_detector import CascadeResult
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
def draw_rect(img, r, angle = 0, color=(255,255,255), thickness = 4, alpha = 0.5):
|
||||||
|
'''
|
||||||
|
accepts:
|
||||||
|
1. a (x,y,dx,dy) list
|
||||||
|
4. a [(x,y,dx,dy),score] list, as returned by cv2.CascadeClassifier.detectMultiScaleWithScores()
|
||||||
|
5. a CascadeResult object
|
||||||
|
'''
|
||||||
|
if type(r) == CascadeResult:
|
||||||
|
color = tuple(list(color) + [alpha])
|
||||||
|
cv2.polylines(img, pts = [r.points_int], isClosed = True, color = color, thickness = thickness)
|
||||||
|
return
|
||||||
|
elif len(r)==4 or len(r)==2: # [x,y,dx,dy]
|
||||||
|
if len(r)==2:
|
||||||
|
if len(r[0]) == 4:
|
||||||
|
r = r[0]
|
||||||
|
else:
|
||||||
|
raise Exception("bad input to draw_rect...")
|
||||||
|
pt1 = int(round(r[0])), int(round(r[1]))
|
||||||
|
pt2 = int(round(r[0]+r[2])), int(round(r[1]+r[3]))
|
||||||
|
color = tuple(list(color) + [alpha])
|
||||||
|
cv2.rectangle(img, pt1, pt2, color, thickness = thickness)
|
||||||
|
else:
|
||||||
|
raise Exception("bad input to draw_rect...")
|
||||||
|
return
|
|
@ -0,0 +1,22 @@
|
||||||
|
'''
|
||||||
|
Created on May 7, 2014
|
||||||
|
|
||||||
|
@author: eran
|
||||||
|
'''
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
from os.path import expanduser
|
||||||
|
|
||||||
|
def make_path(path, delete_content_if_exists = False):
|
||||||
|
if not os.path.exists(path):
|
||||||
|
os.makedirs(path)
|
||||||
|
elif delete_content_if_exists:
|
||||||
|
shutil.rmtree(path)
|
||||||
|
|
||||||
|
def expand_path(file_or_path):
|
||||||
|
if file_or_path.startswith('~/'):
|
||||||
|
home = expanduser("~")
|
||||||
|
file_at = os.path.join(home,file_or_path[2:])
|
||||||
|
return file_at
|
||||||
|
else:
|
||||||
|
return file_or_path
|
|
@ -0,0 +1,87 @@
|
||||||
|
'''
|
||||||
|
Created on May 7, 2014
|
||||||
|
|
||||||
|
@author: eran
|
||||||
|
'''
|
||||||
|
import math
|
||||||
|
import numpy as np
|
||||||
|
import cv2
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def pad_image_for_rotation(img):
|
||||||
|
# we pad the image so, when we rotate it, it would never be clipped
|
||||||
|
rot_y,rot_x = img.shape[:2]
|
||||||
|
rot_x = int(rot_x / 2.0)
|
||||||
|
rot_y = int(rot_y / 2.0)
|
||||||
|
diag = int(math.sqrt(sum([math.pow(x,2) for x in img.shape])))
|
||||||
|
diag = int(math.ceil(diag / 2.0) * 2.0) # make sure it is even
|
||||||
|
if len(img.shape) == 3:
|
||||||
|
big_image = np.zeros((diag, diag, 3), dtype=np.uint8)
|
||||||
|
else:
|
||||||
|
big_image = np.zeros((diag, diag), dtype=np.uint8)
|
||||||
|
x_shift = int(diag/2-rot_x)
|
||||||
|
y_shift = int(diag/2-rot_y)
|
||||||
|
# the shift of the old image within big_image
|
||||||
|
if len(img.shape) == 3:
|
||||||
|
big_image[y_shift :y_shift+img.shape[0], x_shift:x_shift+img.shape[1], :] = img
|
||||||
|
else:
|
||||||
|
big_image[y_shift :y_shift+img.shape[0], x_shift:x_shift+img.shape[1]] = img
|
||||||
|
|
||||||
|
# the rotation center is no the radius (half the old image diagonal)
|
||||||
|
rot_center = diag/2, diag/2
|
||||||
|
return big_image, x_shift, y_shift, diag, rot_center
|
||||||
|
|
||||||
|
|
||||||
|
def extract_rect(img, rect, factor = 0.2):
|
||||||
|
(x,y,dx,dy) = rect
|
||||||
|
new_x = max(0, int(x-dx*factor))
|
||||||
|
new_y = max(0, int(y-dy*factor))
|
||||||
|
new_dx = min(int(dx+2*factor*dx), img.shape[1] - new_x)
|
||||||
|
new_dy = min(int(dy+2*factor*dy), img.shape[0] - new_y)
|
||||||
|
Dx = x - new_x
|
||||||
|
Dy = y - new_y
|
||||||
|
#return [new_x, new_y, new_dx, new_dy]
|
||||||
|
return img[new_y:new_y+new_dy,new_x:new_x+new_dx,:], Dx, Dy
|
||||||
|
|
||||||
|
|
||||||
|
def extract_box(img, box, padding_factor = 0.2):
|
||||||
|
'''
|
||||||
|
we can search for whatever we want in the rotated bordered image,
|
||||||
|
|
||||||
|
Any point found can be translated back to the original image by:
|
||||||
|
1. adding the origins of the bordered area,
|
||||||
|
2. rotating the point using the inverse rotation matrix
|
||||||
|
|
||||||
|
'''
|
||||||
|
|
||||||
|
if box.angle != 0:
|
||||||
|
|
||||||
|
b_w = max(img.shape)*2
|
||||||
|
b_h = b_w
|
||||||
|
dx_center = b_w / 2 - box.center[0]
|
||||||
|
dy_center = b_h / 2 - box.center[1]
|
||||||
|
new_img = np.zeros((b_w, b_h, 3), dtype = img.dtype)
|
||||||
|
new_img[dy_center:(dy_center + img.shape[0]), dx_center:(dx_center + img.shape[1]), :] = img
|
||||||
|
|
||||||
|
box_in_big_image = box.points + np.c_[np.ones((4,1)) * dx_center, np.ones((4,1)) * dy_center]
|
||||||
|
|
||||||
|
rot_mat = cv2.getRotationMatrix2D((b_w/2, b_h/2), box.angle, scale = 1.0)
|
||||||
|
inv_rot_mat = cv2.invertAffineTransform(rot_mat)
|
||||||
|
rot_image = cv2.warpAffine(new_img, rot_mat, (new_img.shape[1],new_img.shape[0]), flags=cv2.INTER_CUBIC)
|
||||||
|
box_UL_in_rotated = (rot_mat * np.matrix([box_in_big_image[0,0], box_in_big_image[0,1], 1]).transpose()).transpose().tolist()[0]
|
||||||
|
box_coords_in_rotated = np.matrix(np.c_[box_in_big_image, np.ones((4,1))]) * rot_mat.T
|
||||||
|
box_coords_in_rotated = box_coords_in_rotated[0,:].tolist()[0] + [box.dx, box.dy]
|
||||||
|
else:
|
||||||
|
rot_mat = cv2.getRotationMatrix2D(box.center, box.angle, scale = 1.0)
|
||||||
|
inv_rot_mat = cv2.invertAffineTransform(rot_mat)
|
||||||
|
# for efficiency
|
||||||
|
rot_image = img.copy()
|
||||||
|
box_UL_in_rotated = (rot_mat * np.matrix([box.points[0,0], box.points[0,1], 1]).transpose()).transpose().tolist()[0]
|
||||||
|
box_coords_in_rotated = box_UL_in_rotated + [box.dx, box.dy]
|
||||||
|
|
||||||
|
img_with_border, Dx, Dy = extract_rect(rot_image, box_coords_in_rotated, padding_factor)
|
||||||
|
box_coords_in_bordered = [Dx, Dy] + [box.dx, box.dy]
|
||||||
|
border_UL_in_rotated = [box_UL_in_rotated[0]-Dx, box_UL_in_rotated[1]-Dy]
|
||||||
|
|
||||||
|
return img_with_border, box_coords_in_bordered, border_UL_in_rotated, inv_rot_mat
|
|
@ -0,0 +1,113 @@
|
||||||
|
'''
|
||||||
|
Created on May 7, 2014
|
||||||
|
|
||||||
|
@author: eran
|
||||||
|
'''
|
||||||
|
|
||||||
|
import csv
|
||||||
|
import cv2
|
||||||
|
from numpy import linalg
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
|
WEIGHTS3 = [11.1088851746,15.8721645013,12.3189439894,15.9467104922,13.9265119716,17.2447706133,11.4118267639,17.0728365324,12.7831886739,17.1908773151,9.6639887492,13.8443342456,8.76890470223,11.4441704453,7.52083144762,10.3245662427,6.35563072919,7.55739887985,6.42340544936,7.48786881875,10.8720924456,8.1349958353,12.3664410374,9.58137800608,6.29390307208,9.47697088783,8.49859202931,9.43946799727,7.92920023102,10.6126442536,10.2953809171,11.299323189,11.1181958685,12.9374719654,12.3764338392,14.7823225327,13.086272904,16.0571795811,15.079169884,17.5936174739,8.39112414861,7.68532826996,8.89386612449,8.70173923211,10.0826620269,8.70286074207,8.13121344224,9.80805203263,7.76044090777,9.2502084627,7.61334683331,10.4813589698,8.64831020289,11.0452512508,9.19528177019,13.0171747152,10.1204323102,14.0189765809,11.0232436734,14.7355286373,12.4881579947,15.4279914333,11.5785971474,16.7942051778,12.4916161829,17.57726411,14.3422306002,19.3015061859,16.3109851665,23.7227227093,17.7687071538,22.6848438204,14.9879312002,18.6763354368,12.927920123,17.7652660198,10.3584444834,15.5584775245,10.660322225,15.4351684107,11.6468441007,13.7962556973,12.9019472625,16.6407866045,13.1946878458,16.4137518526,9.86525395127,11.6687513083,10.4858060411,12.8407630953,9.24210197996,10.9728479778,9.37639005327,12.3418022852,12.2786533953,12.0629300205,14.8495857728,15.4667996708,14.7414922143,15.2761005039,8.5837102275,10.8010609515,6.55275411638,14.4240347981,10.4200283162,17.6888997346,11.4480670185,22.4669420211,13.1705102756,29.3073334802,16.9922725597,35.4031969543,18.7102372238,41.7466671473,21.7036998929,47.1495172267,24.4179633642,51.9023425203,26.6870471848,57.5921966087,7.71654443362,18.3796425232,9.84932443383,23.3915673615,15.7135746598,31.5768046636,18.159161567,39.0502675506,20.5154926286,44.6961338521,22.8541610324,50.9071591504,26.5569627651,54.4338495899,29.1062390164,61.5990210977]
|
||||||
|
|
||||||
|
def read_fidu(fidu_name):
|
||||||
|
fidu_reader = csv.reader(open(fidu_name))
|
||||||
|
try:
|
||||||
|
line = next(fidu_reader)
|
||||||
|
score, yaw_angle = line
|
||||||
|
next(fidu_reader)
|
||||||
|
fidu_points = [[int(float(field)) for field in row[-2:]] for row in fidu_reader]
|
||||||
|
return int(score), int(yaw_angle), fidu_points
|
||||||
|
except:
|
||||||
|
if line[0] == 'nothing found':
|
||||||
|
return -1000, None, None
|
||||||
|
else:
|
||||||
|
raise Exception('Corrupt Fidu File ' + fidu_name)
|
||||||
|
|
||||||
|
|
||||||
|
def draw_fidu(img, fidu_points, radius = 3, color = (255,0,0), thickness = 1, draw_numbers_color = None):
|
||||||
|
'''
|
||||||
|
set draw_numbers_color = (COLOR_BLUE), for example, to draw the point numbers
|
||||||
|
'''
|
||||||
|
for n,point in enumerate(fidu_points):
|
||||||
|
cv2.circle(img, tuple([int(x) for x in point]),radius,color, thickness)
|
||||||
|
if draw_numbers_color:
|
||||||
|
cv2.putText( img,
|
||||||
|
'%d' %n,
|
||||||
|
tuple([int(point[0])-4, int(point[1])-4]),
|
||||||
|
cv2.FONT_HERSHEY_COMPLEX,
|
||||||
|
0.35,
|
||||||
|
draw_numbers_color,
|
||||||
|
thickness = 1 )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _compute_affine_transform_cvpy(refpoints, points, w = None): # Copied from the book
|
||||||
|
if w == None:
|
||||||
|
w = [1] * (len(points) * 2)
|
||||||
|
assert(len(w) == 2*len(points))
|
||||||
|
y = []
|
||||||
|
for n, p in enumerate(refpoints):
|
||||||
|
y += [p[0]/w[n*2], p[1]/w[n*2+1]]
|
||||||
|
A = []
|
||||||
|
for n, p in enumerate(points):
|
||||||
|
A.extend([ [p[0]/w[n*2], p[1]/w[n*2], 0, 0, 1/w[n*2], 0], [0, 0, p[0]/w[n*2+1], p[1]/w[n*2+1], 0, 1/w[n*2+1]] ])
|
||||||
|
|
||||||
|
lstsq = linalg.lstsq(A,y)
|
||||||
|
h11, h12, h21, h22, dx, dy = lstsq[0]
|
||||||
|
err = lstsq[1]
|
||||||
|
|
||||||
|
R = np.array([[h11, h12, dx], [h21, h22, dy]])
|
||||||
|
return R, err
|
||||||
|
|
||||||
|
|
||||||
|
def _compute_affine_transform_ocvlsq(refpoints, points, w = None):
|
||||||
|
if w == None:
|
||||||
|
w = [1] * (len(points) * 2)
|
||||||
|
assert(len(w) == 2*len(points))
|
||||||
|
y = []
|
||||||
|
for n, p in enumerate(refpoints):
|
||||||
|
y += [p[0]/w[n*2], p[1]/w[n*2+1]]
|
||||||
|
A = []
|
||||||
|
for n, p in enumerate(points):
|
||||||
|
A.extend([ [p[0]/w[n*2], p[1]/w[n*2], 0, 0, 1/w[n*2], 0], [0, 0, p[0]/w[n*2+1], p[1]/w[n*2+1], 0, 1/w[n*2+1]] ])
|
||||||
|
|
||||||
|
lstsq = cv2.solve(np.array(A), np.array(y), flags=cv2.DECOMP_SVD)
|
||||||
|
h11, h12, h21, h22, dx, dy = lstsq[1]
|
||||||
|
err = 0#lstsq[1]
|
||||||
|
|
||||||
|
#R = np.array([[h11, h12, dx], [h21, h22, dy]])
|
||||||
|
# The row above works too - but creates a redundant dimension
|
||||||
|
R = np.array([[h11[0], h12[0], dx[0]], [h21[0], h22[0], dy[0]]])
|
||||||
|
return R, err
|
||||||
|
|
||||||
|
def fidu_transform(fidu_model, fidu_points, weights, img, shift=(0.0,0.0), use_ocvlsq=False):
|
||||||
|
FIDU_SIZE = 544
|
||||||
|
|
||||||
|
SHIFT_Y = int(FIDU_SIZE * shift[0])
|
||||||
|
SHIFT_X = int(FIDU_SIZE * shift[1])
|
||||||
|
if not use_ocvlsq:
|
||||||
|
R, err = _compute_affine_transform_cvpy(fidu_model, fidu_points, weights)
|
||||||
|
else:
|
||||||
|
R, err = _compute_affine_transform_ocvlsq(fidu_model, fidu_points, weights)
|
||||||
|
|
||||||
|
funneled_img = cv2.warpAffine(img, R, (FIDU_SIZE + SHIFT_Y*2, FIDU_SIZE + SHIFT_X*2), flags=cv2.INTER_CUBIC)
|
||||||
|
return funneled_img, R
|
||||||
|
|
||||||
|
|
||||||
|
def shift_vector(points, shift):
|
||||||
|
FIDU_SIZE = 544
|
||||||
|
|
||||||
|
SHIFT_Y = int(FIDU_SIZE * shift[0])
|
||||||
|
SHIFT_X = int(FIDU_SIZE * shift[1])
|
||||||
|
SHIFT = (SHIFT_X, SHIFT_Y)
|
||||||
|
s_points = [(p[0] + SHIFT[0], p[1] + SHIFT[1]) for p in points]
|
||||||
|
return s_points
|
||||||
|
|
||||||
|
def unwarp_fidu(orig_fidu_points, unwarp_mat):
|
||||||
|
points = np.array(orig_fidu_points).T
|
||||||
|
points_h = np.r_[points, np.ones((1,points.shape[1]))]
|
||||||
|
orig_fidu_points_in_aligned = np.dot(unwarp_mat,points_h).T.astype(np.int16)
|
||||||
|
return orig_fidu_points_in_aligned
|
|
@ -0,0 +1,113 @@
|
||||||
|
'''
|
||||||
|
Created on May 7, 2014
|
||||||
|
|
||||||
|
@author: eran
|
||||||
|
'''
|
||||||
|
|
||||||
|
import csv
|
||||||
|
import cv2
|
||||||
|
from numpy import linalg
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
|
WEIGHTS3 = [11.1088851746,15.8721645013,12.3189439894,15.9467104922,13.9265119716,17.2447706133,11.4118267639,17.0728365324,12.7831886739,17.1908773151,9.6639887492,13.8443342456,8.76890470223,11.4441704453,7.52083144762,10.3245662427,6.35563072919,7.55739887985,6.42340544936,7.48786881875,10.8720924456,8.1349958353,12.3664410374,9.58137800608,6.29390307208,9.47697088783,8.49859202931,9.43946799727,7.92920023102,10.6126442536,10.2953809171,11.299323189,11.1181958685,12.9374719654,12.3764338392,14.7823225327,13.086272904,16.0571795811,15.079169884,17.5936174739,8.39112414861,7.68532826996,8.89386612449,8.70173923211,10.0826620269,8.70286074207,8.13121344224,9.80805203263,7.76044090777,9.2502084627,7.61334683331,10.4813589698,8.64831020289,11.0452512508,9.19528177019,13.0171747152,10.1204323102,14.0189765809,11.0232436734,14.7355286373,12.4881579947,15.4279914333,11.5785971474,16.7942051778,12.4916161829,17.57726411,14.3422306002,19.3015061859,16.3109851665,23.7227227093,17.7687071538,22.6848438204,14.9879312002,18.6763354368,12.927920123,17.7652660198,10.3584444834,15.5584775245,10.660322225,15.4351684107,11.6468441007,13.7962556973,12.9019472625,16.6407866045,13.1946878458,16.4137518526,9.86525395127,11.6687513083,10.4858060411,12.8407630953,9.24210197996,10.9728479778,9.37639005327,12.3418022852,12.2786533953,12.0629300205,14.8495857728,15.4667996708,14.7414922143,15.2761005039,8.5837102275,10.8010609515,6.55275411638,14.4240347981,10.4200283162,17.6888997346,11.4480670185,22.4669420211,13.1705102756,29.3073334802,16.9922725597,35.4031969543,18.7102372238,41.7466671473,21.7036998929,47.1495172267,24.4179633642,51.9023425203,26.6870471848,57.5921966087,7.71654443362,18.3796425232,9.84932443383,23.3915673615,15.7135746598,31.5768046636,18.159161567,39.0502675506,20.5154926286,44.6961338521,22.8541610324,50.9071591504,26.5569627651,54.4338495899,29.1062390164,61.5990210977]
|
||||||
|
|
||||||
|
def read_fidu(fidu_name):
|
||||||
|
fidu_reader = csv.reader(open(fidu_name))
|
||||||
|
try:
|
||||||
|
line = fidu_reader.next()
|
||||||
|
score, yaw_angle = line
|
||||||
|
fidu_reader.next()
|
||||||
|
fidu_points = [[int(float(field)) for field in row[-2:]] for row in fidu_reader]
|
||||||
|
return int(score), int(yaw_angle), fidu_points
|
||||||
|
except:
|
||||||
|
if line[0] == 'nothing found':
|
||||||
|
return -1000, None, None
|
||||||
|
else:
|
||||||
|
raise Exception('Corrupt Fidu File ' + fidu_name)
|
||||||
|
|
||||||
|
|
||||||
|
def draw_fidu(img, fidu_points, radius = 3, color = (255,0,0), thickness = 1, draw_numbers_color = None):
|
||||||
|
'''
|
||||||
|
set draw_numbers_color = (COLOR_BLUE), for example, to draw the point numbers
|
||||||
|
'''
|
||||||
|
for n,point in enumerate(fidu_points):
|
||||||
|
cv2.circle(img, tuple([int(x) for x in point]),radius,color, thickness)
|
||||||
|
if draw_numbers_color:
|
||||||
|
cv2.putText( img,
|
||||||
|
'%d' %n,
|
||||||
|
tuple([int(point[0])-4, int(point[1])-4]),
|
||||||
|
cv2.FONT_HERSHEY_COMPLEX,
|
||||||
|
0.35,
|
||||||
|
draw_numbers_color,
|
||||||
|
thickness = 1 )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def _compute_affine_transform_cvpy(refpoints, points, w = None): # Copied from the book
|
||||||
|
if w == None:
|
||||||
|
w = [1] * (len(points) * 2)
|
||||||
|
assert(len(w) == 2*len(points))
|
||||||
|
y = []
|
||||||
|
for n, p in enumerate(refpoints):
|
||||||
|
y += [p[0]/w[n*2], p[1]/w[n*2+1]]
|
||||||
|
A = []
|
||||||
|
for n, p in enumerate(points):
|
||||||
|
A.extend([ [p[0]/w[n*2], p[1]/w[n*2], 0, 0, 1/w[n*2], 0], [0, 0, p[0]/w[n*2+1], p[1]/w[n*2+1], 0, 1/w[n*2+1]] ])
|
||||||
|
|
||||||
|
lstsq = linalg.lstsq(A,y)
|
||||||
|
h11, h12, h21, h22, dx, dy = lstsq[0]
|
||||||
|
err = lstsq[1]
|
||||||
|
|
||||||
|
R = np.array([[h11, h12, dx], [h21, h22, dy]])
|
||||||
|
return R, err
|
||||||
|
|
||||||
|
|
||||||
|
def _compute_affine_transform_ocvlsq(refpoints, points, w = None):
|
||||||
|
if w == None:
|
||||||
|
w = [1] * (len(points) * 2)
|
||||||
|
assert(len(w) == 2*len(points))
|
||||||
|
y = []
|
||||||
|
for n, p in enumerate(refpoints):
|
||||||
|
y += [p[0]/w[n*2], p[1]/w[n*2+1]]
|
||||||
|
A = []
|
||||||
|
for n, p in enumerate(points):
|
||||||
|
A.extend([ [p[0]/w[n*2], p[1]/w[n*2], 0, 0, 1/w[n*2], 0], [0, 0, p[0]/w[n*2+1], p[1]/w[n*2+1], 0, 1/w[n*2+1]] ])
|
||||||
|
|
||||||
|
lstsq = cv2.solve(np.array(A), np.array(y), flags=cv2.DECOMP_SVD)
|
||||||
|
h11, h12, h21, h22, dx, dy = lstsq[1]
|
||||||
|
err = 0#lstsq[1]
|
||||||
|
|
||||||
|
#R = np.array([[h11, h12, dx], [h21, h22, dy]])
|
||||||
|
# The row above works too - but creates a redundant dimension
|
||||||
|
R = np.array([[h11[0], h12[0], dx[0]], [h21[0], h22[0], dy[0]]])
|
||||||
|
return R, err
|
||||||
|
|
||||||
|
def fidu_transform(fidu_model, fidu_points, weights, img, shift=(0.0,0.0), use_ocvlsq=False):
|
||||||
|
FIDU_SIZE = 544
|
||||||
|
|
||||||
|
SHIFT_Y = int(FIDU_SIZE * shift[0])
|
||||||
|
SHIFT_X = int(FIDU_SIZE * shift[1])
|
||||||
|
if not use_ocvlsq:
|
||||||
|
R, err = _compute_affine_transform_cvpy(fidu_model, fidu_points, weights)
|
||||||
|
else:
|
||||||
|
R, err = _compute_affine_transform_ocvlsq(fidu_model, fidu_points, weights)
|
||||||
|
|
||||||
|
funneled_img = cv2.warpAffine(img, R, (FIDU_SIZE + SHIFT_Y*2, FIDU_SIZE + SHIFT_X*2), flags=cv2.INTER_CUBIC)
|
||||||
|
return funneled_img, R
|
||||||
|
|
||||||
|
|
||||||
|
def shift_vector(points, shift):
|
||||||
|
FIDU_SIZE = 544
|
||||||
|
|
||||||
|
SHIFT_Y = int(FIDU_SIZE * shift[0])
|
||||||
|
SHIFT_X = int(FIDU_SIZE * shift[1])
|
||||||
|
SHIFT = (SHIFT_X, SHIFT_Y)
|
||||||
|
s_points = [(p[0] + SHIFT[0], p[1] + SHIFT[1]) for p in points]
|
||||||
|
return s_points
|
||||||
|
|
||||||
|
def unwarp_fidu(orig_fidu_points, unwarp_mat):
|
||||||
|
points = np.array(orig_fidu_points).T
|
||||||
|
points_h = np.r_[points, np.ones((1,points.shape[1]))]
|
||||||
|
orig_fidu_points_in_aligned = np.dot(unwarp_mat,points_h).T.astype(np.int16)
|
||||||
|
return orig_fidu_points_in_aligned
|
|
@ -0,0 +1,20 @@
|
||||||
|
'''
|
||||||
|
Created on May 7, 2014
|
||||||
|
|
||||||
|
@author: eran
|
||||||
|
'''
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
|
||||||
|
def detect_landmarks(fname, max_size = 400*400, min_size = 50*50, fidu_exec_dir = os.path.abspath('../resources/')):
|
||||||
|
'''
|
||||||
|
optional flags:
|
||||||
|
max_size - If exceeds this pixel size, image is resized to that before landmark detection
|
||||||
|
min_size - If below this pixel size, image is resized to that before landmark detection
|
||||||
|
'''
|
||||||
|
max_size = str(max_size) if max_size is not None else ''
|
||||||
|
min_size = str(min_size) if min_size is not None else ''
|
||||||
|
fidu_cmd = './FiducialFaceDetector.sh Face_small_146filters_-0.65thr.xml %s %s %s' %(fname, min_size, max_size)
|
||||||
|
print(fidu_cmd)
|
||||||
|
x = subprocess.call(fidu_cmd, shell=True, cwd = fidu_exec_dir)
|
||||||
|
return
|
|
@ -0,0 +1,20 @@
|
||||||
|
'''
|
||||||
|
Created on May 7, 2014
|
||||||
|
|
||||||
|
@author: eran
|
||||||
|
'''
|
||||||
|
import subprocess
|
||||||
|
import os
|
||||||
|
|
||||||
|
def detect_landmarks(fname, max_size = 400*400, min_size = 50*50, fidu_exec_dir = os.path.abspath('../resources/')):
|
||||||
|
'''
|
||||||
|
optional flags:
|
||||||
|
max_size - If exceeds this pixel size, image is resized to that before landmark detection
|
||||||
|
min_size - If below this pixel size, image is resized to that before landmark detection
|
||||||
|
'''
|
||||||
|
max_size = str(max_size) if max_size is not None else ''
|
||||||
|
min_size = str(min_size) if min_size is not None else ''
|
||||||
|
fidu_cmd = './FiducialFaceDetector.sh Face_small_146filters_-0.65thr.xml %s %s %s' %(fname, min_size, max_size)
|
||||||
|
print fidu_cmd
|
||||||
|
x = subprocess.call(fidu_cmd, shell=True, cwd = fidu_exec_dir)
|
||||||
|
return
|
|
@ -0,0 +1,148 @@
|
||||||
|
'''
|
||||||
|
Created on May 8, 2014
|
||||||
|
|
||||||
|
@author: eran
|
||||||
|
'''
|
||||||
|
from adiencealign.cascade_detection.cascade_face_finder import CascadeFaceFinder
|
||||||
|
from adiencealign.affine_alignment.affine_aligner import AffineAligner
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
from adiencealign.landmarks_detection.landmarks_detector import detect_landmarks
|
||||||
|
from adiencealign.common.landmarks import read_fidu, unwarp_fidu, draw_fidu
|
||||||
|
import cv2
|
||||||
|
|
||||||
|
class CascadeFaceAligner(object):
|
||||||
|
'''
|
||||||
|
classdocs
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, haar_file = '../resources/haarcascade_frontalface_default.xml',
|
||||||
|
lbp_file = '../resources/lbpcascade_frontalface.xml',
|
||||||
|
fidu_model_file = '../resources/model_ang_0.txt',
|
||||||
|
fidu_exec_dir = '../resources/'):
|
||||||
|
'''
|
||||||
|
Constructor
|
||||||
|
'''
|
||||||
|
self.face_finder = CascadeFaceFinder(haar_file = haar_file,
|
||||||
|
lbp_file = lbp_file)
|
||||||
|
|
||||||
|
self.aligner = AffineAligner(fidu_model_file = fidu_model_file)
|
||||||
|
self.fidu_exec_dir = fidu_exec_dir
|
||||||
|
|
||||||
|
self.valid_angles = [-45,-30,-15,0,15,30,45]
|
||||||
|
|
||||||
|
def detect_faces(self, input_folder, output_folder, mark_dones = True):
|
||||||
|
'''
|
||||||
|
mark_dones - if True, will create a hidden file, marking this file as done with a hidden file, starting with '.done.'
|
||||||
|
'''
|
||||||
|
input_files1 = glob.glob(os.path.join(input_folder, '*.jpg'))
|
||||||
|
input_files2 = glob.glob(os.path.join(input_folder, '*.png'))
|
||||||
|
input_files = input_files1 + input_files2
|
||||||
|
N = len(input_files)
|
||||||
|
|
||||||
|
for n_file, input_file in enumerate(input_files):
|
||||||
|
a,b = os.path.split(input_file)
|
||||||
|
done_file = os.path.join(a, '.done.' + b.rsplit('.',1)[0])
|
||||||
|
|
||||||
|
if os.path.exists(done_file):
|
||||||
|
continue
|
||||||
|
|
||||||
|
print("... processing", input_file)
|
||||||
|
|
||||||
|
target_faces_file = os.path.join( output_folder, os.path.split(input_file)[1].rsplit('.',1)[0] + '.faces.txt')
|
||||||
|
|
||||||
|
faces_file = self.face_finder.create_faces_file( input_file, is_overwrite = False, target_file = target_faces_file )
|
||||||
|
sub_images_files = self.face_finder.create_sub_images_from_file( original_image_file = input_file,
|
||||||
|
faces_file = faces_file,
|
||||||
|
target_folder = output_folder,
|
||||||
|
img_type = 'jpg')
|
||||||
|
#touch
|
||||||
|
open(done_file,'w').close()
|
||||||
|
print("Detected on %d / %d files" %(n_file, N))
|
||||||
|
|
||||||
|
def align_faces(self, input_images, output_path, fidu_max_size = None, fidu_min_size = None, is_align = True, is_draw_fidu = False, delete_no_fidu = False):
|
||||||
|
'''
|
||||||
|
input_images - can be either a folder (all *.jpgs in it) or a list of filenames
|
||||||
|
|
||||||
|
, fidu_max_size = None, fidu_min_size = None):
|
||||||
|
'''
|
||||||
|
if type(input_images) == type(''):
|
||||||
|
input_images = glob.glob(os.path.join(input_images, '*.jpg'))
|
||||||
|
|
||||||
|
for input_image in input_images:
|
||||||
|
detect_landmarks(fname = os.path.abspath(input_image),
|
||||||
|
max_size = fidu_max_size,
|
||||||
|
min_size = fidu_min_size,
|
||||||
|
fidu_exec_dir = self.fidu_exec_dir)
|
||||||
|
|
||||||
|
fidu_file = input_image.rsplit('.',1)[0] + '.cfidu'
|
||||||
|
fidu_score, yaw_angle, fidu_points = read_fidu(fidu_file)
|
||||||
|
|
||||||
|
if not (fidu_score is not None and yaw_angle in self.valid_angles):
|
||||||
|
# skip face
|
||||||
|
if delete_no_fidu:
|
||||||
|
os.remove(fidu_file)
|
||||||
|
os.remove(input_image)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if is_align:
|
||||||
|
# save the aligned image
|
||||||
|
sub_img = cv2.imread(input_image)
|
||||||
|
_, base_fname = os.path.split(input_image)
|
||||||
|
aligned_img, R = self.aligner.align(sub_img, fidu_points)
|
||||||
|
aligned_img_file = os.path.join(output_path, base_fname.rsplit('.',1)[0] + '.aligned.png')
|
||||||
|
cv2.imwrite(aligned_img_file, aligned_img)
|
||||||
|
|
||||||
|
# save a copy of the aligned image, with the landmarks drawn
|
||||||
|
if is_draw_fidu:
|
||||||
|
aligned_img_file = os.path.join(output_path, base_fname.rsplit('.',1)[0] + '.aligned.withpoints.png')
|
||||||
|
fidu_points_in_aligned = unwarp_fidu(orig_fidu_points = fidu_points, unwarp_mat = R)
|
||||||
|
draw_fidu(aligned_img, fidu_points_in_aligned, radius = 9, color = (255,0,0), thickness = 3)
|
||||||
|
cv2.imwrite(aligned_img_file, aligned_img)
|
||||||
|
|
||||||
|
#
|
||||||
|
# def align_faces2(self, input_folder, output_folder, detect_landmarks = True, delete_no_fidu = True, is_align = True, is_draw_fidu = False, fidu_max_size = None, fidu_min_size = None):
|
||||||
|
# '''
|
||||||
|
# delete_no_fidu - deletes the .cfidu and sub_img if no fidu was found
|
||||||
|
# is_draw_fidu - creates a copy of the aligned images with the original fiducial points on it
|
||||||
|
# '''
|
||||||
|
# input_files = glob.glob(os.path.join(input_folder, '*'))
|
||||||
|
# for input_file in input_files:
|
||||||
|
# print "... processing", input_file
|
||||||
|
# target_faces_file = os.path.join( output_folder, os.path.split(input_file)[1].rsplit('.',1)[0] + '.faces.txt')
|
||||||
|
#
|
||||||
|
# faces_file = self.face_finder.create_faces_file( input_file, is_overwrite = False, target_file = target_faces_file )
|
||||||
|
# sub_images_files = self.face_finder.create_sub_images_from_file( original_image_file = input_file,
|
||||||
|
# faces_file = faces_file,
|
||||||
|
# target_folder = output_folder,
|
||||||
|
# img_type = 'jpg')
|
||||||
|
#
|
||||||
|
# for sub_image_file in sub_images_files:
|
||||||
|
# detect_landmarks(fname = os.path.abspath(sub_image_file),
|
||||||
|
# max_size = fidu_max_size,
|
||||||
|
# min_size = fidu_min_size,
|
||||||
|
# fidu_exec_dir = self.fidu_exec_dir)
|
||||||
|
#
|
||||||
|
# fidu_file = sub_image_file.rsplit('.',1)[0] + '.cfidu'
|
||||||
|
# fidu_score, yaw_angle, fidu_points = read_fidu(fidu_file)
|
||||||
|
#
|
||||||
|
# if not (fidu_score is not None and yaw_angle in self.valid_angles):
|
||||||
|
# # skip face
|
||||||
|
# os.remove(fidu_file)
|
||||||
|
# os.remove(sub_image_file)
|
||||||
|
# continue
|
||||||
|
#
|
||||||
|
# if is_align:
|
||||||
|
# # save the aligned image
|
||||||
|
# sub_img = cv2.imread(sub_image_file)
|
||||||
|
# aligned_img, R = self.aligner.align(sub_img, fidu_points)
|
||||||
|
# aligned_img_file = sub_image_file.rsplit('.',1)[0] + '.aligned.png'
|
||||||
|
# cv2.imwrite(aligned_img_file, aligned_img)
|
||||||
|
#
|
||||||
|
# # save a copy of the aligned image, with the landmarks drawn
|
||||||
|
# if is_draw_fidu:
|
||||||
|
# aligned_img_file = sub_image_file.rsplit('.',1)[0] + '.aligned.withpoints.png'
|
||||||
|
# fidu_points_in_aligned = unwarp_fidu(orig_fidu_points = fidu_points, unwarp_mat = R)
|
||||||
|
# draw_fidu(aligned_img, fidu_points_in_aligned, radius = 9, color = (255,0,0), thickness = 3)
|
||||||
|
# cv2.imwrite(aligned_img_file, aligned_img)
|
|
@ -0,0 +1,148 @@
|
||||||
|
'''
|
||||||
|
Created on May 8, 2014
|
||||||
|
|
||||||
|
@author: eran
|
||||||
|
'''
|
||||||
|
from adiencealign.cascade_detection.cascade_face_finder import CascadeFaceFinder
|
||||||
|
from adiencealign.affine_alignment.affine_aligner import AffineAligner
|
||||||
|
import glob
|
||||||
|
import os
|
||||||
|
from adiencealign.landmarks_detection.landmarks_detector import detect_landmarks
|
||||||
|
from adiencealign.common.landmarks import read_fidu, unwarp_fidu, draw_fidu
|
||||||
|
import cv2
|
||||||
|
|
||||||
|
class CascadeFaceAligner(object):
|
||||||
|
'''
|
||||||
|
classdocs
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, haar_file = '../resources/haarcascade_frontalface_default.xml',
|
||||||
|
lbp_file = '../resources/lbpcascade_frontalface.xml',
|
||||||
|
fidu_model_file = '../resources/model_ang_0.txt',
|
||||||
|
fidu_exec_dir = '../resources/'):
|
||||||
|
'''
|
||||||
|
Constructor
|
||||||
|
'''
|
||||||
|
self.face_finder = CascadeFaceFinder(haar_file = haar_file,
|
||||||
|
lbp_file = lbp_file)
|
||||||
|
|
||||||
|
self.aligner = AffineAligner(fidu_model_file = fidu_model_file)
|
||||||
|
self.fidu_exec_dir = fidu_exec_dir
|
||||||
|
|
||||||
|
self.valid_angles = [-45,-30,-15,0,15,30,45]
|
||||||
|
|
||||||
|
def detect_faces(self, input_folder, output_folder, mark_dones = True):
|
||||||
|
'''
|
||||||
|
mark_dones - if True, will create a hidden file, marking this file as done with a hidden file, starting with '.done.'
|
||||||
|
'''
|
||||||
|
input_files1 = glob.glob(os.path.join(input_folder, '*.jpg'))
|
||||||
|
input_files2 = glob.glob(os.path.join(input_folder, '*.png'))
|
||||||
|
input_files = input_files1 + input_files2
|
||||||
|
N = len(input_files)
|
||||||
|
|
||||||
|
for n_file, input_file in enumerate(input_files):
|
||||||
|
a,b = os.path.split(input_file)
|
||||||
|
done_file = os.path.join(a, '.done.' + b.rsplit('.',1)[0])
|
||||||
|
|
||||||
|
if os.path.exists(done_file):
|
||||||
|
continue
|
||||||
|
|
||||||
|
print "... processing", input_file
|
||||||
|
|
||||||
|
target_faces_file = os.path.join( output_folder, os.path.split(input_file)[1].rsplit('.',1)[0] + '.faces.txt')
|
||||||
|
|
||||||
|
faces_file = self.face_finder.create_faces_file( input_file, is_overwrite = False, target_file = target_faces_file )
|
||||||
|
sub_images_files = self.face_finder.create_sub_images_from_file( original_image_file = input_file,
|
||||||
|
faces_file = faces_file,
|
||||||
|
target_folder = output_folder,
|
||||||
|
img_type = 'jpg')
|
||||||
|
#touch
|
||||||
|
open(done_file,'w').close()
|
||||||
|
print "Detected on %d / %d files" %(n_file, N)
|
||||||
|
|
||||||
|
def align_faces(self, input_images, output_path, fidu_max_size = None, fidu_min_size = None, is_align = True, is_draw_fidu = False, delete_no_fidu = False):
|
||||||
|
'''
|
||||||
|
input_images - can be either a folder (all *.jpgs in it) or a list of filenames
|
||||||
|
|
||||||
|
, fidu_max_size = None, fidu_min_size = None):
|
||||||
|
'''
|
||||||
|
if type(input_images) == type(''):
|
||||||
|
input_images = glob.glob(os.path.join(input_images, '*.jpg'))
|
||||||
|
|
||||||
|
for input_image in input_images:
|
||||||
|
detect_landmarks(fname = os.path.abspath(input_image),
|
||||||
|
max_size = fidu_max_size,
|
||||||
|
min_size = fidu_min_size,
|
||||||
|
fidu_exec_dir = self.fidu_exec_dir)
|
||||||
|
|
||||||
|
fidu_file = input_image.rsplit('.',1)[0] + '.cfidu'
|
||||||
|
fidu_score, yaw_angle, fidu_points = read_fidu(fidu_file)
|
||||||
|
|
||||||
|
if not (fidu_score is not None and yaw_angle in self.valid_angles):
|
||||||
|
# skip face
|
||||||
|
if delete_no_fidu:
|
||||||
|
os.remove(fidu_file)
|
||||||
|
os.remove(input_image)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if is_align:
|
||||||
|
# save the aligned image
|
||||||
|
sub_img = cv2.imread(input_image)
|
||||||
|
_, base_fname = os.path.split(input_image)
|
||||||
|
aligned_img, R = self.aligner.align(sub_img, fidu_points)
|
||||||
|
aligned_img_file = os.path.join(output_path, base_fname.rsplit('.',1)[0] + '.aligned.png')
|
||||||
|
cv2.imwrite(aligned_img_file, aligned_img)
|
||||||
|
|
||||||
|
# save a copy of the aligned image, with the landmarks drawn
|
||||||
|
if is_draw_fidu:
|
||||||
|
aligned_img_file = os.path.join(output_path, base_fname.rsplit('.',1)[0] + '.aligned.withpoints.png')
|
||||||
|
fidu_points_in_aligned = unwarp_fidu(orig_fidu_points = fidu_points, unwarp_mat = R)
|
||||||
|
draw_fidu(aligned_img, fidu_points_in_aligned, radius = 9, color = (255,0,0), thickness = 3)
|
||||||
|
cv2.imwrite(aligned_img_file, aligned_img)
|
||||||
|
|
||||||
|
#
|
||||||
|
# def align_faces2(self, input_folder, output_folder, detect_landmarks = True, delete_no_fidu = True, is_align = True, is_draw_fidu = False, fidu_max_size = None, fidu_min_size = None):
|
||||||
|
# '''
|
||||||
|
# delete_no_fidu - deletes the .cfidu and sub_img if no fidu was found
|
||||||
|
# is_draw_fidu - creates a copy of the aligned images with the original fiducial points on it
|
||||||
|
# '''
|
||||||
|
# input_files = glob.glob(os.path.join(input_folder, '*'))
|
||||||
|
# for input_file in input_files:
|
||||||
|
# print "... processing", input_file
|
||||||
|
# target_faces_file = os.path.join( output_folder, os.path.split(input_file)[1].rsplit('.',1)[0] + '.faces.txt')
|
||||||
|
#
|
||||||
|
# faces_file = self.face_finder.create_faces_file( input_file, is_overwrite = False, target_file = target_faces_file )
|
||||||
|
# sub_images_files = self.face_finder.create_sub_images_from_file( original_image_file = input_file,
|
||||||
|
# faces_file = faces_file,
|
||||||
|
# target_folder = output_folder,
|
||||||
|
# img_type = 'jpg')
|
||||||
|
#
|
||||||
|
# for sub_image_file in sub_images_files:
|
||||||
|
# detect_landmarks(fname = os.path.abspath(sub_image_file),
|
||||||
|
# max_size = fidu_max_size,
|
||||||
|
# min_size = fidu_min_size,
|
||||||
|
# fidu_exec_dir = self.fidu_exec_dir)
|
||||||
|
#
|
||||||
|
# fidu_file = sub_image_file.rsplit('.',1)[0] + '.cfidu'
|
||||||
|
# fidu_score, yaw_angle, fidu_points = read_fidu(fidu_file)
|
||||||
|
#
|
||||||
|
# if not (fidu_score is not None and yaw_angle in self.valid_angles):
|
||||||
|
# # skip face
|
||||||
|
# os.remove(fidu_file)
|
||||||
|
# os.remove(sub_image_file)
|
||||||
|
# continue
|
||||||
|
#
|
||||||
|
# if is_align:
|
||||||
|
# # save the aligned image
|
||||||
|
# sub_img = cv2.imread(sub_image_file)
|
||||||
|
# aligned_img, R = self.aligner.align(sub_img, fidu_points)
|
||||||
|
# aligned_img_file = sub_image_file.rsplit('.',1)[0] + '.aligned.png'
|
||||||
|
# cv2.imwrite(aligned_img_file, aligned_img)
|
||||||
|
#
|
||||||
|
# # save a copy of the aligned image, with the landmarks drawn
|
||||||
|
# if is_draw_fidu:
|
||||||
|
# aligned_img_file = sub_image_file.rsplit('.',1)[0] + '.aligned.withpoints.png'
|
||||||
|
# fidu_points_in_aligned = unwarp_fidu(orig_fidu_points = fidu_points, unwarp_mat = R)
|
||||||
|
# draw_fidu(aligned_img, fidu_points_in_aligned, radius = 9, color = (255,0,0), thickness = 3)
|
||||||
|
# cv2.imwrite(aligned_img_file, aligned_img)
|
65460
adience_align-master/adiencealign(old)/resources/Face_small_146filters_-0.65thr.xml
Executable file
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/sh
|
||||||
|
export LD_LIBRARY_PATH=/usr/local/lib:.
|
||||||
|
"./FiducialFaceDetector" $1 $2 $3 $4
|
|
@ -0,0 +1,68 @@
|
||||||
|
1,272,272
|
||||||
|
2,252,272
|
||||||
|
3,232,272
|
||||||
|
4,292,272
|
||||||
|
5,312,272
|
||||||
|
6,272,232
|
||||||
|
7,272,192
|
||||||
|
8,272,152
|
||||||
|
9,272,112
|
||||||
|
10,212,112
|
||||||
|
11,192,112
|
||||||
|
12,172,112
|
||||||
|
13,192,92
|
||||||
|
14,172,92
|
||||||
|
15,152,112
|
||||||
|
16,112,72
|
||||||
|
17,132,52
|
||||||
|
18,172,52
|
||||||
|
19,212,52
|
||||||
|
20,252,52
|
||||||
|
21,332,112
|
||||||
|
22,352,112
|
||||||
|
23,372,112
|
||||||
|
24,352,92
|
||||||
|
25,372,92
|
||||||
|
26,392,112
|
||||||
|
27,432,72
|
||||||
|
28,412,52
|
||||||
|
29,372,52
|
||||||
|
30,332,52
|
||||||
|
31,292,52
|
||||||
|
32,272,312
|
||||||
|
33,252,312
|
||||||
|
34,232,332
|
||||||
|
35,212,352
|
||||||
|
36,232,352
|
||||||
|
37,252,332
|
||||||
|
38,272,332
|
||||||
|
39,312,312
|
||||||
|
40,332,332
|
||||||
|
41,352,352
|
||||||
|
42,332,352
|
||||||
|
43,312,332
|
||||||
|
44,332,372
|
||||||
|
45,312,352
|
||||||
|
46,312,372
|
||||||
|
47,272,352
|
||||||
|
48,252,372
|
||||||
|
49,252,352
|
||||||
|
50,232,372
|
||||||
|
51,272,372
|
||||||
|
52,272,492
|
||||||
|
53,212,492
|
||||||
|
54,172,472
|
||||||
|
55,132,432
|
||||||
|
56,92,392
|
||||||
|
57,72,332
|
||||||
|
58,52,272
|
||||||
|
59,52,212
|
||||||
|
60,52,152
|
||||||
|
61,332,472
|
||||||
|
62,372,452
|
||||||
|
63,412,412
|
||||||
|
64,452,372
|
||||||
|
65,472,312
|
||||||
|
66,472,252
|
||||||
|
67,472,192
|
||||||
|
68,472,132
|
After Width: | Height: | Size: 696 KiB |
|
@ -0,0 +1,6 @@
|
||||||
|
rm outputs/pipeline/faces/*
|
||||||
|
rm outputs/pipeline/aligned/*
|
||||||
|
rm outputs/cascade/1/*
|
||||||
|
rm outputs/cascade/2/*
|
||||||
|
|
||||||
|
rm resources/pipeline/.done*
|
|
@ -0,0 +1,4 @@
|
||||||
|
rm outputs/pipeline/faces/*
|
||||||
|
rm outputs/pipeline/aligned/*
|
||||||
|
rm outputs/cascade/1/*
|
||||||
|
rm outputs/cascade/2/*
|
After Width: | Height: | Size: 61 KiB |
After Width: | Height: | Size: 65 KiB |
After Width: | Height: | Size: 57 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 44 KiB |
|
@ -0,0 +1,2 @@
|
||||||
|
x,y,dx,dy,score,angle,type
|
||||||
|
61,62,132,132,344,0.0,haar
|
After Width: | Height: | Size: 61 KiB |
|
@ -0,0 +1,5 @@
|
||||||
|
x,y,dx,dy,score,angle,type
|
||||||
|
327,101,121,121,154,0.0,lbp
|
||||||
|
237,106,113,113,139,0.0,lbp
|
||||||
|
164,49,91,91,49,0.0,lbp
|
||||||
|
434,86,94,94,95,0.0,lbp
|
After Width: | Height: | Size: 68 KiB |
After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 42 KiB |
After Width: | Height: | Size: 43 KiB |
After Width: | Height: | Size: 436 KiB |
After Width: | Height: | Size: 449 KiB |
After Width: | Height: | Size: 696 KiB |
After Width: | Height: | Size: 703 KiB |
After Width: | Height: | Size: 645 KiB |
After Width: | Height: | Size: 649 KiB |
After Width: | Height: | Size: 586 KiB |
After Width: | Height: | Size: 586 KiB |
After Width: | Height: | Size: 720 KiB |
After Width: | Height: | Size: 722 KiB |
After Width: | Height: | Size: 742 KiB |
After Width: | Height: | Size: 741 KiB |
After Width: | Height: | Size: 750 KiB |
After Width: | Height: | Size: 750 KiB |
After Width: | Height: | Size: 783 KiB |
After Width: | Height: | Size: 781 KiB |
After Width: | Height: | Size: 696 KiB |
After Width: | Height: | Size: 696 KiB |
|
@ -0,0 +1,2 @@
|
||||||
|
x,y,dx,dy,score,angle,type
|
||||||
|
61,62,132,132,344,0.0,haar
|
|
@ -0,0 +1,70 @@
|
||||||
|
233,0
|
||||||
|
x,y,dx,dy,x_c,y_c
|
||||||
|
87.00,106.00,22.00,22.00,98.00,117.00
|
||||||
|
83.00,106.00,22.00,22.00,94.00,117.00
|
||||||
|
78.00,106.00,22.00,22.00,89.00,117.00
|
||||||
|
92.00,106.00,22.00,22.00,103.00,117.00
|
||||||
|
96.00,106.00,22.00,22.00,107.00,117.00
|
||||||
|
87.00,96.00,22.00,22.00,98.00,107.00
|
||||||
|
87.00,87.00,22.00,22.00,98.00,98.00
|
||||||
|
87.00,78.00,22.00,22.00,98.00,89.00
|
||||||
|
87.00,74.00,22.00,22.00,98.00,85.00
|
||||||
|
74.00,74.00,22.00,22.00,85.00,85.00
|
||||||
|
69.00,74.00,22.00,22.00,80.00,85.00
|
||||||
|
64.00,74.00,22.00,22.00,75.00,85.00
|
||||||
|
69.00,69.00,22.00,22.00,80.00,80.00
|
||||||
|
64.00,69.00,22.00,22.00,75.00,80.00
|
||||||
|
60.00,74.00,22.00,22.00,71.00,85.00
|
||||||
|
51.00,64.00,22.00,22.00,62.00,75.00
|
||||||
|
55.00,55.00,22.00,22.00,66.00,66.00
|
||||||
|
60.00,51.00,22.00,22.00,71.00,62.00
|
||||||
|
69.00,55.00,22.00,22.00,80.00,66.00
|
||||||
|
74.00,60.00,22.00,22.00,85.00,71.00
|
||||||
|
96.00,74.00,22.00,22.00,107.00,85.00
|
||||||
|
101.00,74.00,22.00,22.00,112.00,85.00
|
||||||
|
106.00,74.00,22.00,22.00,117.00,85.00
|
||||||
|
101.00,69.00,22.00,22.00,112.00,80.00
|
||||||
|
106.00,69.00,22.00,22.00,117.00,80.00
|
||||||
|
110.00,74.00,22.00,22.00,121.00,85.00
|
||||||
|
119.00,64.00,22.00,22.00,130.00,75.00
|
||||||
|
115.00,60.00,22.00,22.00,126.00,71.00
|
||||||
|
106.00,55.00,22.00,22.00,117.00,66.00
|
||||||
|
101.00,55.00,22.00,22.00,112.00,66.00
|
||||||
|
92.00,55.00,22.00,22.00,103.00,66.00
|
||||||
|
87.00,110.00,22.00,22.00,98.00,121.00
|
||||||
|
78.00,110.00,22.00,22.00,89.00,121.00
|
||||||
|
74.00,115.00,22.00,22.00,85.00,126.00
|
||||||
|
69.00,119.00,22.00,22.00,80.00,130.00
|
||||||
|
69.00,119.00,22.00,22.00,80.00,130.00
|
||||||
|
78.00,115.00,22.00,22.00,89.00,126.00
|
||||||
|
87.00,115.00,22.00,22.00,98.00,126.00
|
||||||
|
96.00,110.00,22.00,22.00,107.00,121.00
|
||||||
|
101.00,115.00,22.00,22.00,112.00,126.00
|
||||||
|
106.00,119.00,22.00,22.00,117.00,130.00
|
||||||
|
101.00,115.00,22.00,22.00,112.00,126.00
|
||||||
|
101.00,115.00,22.00,22.00,112.00,126.00
|
||||||
|
101.00,124.00,22.00,22.00,112.00,135.00
|
||||||
|
96.00,119.00,22.00,22.00,107.00,130.00
|
||||||
|
96.00,129.00,22.00,22.00,107.00,140.00
|
||||||
|
87.00,124.00,22.00,22.00,98.00,135.00
|
||||||
|
78.00,129.00,22.00,22.00,89.00,140.00
|
||||||
|
78.00,119.00,22.00,22.00,89.00,130.00
|
||||||
|
74.00,124.00,22.00,22.00,85.00,135.00
|
||||||
|
87.00,133.00,22.00,22.00,98.00,144.00
|
||||||
|
87.00,156.00,22.00,22.00,98.00,167.00
|
||||||
|
78.00,152.00,22.00,22.00,89.00,163.00
|
||||||
|
69.00,147.00,22.00,22.00,80.00,158.00
|
||||||
|
60.00,138.00,22.00,22.00,71.00,149.00
|
||||||
|
55.00,129.00,22.00,22.00,66.00,140.00
|
||||||
|
51.00,115.00,22.00,22.00,62.00,126.00
|
||||||
|
51.00,106.00,22.00,22.00,62.00,117.00
|
||||||
|
46.00,92.00,22.00,22.00,57.00,103.00
|
||||||
|
46.00,83.00,22.00,22.00,57.00,94.00
|
||||||
|
101.00,152.00,22.00,22.00,112.00,163.00
|
||||||
|
110.00,142.00,22.00,22.00,121.00,153.00
|
||||||
|
119.00,133.00,22.00,22.00,130.00,144.00
|
||||||
|
124.00,119.00,22.00,22.00,135.00,130.00
|
||||||
|
129.00,110.00,22.00,22.00,140.00,121.00
|
||||||
|
133.00,101.00,22.00,22.00,144.00,112.00
|
||||||
|
138.00,87.00,22.00,22.00,149.00,98.00
|
||||||
|
138.00,74.00,22.00,22.00,149.00,85.00
|
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,2 @@
|
||||||
|
x,y,dx,dy,score,angle,type
|
||||||
|
69,69,109,109,306,0.0,haar
|
|
@ -0,0 +1,70 @@
|
||||||
|
130,0
|
||||||
|
x,y,dx,dy,x_c,y_c
|
||||||
|
68.00,92.00,19.00,19.00,77.50,101.50
|
||||||
|
68.00,92.00,19.00,19.00,77.50,101.50
|
||||||
|
68.00,88.00,19.00,19.00,77.50,97.50
|
||||||
|
72.00,92.00,19.00,19.00,81.50,101.50
|
||||||
|
76.00,92.00,19.00,19.00,85.50,101.50
|
||||||
|
68.00,84.00,19.00,19.00,77.50,93.50
|
||||||
|
68.00,76.00,19.00,19.00,77.50,85.50
|
||||||
|
68.00,68.00,19.00,19.00,77.50,77.50
|
||||||
|
72.00,60.00,19.00,19.00,81.50,69.50
|
||||||
|
60.00,60.00,19.00,19.00,69.50,69.50
|
||||||
|
56.00,60.00,19.00,19.00,65.50,69.50
|
||||||
|
52.00,60.00,19.00,19.00,61.50,69.50
|
||||||
|
56.00,56.00,19.00,19.00,65.50,65.50
|
||||||
|
52.00,56.00,19.00,19.00,61.50,65.50
|
||||||
|
48.00,56.00,19.00,19.00,57.50,65.50
|
||||||
|
40.00,48.00,19.00,19.00,49.50,57.50
|
||||||
|
44.00,44.00,19.00,19.00,53.50,53.50
|
||||||
|
48.00,40.00,19.00,19.00,57.50,49.50
|
||||||
|
56.00,44.00,19.00,19.00,65.50,53.50
|
||||||
|
60.00,48.00,19.00,19.00,69.50,57.50
|
||||||
|
84.00,64.00,19.00,19.00,93.50,73.50
|
||||||
|
88.00,64.00,19.00,19.00,97.50,73.50
|
||||||
|
92.00,64.00,19.00,19.00,101.50,73.50
|
||||||
|
88.00,60.00,19.00,19.00,97.50,69.50
|
||||||
|
92.00,60.00,19.00,19.00,101.50,69.50
|
||||||
|
96.00,64.00,19.00,19.00,105.50,73.50
|
||||||
|
104.00,56.00,19.00,19.00,113.50,65.50
|
||||||
|
100.00,52.00,19.00,19.00,109.50,61.50
|
||||||
|
92.00,52.00,19.00,19.00,101.50,61.50
|
||||||
|
84.00,52.00,19.00,19.00,93.50,61.50
|
||||||
|
76.00,52.00,19.00,19.00,85.50,61.50
|
||||||
|
68.00,96.00,19.00,19.00,77.50,105.50
|
||||||
|
64.00,96.00,19.00,19.00,73.50,105.50
|
||||||
|
60.00,96.00,19.00,19.00,69.50,105.50
|
||||||
|
56.00,100.00,19.00,19.00,65.50,109.50
|
||||||
|
56.00,100.00,19.00,19.00,65.50,109.50
|
||||||
|
64.00,100.00,19.00,19.00,73.50,109.50
|
||||||
|
68.00,100.00,19.00,19.00,77.50,109.50
|
||||||
|
76.00,96.00,19.00,19.00,85.50,105.50
|
||||||
|
80.00,100.00,19.00,19.00,89.50,109.50
|
||||||
|
84.00,100.00,19.00,19.00,93.50,109.50
|
||||||
|
80.00,100.00,19.00,19.00,89.50,109.50
|
||||||
|
80.00,100.00,19.00,19.00,89.50,109.50
|
||||||
|
80.00,104.00,19.00,19.00,89.50,113.50
|
||||||
|
76.00,100.00,19.00,19.00,85.50,109.50
|
||||||
|
76.00,108.00,19.00,19.00,85.50,117.50
|
||||||
|
68.00,104.00,19.00,19.00,77.50,113.50
|
||||||
|
60.00,108.00,19.00,19.00,69.50,117.50
|
||||||
|
60.00,100.00,19.00,19.00,69.50,109.50
|
||||||
|
56.00,104.00,19.00,19.00,65.50,113.50
|
||||||
|
68.00,108.00,19.00,19.00,77.50,117.50
|
||||||
|
72.00,128.00,19.00,19.00,81.50,137.50
|
||||||
|
60.00,124.00,19.00,19.00,69.50,133.50
|
||||||
|
52.00,120.00,19.00,19.00,61.50,129.50
|
||||||
|
44.00,112.00,19.00,19.00,53.50,121.50
|
||||||
|
40.00,104.00,19.00,19.00,49.50,113.50
|
||||||
|
36.00,92.00,19.00,19.00,45.50,101.50
|
||||||
|
32.00,80.00,19.00,19.00,41.50,89.50
|
||||||
|
28.00,68.00,19.00,19.00,37.50,77.50
|
||||||
|
28.00,56.00,19.00,19.00,37.50,65.50
|
||||||
|
80.00,124.00,19.00,19.00,89.50,133.50
|
||||||
|
88.00,120.00,19.00,19.00,97.50,129.50
|
||||||
|
96.00,112.00,19.00,19.00,105.50,121.50
|
||||||
|
100.00,96.00,19.00,19.00,109.50,105.50
|
||||||
|
104.00,84.00,19.00,19.00,113.50,93.50
|
||||||
|
108.00,76.00,19.00,19.00,117.50,85.50
|
||||||
|
116.00,64.00,19.00,19.00,125.50,73.50
|
||||||
|
116.00,56.00,19.00,19.00,125.50,65.50
|
After Width: | Height: | Size: 11 KiB |
|
@ -0,0 +1,4 @@
|
||||||
|
x,y,dx,dy,score,angle,type
|
||||||
|
254,40,107,107,345,0.0,haar
|
||||||
|
159,61,87,86,90,22.0,haar
|
||||||
|
20,63,82,82,117,0.0,lbp
|
|
@ -0,0 +1,70 @@
|
||||||
|
157,0
|
||||||
|
x,y,dx,dy,x_c,y_c
|
||||||
|
68.00,88.00,19.00,19.00,77.50,97.50
|
||||||
|
64.00,88.00,19.00,19.00,73.50,97.50
|
||||||
|
64.00,88.00,19.00,19.00,73.50,97.50
|
||||||
|
76.00,84.00,19.00,19.00,85.50,93.50
|
||||||
|
80.00,84.00,19.00,19.00,89.50,93.50
|
||||||
|
68.00,80.00,19.00,19.00,77.50,89.50
|
||||||
|
68.00,76.00,19.00,19.00,77.50,85.50
|
||||||
|
68.00,68.00,19.00,19.00,77.50,77.50
|
||||||
|
68.00,60.00,19.00,19.00,77.50,69.50
|
||||||
|
56.00,60.00,19.00,19.00,65.50,69.50
|
||||||
|
56.00,64.00,19.00,19.00,65.50,73.50
|
||||||
|
52.00,64.00,19.00,19.00,61.50,73.50
|
||||||
|
52.00,60.00,19.00,19.00,61.50,69.50
|
||||||
|
52.00,60.00,19.00,19.00,61.50,69.50
|
||||||
|
48.00,64.00,19.00,19.00,57.50,73.50
|
||||||
|
36.00,56.00,19.00,19.00,45.50,65.50
|
||||||
|
40.00,52.00,19.00,19.00,49.50,61.50
|
||||||
|
48.00,48.00,19.00,19.00,57.50,57.50
|
||||||
|
56.00,48.00,19.00,19.00,65.50,57.50
|
||||||
|
64.00,48.00,19.00,19.00,73.50,57.50
|
||||||
|
80.00,56.00,19.00,19.00,89.50,65.50
|
||||||
|
84.00,56.00,19.00,19.00,93.50,65.50
|
||||||
|
88.00,56.00,19.00,19.00,97.50,65.50
|
||||||
|
84.00,52.00,19.00,19.00,93.50,61.50
|
||||||
|
88.00,52.00,19.00,19.00,97.50,61.50
|
||||||
|
92.00,52.00,19.00,19.00,101.50,61.50
|
||||||
|
104.00,44.00,19.00,19.00,113.50,53.50
|
||||||
|
104.00,40.00,19.00,19.00,113.50,49.50
|
||||||
|
96.00,40.00,19.00,19.00,105.50,49.50
|
||||||
|
88.00,44.00,19.00,19.00,97.50,53.50
|
||||||
|
80.00,48.00,19.00,19.00,89.50,57.50
|
||||||
|
68.00,92.00,19.00,19.00,77.50,101.50
|
||||||
|
64.00,92.00,19.00,19.00,73.50,101.50
|
||||||
|
60.00,96.00,19.00,19.00,69.50,105.50
|
||||||
|
56.00,100.00,19.00,19.00,65.50,109.50
|
||||||
|
60.00,100.00,19.00,19.00,69.50,109.50
|
||||||
|
64.00,96.00,19.00,19.00,73.50,105.50
|
||||||
|
68.00,96.00,19.00,19.00,77.50,105.50
|
||||||
|
76.00,88.00,19.00,19.00,85.50,97.50
|
||||||
|
84.00,92.00,19.00,19.00,93.50,101.50
|
||||||
|
88.00,96.00,19.00,19.00,97.50,105.50
|
||||||
|
88.00,92.00,19.00,19.00,97.50,101.50
|
||||||
|
80.00,92.00,19.00,19.00,89.50,101.50
|
||||||
|
88.00,108.00,19.00,19.00,97.50,117.50
|
||||||
|
84.00,104.00,19.00,19.00,93.50,113.50
|
||||||
|
84.00,112.00,19.00,19.00,93.50,121.50
|
||||||
|
76.00,108.00,19.00,19.00,85.50,117.50
|
||||||
|
68.00,112.00,19.00,19.00,77.50,121.50
|
||||||
|
68.00,104.00,19.00,19.00,77.50,113.50
|
||||||
|
64.00,104.00,19.00,19.00,73.50,113.50
|
||||||
|
76.00,112.00,19.00,19.00,85.50,121.50
|
||||||
|
76.00,128.00,19.00,19.00,85.50,137.50
|
||||||
|
68.00,124.00,19.00,19.00,77.50,133.50
|
||||||
|
60.00,116.00,19.00,19.00,69.50,125.50
|
||||||
|
52.00,108.00,19.00,19.00,61.50,117.50
|
||||||
|
44.00,104.00,19.00,19.00,53.50,113.50
|
||||||
|
40.00,96.00,19.00,19.00,49.50,105.50
|
||||||
|
40.00,88.00,19.00,19.00,49.50,97.50
|
||||||
|
36.00,76.00,19.00,19.00,45.50,85.50
|
||||||
|
36.00,68.00,19.00,19.00,45.50,77.50
|
||||||
|
84.00,124.00,19.00,19.00,93.50,133.50
|
||||||
|
92.00,116.00,19.00,19.00,101.50,125.50
|
||||||
|
100.00,112.00,19.00,19.00,109.50,121.50
|
||||||
|
104.00,100.00,19.00,19.00,113.50,109.50
|
||||||
|
108.00,92.00,19.00,19.00,117.50,101.50
|
||||||
|
112.00,80.00,19.00,19.00,121.50,89.50
|
||||||
|
112.00,68.00,19.00,19.00,121.50,77.50
|
||||||
|
112.00,60.00,19.00,19.00,121.50,69.50
|
After Width: | Height: | Size: 11 KiB |
|
@ -0,0 +1,70 @@
|
||||||
|
67,0
|
||||||
|
x,y,dx,dy,x_c,y_c
|
||||||
|
60.00,76.00,19.00,19.00,69.50,85.50
|
||||||
|
60.00,76.00,19.00,19.00,69.50,85.50
|
||||||
|
56.00,72.00,19.00,19.00,65.50,81.50
|
||||||
|
64.00,72.00,19.00,19.00,73.50,81.50
|
||||||
|
64.00,72.00,19.00,19.00,73.50,81.50
|
||||||
|
60.00,68.00,19.00,19.00,69.50,77.50
|
||||||
|
60.00,64.00,19.00,19.00,69.50,73.50
|
||||||
|
56.00,56.00,19.00,19.00,65.50,65.50
|
||||||
|
56.00,52.00,19.00,19.00,65.50,61.50
|
||||||
|
44.00,52.00,19.00,19.00,53.50,61.50
|
||||||
|
40.00,56.00,19.00,19.00,49.50,65.50
|
||||||
|
36.00,56.00,19.00,19.00,45.50,65.50
|
||||||
|
40.00,52.00,19.00,19.00,49.50,61.50
|
||||||
|
40.00,52.00,19.00,19.00,49.50,61.50
|
||||||
|
36.00,56.00,19.00,19.00,45.50,65.50
|
||||||
|
24.00,48.00,19.00,19.00,33.50,57.50
|
||||||
|
28.00,44.00,19.00,19.00,37.50,53.50
|
||||||
|
32.00,40.00,19.00,19.00,41.50,49.50
|
||||||
|
40.00,44.00,19.00,19.00,49.50,53.50
|
||||||
|
48.00,44.00,19.00,19.00,57.50,53.50
|
||||||
|
64.00,48.00,19.00,19.00,73.50,57.50
|
||||||
|
68.00,48.00,19.00,19.00,77.50,57.50
|
||||||
|
72.00,48.00,19.00,19.00,81.50,57.50
|
||||||
|
68.00,44.00,19.00,19.00,77.50,53.50
|
||||||
|
72.00,44.00,19.00,19.00,81.50,53.50
|
||||||
|
76.00,44.00,19.00,19.00,85.50,53.50
|
||||||
|
84.00,36.00,19.00,19.00,93.50,45.50
|
||||||
|
80.00,32.00,19.00,19.00,89.50,41.50
|
||||||
|
72.00,28.00,19.00,19.00,81.50,37.50
|
||||||
|
68.00,28.00,19.00,19.00,77.50,37.50
|
||||||
|
64.00,32.00,19.00,19.00,73.50,41.50
|
||||||
|
60.00,80.00,19.00,19.00,69.50,89.50
|
||||||
|
56.00,84.00,19.00,19.00,65.50,93.50
|
||||||
|
52.00,88.00,19.00,19.00,61.50,97.50
|
||||||
|
52.00,96.00,19.00,19.00,61.50,105.50
|
||||||
|
52.00,96.00,19.00,19.00,61.50,105.50
|
||||||
|
56.00,84.00,19.00,19.00,65.50,93.50
|
||||||
|
60.00,84.00,19.00,19.00,69.50,93.50
|
||||||
|
68.00,80.00,19.00,19.00,77.50,89.50
|
||||||
|
72.00,80.00,19.00,19.00,81.50,89.50
|
||||||
|
76.00,80.00,19.00,19.00,85.50,89.50
|
||||||
|
72.00,84.00,19.00,19.00,81.50,93.50
|
||||||
|
68.00,84.00,19.00,19.00,77.50,93.50
|
||||||
|
76.00,84.00,19.00,19.00,85.50,93.50
|
||||||
|
72.00,80.00,19.00,19.00,81.50,89.50
|
||||||
|
72.00,84.00,19.00,19.00,81.50,93.50
|
||||||
|
64.00,80.00,19.00,19.00,73.50,89.50
|
||||||
|
56.00,84.00,19.00,19.00,65.50,93.50
|
||||||
|
56.00,76.00,19.00,19.00,65.50,85.50
|
||||||
|
52.00,76.00,19.00,19.00,61.50,85.50
|
||||||
|
64.00,84.00,19.00,19.00,73.50,93.50
|
||||||
|
64.00,100.00,19.00,19.00,73.50,109.50
|
||||||
|
56.00,96.00,19.00,19.00,65.50,105.50
|
||||||
|
48.00,88.00,19.00,19.00,57.50,97.50
|
||||||
|
40.00,76.00,19.00,19.00,49.50,85.50
|
||||||
|
32.00,68.00,19.00,19.00,41.50,77.50
|
||||||
|
28.00,56.00,19.00,19.00,37.50,65.50
|
||||||
|
24.00,44.00,19.00,19.00,33.50,53.50
|
||||||
|
20.00,32.00,19.00,19.00,29.50,41.50
|
||||||
|
20.00,20.00,19.00,19.00,29.50,29.50
|
||||||
|
72.00,96.00,19.00,19.00,81.50,105.50
|
||||||
|
80.00,88.00,19.00,19.00,89.50,97.50
|
||||||
|
84.00,80.00,19.00,19.00,93.50,89.50
|
||||||
|
88.00,68.00,19.00,19.00,97.50,77.50
|
||||||
|
88.00,56.00,19.00,19.00,97.50,65.50
|
||||||
|
92.00,44.00,19.00,19.00,101.50,53.50
|
||||||
|
92.00,32.00,19.00,19.00,101.50,41.50
|
||||||
|
92.00,20.00,19.00,19.00,101.50,29.50
|
After Width: | Height: | Size: 8.1 KiB |
|
@ -0,0 +1,70 @@
|
||||||
|
145,0
|
||||||
|
x,y,dx,dy,x_c,y_c
|
||||||
|
48.00,64.00,19.00,19.00,57.50,73.50
|
||||||
|
48.00,64.00,19.00,19.00,57.50,73.50
|
||||||
|
44.00,64.00,19.00,19.00,53.50,73.50
|
||||||
|
52.00,64.00,19.00,19.00,61.50,73.50
|
||||||
|
56.00,64.00,19.00,19.00,65.50,73.50
|
||||||
|
48.00,60.00,19.00,19.00,57.50,69.50
|
||||||
|
48.00,56.00,19.00,19.00,57.50,65.50
|
||||||
|
48.00,48.00,19.00,19.00,57.50,57.50
|
||||||
|
52.00,44.00,19.00,19.00,61.50,53.50
|
||||||
|
40.00,44.00,19.00,19.00,49.50,53.50
|
||||||
|
36.00,44.00,19.00,19.00,45.50,53.50
|
||||||
|
36.00,44.00,19.00,19.00,45.50,53.50
|
||||||
|
36.00,40.00,19.00,19.00,45.50,49.50
|
||||||
|
36.00,40.00,19.00,19.00,45.50,49.50
|
||||||
|
32.00,44.00,19.00,19.00,41.50,53.50
|
||||||
|
20.00,36.00,19.00,19.00,29.50,45.50
|
||||||
|
24.00,32.00,19.00,19.00,33.50,41.50
|
||||||
|
28.00,28.00,19.00,19.00,37.50,37.50
|
||||||
|
36.00,32.00,19.00,19.00,45.50,41.50
|
||||||
|
40.00,36.00,19.00,19.00,49.50,45.50
|
||||||
|
60.00,44.00,19.00,19.00,69.50,53.50
|
||||||
|
64.00,44.00,19.00,19.00,73.50,53.50
|
||||||
|
64.00,44.00,19.00,19.00,73.50,53.50
|
||||||
|
64.00,40.00,19.00,19.00,73.50,49.50
|
||||||
|
64.00,40.00,19.00,19.00,73.50,49.50
|
||||||
|
68.00,44.00,19.00,19.00,77.50,53.50
|
||||||
|
76.00,36.00,19.00,19.00,85.50,45.50
|
||||||
|
72.00,36.00,19.00,19.00,81.50,45.50
|
||||||
|
68.00,32.00,19.00,19.00,77.50,41.50
|
||||||
|
64.00,32.00,19.00,19.00,73.50,41.50
|
||||||
|
56.00,32.00,19.00,19.00,65.50,41.50
|
||||||
|
48.00,68.00,19.00,19.00,57.50,77.50
|
||||||
|
44.00,64.00,19.00,19.00,53.50,73.50
|
||||||
|
40.00,68.00,19.00,19.00,49.50,77.50
|
||||||
|
36.00,72.00,19.00,19.00,45.50,81.50
|
||||||
|
36.00,72.00,19.00,19.00,45.50,81.50
|
||||||
|
44.00,68.00,19.00,19.00,53.50,77.50
|
||||||
|
48.00,72.00,19.00,19.00,57.50,81.50
|
||||||
|
56.00,64.00,19.00,19.00,65.50,73.50
|
||||||
|
60.00,68.00,19.00,19.00,69.50,77.50
|
||||||
|
64.00,68.00,19.00,19.00,73.50,77.50
|
||||||
|
60.00,72.00,19.00,19.00,69.50,81.50
|
||||||
|
60.00,68.00,19.00,19.00,69.50,77.50
|
||||||
|
60.00,76.00,19.00,19.00,69.50,85.50
|
||||||
|
56.00,72.00,19.00,19.00,65.50,81.50
|
||||||
|
56.00,80.00,19.00,19.00,65.50,89.50
|
||||||
|
48.00,76.00,19.00,19.00,57.50,85.50
|
||||||
|
40.00,76.00,19.00,19.00,49.50,85.50
|
||||||
|
40.00,68.00,19.00,19.00,49.50,77.50
|
||||||
|
36.00,72.00,19.00,19.00,45.50,81.50
|
||||||
|
48.00,80.00,19.00,19.00,57.50,89.50
|
||||||
|
48.00,100.00,19.00,19.00,57.50,109.50
|
||||||
|
40.00,96.00,19.00,19.00,49.50,105.50
|
||||||
|
36.00,92.00,19.00,19.00,45.50,101.50
|
||||||
|
28.00,84.00,19.00,19.00,37.50,93.50
|
||||||
|
24.00,80.00,19.00,19.00,33.50,89.50
|
||||||
|
20.00,72.00,19.00,19.00,29.50,81.50
|
||||||
|
20.00,64.00,19.00,19.00,29.50,73.50
|
||||||
|
16.00,52.00,19.00,19.00,25.50,61.50
|
||||||
|
16.00,44.00,19.00,19.00,25.50,53.50
|
||||||
|
56.00,96.00,19.00,19.00,65.50,105.50
|
||||||
|
64.00,88.00,19.00,19.00,73.50,97.50
|
||||||
|
72.00,84.00,19.00,19.00,81.50,93.50
|
||||||
|
76.00,76.00,19.00,19.00,85.50,85.50
|
||||||
|
76.00,68.00,19.00,19.00,85.50,77.50
|
||||||
|
76.00,60.00,19.00,19.00,85.50,69.50
|
||||||
|
80.00,48.00,19.00,19.00,89.50,57.50
|
||||||
|
80.00,40.00,19.00,19.00,89.50,49.50
|
After Width: | Height: | Size: 8.3 KiB |
|
@ -0,0 +1,5 @@
|
||||||
|
x,y,dx,dy,score,angle,type
|
||||||
|
327,101,121,121,154,0.0,lbp
|
||||||
|
237,106,113,113,139,0.0,lbp
|
||||||
|
164,49,91,91,49,0.0,lbp
|
||||||
|
434,86,94,94,95,0.0,lbp
|
|
@ -0,0 +1,70 @@
|
||||||
|
119,0
|
||||||
|
x,y,dx,dy,x_c,y_c
|
||||||
|
74.00,84.00,25.00,25.00,86.50,96.50
|
||||||
|
69.00,84.00,25.00,25.00,81.50,96.50
|
||||||
|
69.00,79.00,25.00,25.00,81.50,91.50
|
||||||
|
79.00,79.00,25.00,25.00,91.50,91.50
|
||||||
|
84.00,79.00,25.00,25.00,96.50,91.50
|
||||||
|
74.00,79.00,25.00,25.00,86.50,91.50
|
||||||
|
74.00,74.00,25.00,25.00,86.50,86.50
|
||||||
|
74.00,69.00,25.00,25.00,86.50,81.50
|
||||||
|
74.00,63.00,25.00,25.00,86.50,75.50
|
||||||
|
58.00,63.00,25.00,25.00,70.50,75.50
|
||||||
|
58.00,63.00,25.00,25.00,70.50,75.50
|
||||||
|
53.00,69.00,25.00,25.00,65.50,81.50
|
||||||
|
53.00,63.00,25.00,25.00,65.50,75.50
|
||||||
|
53.00,63.00,25.00,25.00,65.50,75.50
|
||||||
|
48.00,69.00,25.00,25.00,60.50,81.50
|
||||||
|
37.00,58.00,25.00,25.00,49.50,70.50
|
||||||
|
42.00,53.00,25.00,25.00,54.50,65.50
|
||||||
|
48.00,48.00,25.00,25.00,60.50,60.50
|
||||||
|
58.00,53.00,25.00,25.00,70.50,65.50
|
||||||
|
63.00,53.00,25.00,25.00,75.50,65.50
|
||||||
|
90.00,63.00,25.00,25.00,102.50,75.50
|
||||||
|
95.00,63.00,25.00,25.00,107.50,75.50
|
||||||
|
100.00,63.00,25.00,25.00,112.50,75.50
|
||||||
|
95.00,63.00,25.00,25.00,107.50,75.50
|
||||||
|
100.00,63.00,25.00,25.00,112.50,75.50
|
||||||
|
106.00,63.00,25.00,25.00,118.50,75.50
|
||||||
|
116.00,53.00,25.00,25.00,128.50,65.50
|
||||||
|
111.00,53.00,25.00,25.00,123.50,65.50
|
||||||
|
100.00,48.00,25.00,25.00,112.50,60.50
|
||||||
|
95.00,48.00,25.00,25.00,107.50,60.50
|
||||||
|
84.00,53.00,25.00,25.00,96.50,65.50
|
||||||
|
74.00,90.00,25.00,25.00,86.50,102.50
|
||||||
|
63.00,90.00,25.00,25.00,75.50,102.50
|
||||||
|
58.00,95.00,25.00,25.00,70.50,107.50
|
||||||
|
53.00,100.00,25.00,25.00,65.50,112.50
|
||||||
|
58.00,106.00,25.00,25.00,70.50,118.50
|
||||||
|
63.00,95.00,25.00,25.00,75.50,107.50
|
||||||
|
74.00,90.00,25.00,25.00,86.50,102.50
|
||||||
|
84.00,90.00,25.00,25.00,96.50,102.50
|
||||||
|
95.00,95.00,25.00,25.00,107.50,107.50
|
||||||
|
100.00,100.00,25.00,25.00,112.50,112.50
|
||||||
|
100.00,100.00,25.00,25.00,112.50,112.50
|
||||||
|
84.00,95.00,25.00,25.00,96.50,107.50
|
||||||
|
95.00,111.00,25.00,25.00,107.50,123.50
|
||||||
|
90.00,106.00,25.00,25.00,102.50,118.50
|
||||||
|
90.00,116.00,25.00,25.00,102.50,128.50
|
||||||
|
79.00,111.00,25.00,25.00,91.50,123.50
|
||||||
|
63.00,116.00,25.00,25.00,75.50,128.50
|
||||||
|
63.00,106.00,25.00,25.00,75.50,118.50
|
||||||
|
58.00,111.00,25.00,25.00,70.50,123.50
|
||||||
|
79.00,116.00,25.00,25.00,91.50,128.50
|
||||||
|
84.00,143.00,25.00,25.00,96.50,155.50
|
||||||
|
69.00,137.00,25.00,25.00,81.50,149.50
|
||||||
|
58.00,127.00,25.00,25.00,70.50,139.50
|
||||||
|
48.00,116.00,25.00,25.00,60.50,128.50
|
||||||
|
42.00,100.00,25.00,25.00,54.50,112.50
|
||||||
|
37.00,84.00,25.00,25.00,49.50,96.50
|
||||||
|
32.00,69.00,25.00,25.00,44.50,81.50
|
||||||
|
26.00,48.00,25.00,25.00,38.50,60.50
|
||||||
|
26.00,32.00,25.00,25.00,38.50,44.50
|
||||||
|
95.00,137.00,25.00,25.00,107.50,149.50
|
||||||
|
106.00,127.00,25.00,25.00,118.50,139.50
|
||||||
|
116.00,121.00,25.00,25.00,128.50,133.50
|
||||||
|
121.00,111.00,25.00,25.00,133.50,123.50
|
||||||
|
127.00,100.00,25.00,25.00,139.50,112.50
|
||||||
|
132.00,90.00,25.00,25.00,144.50,102.50
|
||||||
|
132.00,74.00,25.00,25.00,144.50,86.50
|
||||||
|
132.00,58.00,25.00,25.00,144.50,70.50
|
After Width: | Height: | Size: 18 KiB |
|
@ -0,0 +1,70 @@
|
||||||
|
84,0
|
||||||
|
x,y,dx,dy,x_c,y_c
|
||||||
|
74.00,92.00,22.00,22.00,85.00,103.00
|
||||||
|
69.00,92.00,22.00,22.00,80.00,103.00
|
||||||
|
64.00,92.00,22.00,22.00,75.00,103.00
|
||||||
|
78.00,92.00,22.00,22.00,89.00,103.00
|
||||||
|
83.00,92.00,22.00,22.00,94.00,103.00
|
||||||
|
74.00,83.00,22.00,22.00,85.00,94.00
|
||||||
|
74.00,78.00,22.00,22.00,85.00,89.00
|
||||||
|
74.00,69.00,22.00,22.00,85.00,80.00
|
||||||
|
74.00,60.00,22.00,22.00,85.00,71.00
|
||||||
|
60.00,60.00,22.00,22.00,71.00,71.00
|
||||||
|
60.00,60.00,22.00,22.00,71.00,71.00
|
||||||
|
55.00,60.00,22.00,22.00,66.00,71.00
|
||||||
|
55.00,55.00,22.00,22.00,66.00,66.00
|
||||||
|
51.00,55.00,22.00,22.00,62.00,66.00
|
||||||
|
46.00,55.00,22.00,22.00,57.00,66.00
|
||||||
|
37.00,51.00,22.00,22.00,48.00,62.00
|
||||||
|
41.00,46.00,22.00,22.00,52.00,57.00
|
||||||
|
46.00,41.00,22.00,22.00,57.00,52.00
|
||||||
|
55.00,46.00,22.00,22.00,66.00,57.00
|
||||||
|
64.00,51.00,22.00,22.00,75.00,62.00
|
||||||
|
87.00,64.00,22.00,22.00,98.00,75.00
|
||||||
|
92.00,64.00,22.00,22.00,103.00,75.00
|
||||||
|
96.00,64.00,22.00,22.00,107.00,75.00
|
||||||
|
92.00,64.00,22.00,22.00,103.00,75.00
|
||||||
|
92.00,64.00,22.00,22.00,103.00,75.00
|
||||||
|
96.00,64.00,22.00,22.00,107.00,75.00
|
||||||
|
106.00,55.00,22.00,22.00,117.00,66.00
|
||||||
|
101.00,51.00,22.00,22.00,112.00,62.00
|
||||||
|
92.00,51.00,22.00,22.00,103.00,62.00
|
||||||
|
87.00,51.00,22.00,22.00,98.00,62.00
|
||||||
|
83.00,51.00,22.00,22.00,94.00,62.00
|
||||||
|
74.00,96.00,22.00,22.00,85.00,107.00
|
||||||
|
69.00,96.00,22.00,22.00,80.00,107.00
|
||||||
|
60.00,101.00,22.00,22.00,71.00,112.00
|
||||||
|
55.00,110.00,22.00,22.00,66.00,121.00
|
||||||
|
55.00,110.00,22.00,22.00,66.00,121.00
|
||||||
|
69.00,101.00,22.00,22.00,80.00,112.00
|
||||||
|
74.00,101.00,22.00,22.00,85.00,112.00
|
||||||
|
83.00,92.00,22.00,22.00,94.00,103.00
|
||||||
|
87.00,96.00,22.00,22.00,98.00,107.00
|
||||||
|
87.00,101.00,22.00,22.00,98.00,112.00
|
||||||
|
87.00,101.00,22.00,22.00,98.00,112.00
|
||||||
|
83.00,96.00,22.00,22.00,94.00,107.00
|
||||||
|
83.00,110.00,22.00,22.00,94.00,121.00
|
||||||
|
78.00,106.00,22.00,22.00,89.00,117.00
|
||||||
|
78.00,110.00,22.00,22.00,89.00,121.00
|
||||||
|
64.00,106.00,22.00,22.00,75.00,117.00
|
||||||
|
55.00,110.00,22.00,22.00,66.00,121.00
|
||||||
|
55.00,101.00,22.00,22.00,66.00,112.00
|
||||||
|
51.00,101.00,22.00,22.00,62.00,112.00
|
||||||
|
64.00,110.00,22.00,22.00,75.00,121.00
|
||||||
|
69.00,133.00,22.00,22.00,80.00,144.00
|
||||||
|
55.00,129.00,22.00,22.00,66.00,140.00
|
||||||
|
46.00,119.00,22.00,22.00,57.00,130.00
|
||||||
|
37.00,110.00,22.00,22.00,48.00,121.00
|
||||||
|
28.00,106.00,22.00,22.00,39.00,117.00
|
||||||
|
23.00,96.00,22.00,22.00,34.00,107.00
|
||||||
|
23.00,87.00,22.00,22.00,34.00,98.00
|
||||||
|
18.00,74.00,22.00,22.00,29.00,85.00
|
||||||
|
18.00,60.00,22.00,22.00,29.00,71.00
|
||||||
|
78.00,129.00,22.00,22.00,89.00,140.00
|
||||||
|
87.00,124.00,22.00,22.00,98.00,135.00
|
||||||
|
101.00,115.00,22.00,22.00,112.00,126.00
|
||||||
|
101.00,101.00,22.00,22.00,112.00,112.00
|
||||||
|
106.00,92.00,22.00,22.00,117.00,103.00
|
||||||
|
110.00,83.00,22.00,22.00,121.00,94.00
|
||||||
|
115.00,69.00,22.00,22.00,126.00,80.00
|
||||||
|
115.00,55.00,22.00,22.00,126.00,66.00
|
After Width: | Height: | Size: 16 KiB |
|
@ -0,0 +1,70 @@
|
||||||
|
80,0
|
||||||
|
x,y,dx,dy,x_c,y_c
|
||||||
|
60.00,72.00,19.00,19.00,69.50,81.50
|
||||||
|
56.00,72.00,19.00,19.00,65.50,81.50
|
||||||
|
52.00,72.00,19.00,19.00,61.50,81.50
|
||||||
|
64.00,68.00,19.00,19.00,73.50,77.50
|
||||||
|
68.00,68.00,19.00,19.00,77.50,77.50
|
||||||
|
60.00,64.00,19.00,19.00,69.50,73.50
|
||||||
|
60.00,60.00,19.00,19.00,69.50,69.50
|
||||||
|
60.00,52.00,19.00,19.00,69.50,61.50
|
||||||
|
60.00,48.00,19.00,19.00,69.50,57.50
|
||||||
|
48.00,48.00,19.00,19.00,57.50,57.50
|
||||||
|
44.00,48.00,19.00,19.00,53.50,57.50
|
||||||
|
40.00,48.00,19.00,19.00,49.50,57.50
|
||||||
|
44.00,48.00,19.00,19.00,53.50,57.50
|
||||||
|
44.00,48.00,19.00,19.00,53.50,57.50
|
||||||
|
40.00,48.00,19.00,19.00,49.50,57.50
|
||||||
|
32.00,44.00,19.00,19.00,41.50,53.50
|
||||||
|
36.00,40.00,19.00,19.00,45.50,49.50
|
||||||
|
40.00,40.00,19.00,19.00,49.50,49.50
|
||||||
|
44.00,44.00,19.00,19.00,53.50,53.50
|
||||||
|
48.00,44.00,19.00,19.00,57.50,53.50
|
||||||
|
72.00,48.00,19.00,19.00,81.50,57.50
|
||||||
|
76.00,48.00,19.00,19.00,85.50,57.50
|
||||||
|
76.00,48.00,19.00,19.00,85.50,57.50
|
||||||
|
76.00,44.00,19.00,19.00,85.50,53.50
|
||||||
|
80.00,44.00,19.00,19.00,89.50,53.50
|
||||||
|
84.00,44.00,19.00,19.00,93.50,53.50
|
||||||
|
96.00,40.00,19.00,19.00,105.50,49.50
|
||||||
|
92.00,36.00,19.00,19.00,101.50,45.50
|
||||||
|
84.00,36.00,19.00,19.00,93.50,45.50
|
||||||
|
76.00,36.00,19.00,19.00,85.50,45.50
|
||||||
|
68.00,40.00,19.00,19.00,77.50,49.50
|
||||||
|
60.00,76.00,19.00,19.00,69.50,85.50
|
||||||
|
52.00,72.00,19.00,19.00,61.50,81.50
|
||||||
|
44.00,76.00,19.00,19.00,53.50,85.50
|
||||||
|
40.00,80.00,19.00,19.00,49.50,89.50
|
||||||
|
44.00,80.00,19.00,19.00,53.50,89.50
|
||||||
|
48.00,76.00,19.00,19.00,57.50,85.50
|
||||||
|
60.00,80.00,19.00,19.00,69.50,89.50
|
||||||
|
68.00,72.00,19.00,19.00,77.50,81.50
|
||||||
|
76.00,72.00,19.00,19.00,85.50,81.50
|
||||||
|
80.00,76.00,19.00,19.00,89.50,85.50
|
||||||
|
80.00,76.00,19.00,19.00,89.50,85.50
|
||||||
|
68.00,76.00,19.00,19.00,77.50,85.50
|
||||||
|
76.00,84.00,19.00,19.00,85.50,93.50
|
||||||
|
68.00,80.00,19.00,19.00,77.50,89.50
|
||||||
|
68.00,88.00,19.00,19.00,77.50,97.50
|
||||||
|
60.00,84.00,19.00,19.00,69.50,93.50
|
||||||
|
52.00,88.00,19.00,19.00,61.50,97.50
|
||||||
|
52.00,80.00,19.00,19.00,61.50,89.50
|
||||||
|
48.00,84.00,19.00,19.00,57.50,93.50
|
||||||
|
60.00,88.00,19.00,19.00,69.50,97.50
|
||||||
|
60.00,104.00,19.00,19.00,69.50,113.50
|
||||||
|
52.00,104.00,19.00,19.00,61.50,113.50
|
||||||
|
44.00,96.00,19.00,19.00,53.50,105.50
|
||||||
|
36.00,88.00,19.00,19.00,45.50,97.50
|
||||||
|
28.00,84.00,19.00,19.00,37.50,93.50
|
||||||
|
24.00,76.00,19.00,19.00,33.50,85.50
|
||||||
|
24.00,68.00,19.00,19.00,33.50,77.50
|
||||||
|
20.00,56.00,19.00,19.00,29.50,65.50
|
||||||
|
20.00,48.00,19.00,19.00,29.50,57.50
|
||||||
|
72.00,100.00,19.00,19.00,81.50,109.50
|
||||||
|
80.00,92.00,19.00,19.00,89.50,101.50
|
||||||
|
92.00,84.00,19.00,19.00,101.50,93.50
|
||||||
|
96.00,72.00,19.00,19.00,105.50,81.50
|
||||||
|
100.00,64.00,19.00,19.00,109.50,73.50
|
||||||
|
100.00,56.00,19.00,19.00,109.50,65.50
|
||||||
|
104.00,44.00,19.00,19.00,113.50,53.50
|
||||||
|
104.00,36.00,19.00,19.00,113.50,45.50
|
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,70 @@
|
||||||
|
110,0
|
||||||
|
x,y,dx,dy,x_c,y_c
|
||||||
|
60.00,74.00,22.00,22.00,71.00,85.00
|
||||||
|
55.00,74.00,22.00,22.00,66.00,85.00
|
||||||
|
51.00,74.00,22.00,22.00,62.00,85.00
|
||||||
|
64.00,74.00,22.00,22.00,75.00,85.00
|
||||||
|
69.00,74.00,22.00,22.00,80.00,85.00
|
||||||
|
60.00,64.00,22.00,22.00,71.00,75.00
|
||||||
|
60.00,60.00,22.00,22.00,71.00,71.00
|
||||||
|
60.00,51.00,22.00,22.00,71.00,62.00
|
||||||
|
60.00,46.00,22.00,22.00,71.00,57.00
|
||||||
|
46.00,46.00,22.00,22.00,57.00,57.00
|
||||||
|
41.00,46.00,22.00,22.00,52.00,57.00
|
||||||
|
41.00,46.00,22.00,22.00,52.00,57.00
|
||||||
|
41.00,41.00,22.00,22.00,52.00,52.00
|
||||||
|
41.00,41.00,22.00,22.00,52.00,52.00
|
||||||
|
37.00,46.00,22.00,22.00,48.00,57.00
|
||||||
|
23.00,41.00,22.00,22.00,34.00,52.00
|
||||||
|
28.00,37.00,22.00,22.00,39.00,48.00
|
||||||
|
32.00,32.00,22.00,22.00,43.00,43.00
|
||||||
|
41.00,37.00,22.00,22.00,52.00,48.00
|
||||||
|
51.00,41.00,22.00,22.00,62.00,52.00
|
||||||
|
69.00,46.00,22.00,22.00,80.00,57.00
|
||||||
|
74.00,46.00,22.00,22.00,85.00,57.00
|
||||||
|
78.00,46.00,22.00,22.00,89.00,57.00
|
||||||
|
74.00,46.00,22.00,22.00,85.00,57.00
|
||||||
|
78.00,46.00,22.00,22.00,89.00,57.00
|
||||||
|
83.00,46.00,22.00,22.00,94.00,57.00
|
||||||
|
92.00,37.00,22.00,22.00,103.00,48.00
|
||||||
|
87.00,37.00,22.00,22.00,98.00,48.00
|
||||||
|
78.00,37.00,22.00,22.00,89.00,48.00
|
||||||
|
74.00,37.00,22.00,22.00,85.00,48.00
|
||||||
|
64.00,37.00,22.00,22.00,75.00,48.00
|
||||||
|
60.00,78.00,22.00,22.00,71.00,89.00
|
||||||
|
55.00,74.00,22.00,22.00,66.00,85.00
|
||||||
|
46.00,74.00,22.00,22.00,57.00,85.00
|
||||||
|
41.00,78.00,22.00,22.00,52.00,89.00
|
||||||
|
46.00,78.00,22.00,22.00,57.00,89.00
|
||||||
|
51.00,78.00,22.00,22.00,62.00,89.00
|
||||||
|
60.00,83.00,22.00,22.00,71.00,94.00
|
||||||
|
69.00,74.00,22.00,22.00,80.00,85.00
|
||||||
|
74.00,78.00,22.00,22.00,85.00,89.00
|
||||||
|
78.00,78.00,22.00,22.00,89.00,89.00
|
||||||
|
78.00,78.00,22.00,22.00,89.00,89.00
|
||||||
|
74.00,78.00,22.00,22.00,85.00,89.00
|
||||||
|
74.00,87.00,22.00,22.00,85.00,98.00
|
||||||
|
64.00,83.00,22.00,22.00,75.00,94.00
|
||||||
|
64.00,92.00,22.00,22.00,75.00,103.00
|
||||||
|
55.00,87.00,22.00,22.00,66.00,98.00
|
||||||
|
46.00,92.00,22.00,22.00,57.00,103.00
|
||||||
|
46.00,83.00,22.00,22.00,57.00,94.00
|
||||||
|
41.00,83.00,22.00,22.00,52.00,94.00
|
||||||
|
55.00,92.00,22.00,22.00,66.00,103.00
|
||||||
|
60.00,115.00,22.00,22.00,71.00,126.00
|
||||||
|
51.00,110.00,22.00,22.00,62.00,121.00
|
||||||
|
41.00,101.00,22.00,22.00,52.00,112.00
|
||||||
|
32.00,92.00,22.00,22.00,43.00,103.00
|
||||||
|
28.00,83.00,22.00,22.00,39.00,94.00
|
||||||
|
23.00,74.00,22.00,22.00,34.00,85.00
|
||||||
|
18.00,64.00,22.00,22.00,29.00,75.00
|
||||||
|
14.00,51.00,22.00,22.00,25.00,62.00
|
||||||
|
14.00,37.00,22.00,22.00,25.00,48.00
|
||||||
|
69.00,115.00,22.00,22.00,80.00,126.00
|
||||||
|
78.00,110.00,22.00,22.00,89.00,121.00
|
||||||
|
87.00,101.00,22.00,22.00,98.00,112.00
|
||||||
|
92.00,87.00,22.00,22.00,103.00,98.00
|
||||||
|
96.00,74.00,22.00,22.00,107.00,85.00
|
||||||
|
101.00,64.00,22.00,22.00,112.00,75.00
|
||||||
|
106.00,51.00,22.00,22.00,117.00,62.00
|
||||||
|
106.00,41.00,22.00,22.00,117.00,52.00
|
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,70 @@
|
||||||
|
252,0
|
||||||
|
x,y,dx,dy,x_c,y_c
|
||||||
|
111.00,132.00,25.00,25.00,123.50,144.50
|
||||||
|
111.00,132.00,25.00,25.00,123.50,144.50
|
||||||
|
106.00,132.00,25.00,25.00,118.50,144.50
|
||||||
|
116.00,132.00,25.00,25.00,128.50,144.50
|
||||||
|
121.00,132.00,25.00,25.00,133.50,144.50
|
||||||
|
111.00,121.00,25.00,25.00,123.50,133.50
|
||||||
|
111.00,116.00,25.00,25.00,123.50,128.50
|
||||||
|
111.00,106.00,25.00,25.00,123.50,118.50
|
||||||
|
111.00,100.00,25.00,25.00,123.50,112.50
|
||||||
|
100.00,100.00,25.00,25.00,112.50,112.50
|
||||||
|
95.00,100.00,25.00,25.00,107.50,112.50
|
||||||
|
90.00,100.00,25.00,25.00,102.50,112.50
|
||||||
|
95.00,95.00,25.00,25.00,107.50,107.50
|
||||||
|
90.00,95.00,25.00,25.00,102.50,107.50
|
||||||
|
84.00,100.00,25.00,25.00,96.50,112.50
|
||||||
|
74.00,90.00,25.00,25.00,86.50,102.50
|
||||||
|
79.00,84.00,25.00,25.00,91.50,96.50
|
||||||
|
84.00,79.00,25.00,25.00,96.50,91.50
|
||||||
|
95.00,84.00,25.00,25.00,107.50,96.50
|
||||||
|
106.00,84.00,25.00,25.00,118.50,96.50
|
||||||
|
127.00,100.00,25.00,25.00,139.50,112.50
|
||||||
|
132.00,100.00,25.00,25.00,144.50,112.50
|
||||||
|
132.00,100.00,25.00,25.00,144.50,112.50
|
||||||
|
127.00,95.00,25.00,25.00,139.50,107.50
|
||||||
|
132.00,95.00,25.00,25.00,144.50,107.50
|
||||||
|
137.00,100.00,25.00,25.00,149.50,112.50
|
||||||
|
148.00,90.00,25.00,25.00,160.50,102.50
|
||||||
|
143.00,84.00,25.00,25.00,155.50,96.50
|
||||||
|
132.00,84.00,25.00,25.00,144.50,96.50
|
||||||
|
127.00,84.00,25.00,25.00,139.50,96.50
|
||||||
|
116.00,84.00,25.00,25.00,128.50,96.50
|
||||||
|
111.00,137.00,25.00,25.00,123.50,149.50
|
||||||
|
106.00,137.00,25.00,25.00,118.50,149.50
|
||||||
|
100.00,143.00,25.00,25.00,112.50,155.50
|
||||||
|
95.00,148.00,25.00,25.00,107.50,160.50
|
||||||
|
100.00,148.00,25.00,25.00,112.50,160.50
|
||||||
|
106.00,143.00,25.00,25.00,118.50,155.50
|
||||||
|
111.00,143.00,25.00,25.00,123.50,155.50
|
||||||
|
121.00,137.00,25.00,25.00,133.50,149.50
|
||||||
|
127.00,143.00,25.00,25.00,139.50,155.50
|
||||||
|
132.00,143.00,25.00,25.00,144.50,155.50
|
||||||
|
127.00,143.00,25.00,25.00,139.50,155.50
|
||||||
|
127.00,143.00,25.00,25.00,139.50,155.50
|
||||||
|
127.00,153.00,25.00,25.00,139.50,165.50
|
||||||
|
121.00,148.00,25.00,25.00,133.50,160.50
|
||||||
|
121.00,158.00,25.00,25.00,133.50,170.50
|
||||||
|
111.00,153.00,25.00,25.00,123.50,165.50
|
||||||
|
106.00,158.00,25.00,25.00,118.50,170.50
|
||||||
|
106.00,148.00,25.00,25.00,118.50,160.50
|
||||||
|
100.00,153.00,25.00,25.00,112.50,165.50
|
||||||
|
111.00,158.00,25.00,25.00,123.50,170.50
|
||||||
|
116.00,185.00,25.00,25.00,128.50,197.50
|
||||||
|
106.00,179.00,25.00,25.00,118.50,191.50
|
||||||
|
95.00,174.00,25.00,25.00,107.50,186.50
|
||||||
|
84.00,164.00,25.00,25.00,96.50,176.50
|
||||||
|
79.00,153.00,25.00,25.00,91.50,165.50
|
||||||
|
74.00,143.00,25.00,25.00,86.50,155.50
|
||||||
|
74.00,132.00,25.00,25.00,86.50,144.50
|
||||||
|
74.00,116.00,25.00,25.00,86.50,128.50
|
||||||
|
74.00,100.00,25.00,25.00,86.50,112.50
|
||||||
|
127.00,179.00,25.00,25.00,139.50,191.50
|
||||||
|
137.00,174.00,25.00,25.00,149.50,186.50
|
||||||
|
143.00,164.00,25.00,25.00,155.50,176.50
|
||||||
|
148.00,148.00,25.00,25.00,160.50,160.50
|
||||||
|
153.00,137.00,25.00,25.00,165.50,149.50
|
||||||
|
158.00,127.00,25.00,25.00,170.50,139.50
|
||||||
|
164.00,111.00,25.00,25.00,176.50,123.50
|
||||||
|
164.00,95.00,25.00,25.00,176.50,107.50
|
After Width: | Height: | Size: 7.6 KiB |
|
@ -0,0 +1,70 @@
|
||||||
|
126,0
|
||||||
|
x,y,dx,dy,x_c,y_c
|
||||||
|
112.00,132.00,19.00,19.00,121.50,141.50
|
||||||
|
108.00,132.00,19.00,19.00,117.50,141.50
|
||||||
|
108.00,132.00,19.00,19.00,117.50,141.50
|
||||||
|
116.00,132.00,19.00,19.00,125.50,141.50
|
||||||
|
116.00,132.00,19.00,19.00,125.50,141.50
|
||||||
|
112.00,124.00,19.00,19.00,121.50,133.50
|
||||||
|
112.00,116.00,19.00,19.00,121.50,125.50
|
||||||
|
112.00,108.00,19.00,19.00,121.50,117.50
|
||||||
|
112.00,100.00,19.00,19.00,121.50,109.50
|
||||||
|
100.00,100.00,19.00,19.00,109.50,109.50
|
||||||
|
96.00,100.00,19.00,19.00,105.50,109.50
|
||||||
|
92.00,100.00,19.00,19.00,101.50,109.50
|
||||||
|
96.00,96.00,19.00,19.00,105.50,105.50
|
||||||
|
92.00,96.00,19.00,19.00,101.50,105.50
|
||||||
|
88.00,96.00,19.00,19.00,97.50,105.50
|
||||||
|
80.00,88.00,19.00,19.00,89.50,97.50
|
||||||
|
84.00,84.00,19.00,19.00,93.50,93.50
|
||||||
|
92.00,84.00,19.00,19.00,101.50,93.50
|
||||||
|
96.00,88.00,19.00,19.00,105.50,97.50
|
||||||
|
104.00,88.00,19.00,19.00,113.50,97.50
|
||||||
|
124.00,104.00,19.00,19.00,133.50,113.50
|
||||||
|
132.00,104.00,19.00,19.00,141.50,113.50
|
||||||
|
136.00,104.00,19.00,19.00,145.50,113.50
|
||||||
|
128.00,104.00,19.00,19.00,137.50,113.50
|
||||||
|
132.00,104.00,19.00,19.00,141.50,113.50
|
||||||
|
136.00,104.00,19.00,19.00,145.50,113.50
|
||||||
|
148.00,96.00,19.00,19.00,157.50,105.50
|
||||||
|
144.00,92.00,19.00,19.00,153.50,101.50
|
||||||
|
136.00,92.00,19.00,19.00,145.50,101.50
|
||||||
|
128.00,92.00,19.00,19.00,137.50,101.50
|
||||||
|
120.00,92.00,19.00,19.00,129.50,101.50
|
||||||
|
112.00,136.00,19.00,19.00,121.50,145.50
|
||||||
|
108.00,136.00,19.00,19.00,117.50,145.50
|
||||||
|
100.00,136.00,19.00,19.00,109.50,145.50
|
||||||
|
96.00,140.00,19.00,19.00,105.50,149.50
|
||||||
|
96.00,140.00,19.00,19.00,105.50,149.50
|
||||||
|
108.00,140.00,19.00,19.00,117.50,149.50
|
||||||
|
112.00,140.00,19.00,19.00,121.50,149.50
|
||||||
|
116.00,136.00,19.00,19.00,125.50,145.50
|
||||||
|
120.00,140.00,19.00,19.00,129.50,149.50
|
||||||
|
124.00,140.00,19.00,19.00,133.50,149.50
|
||||||
|
120.00,140.00,19.00,19.00,129.50,149.50
|
||||||
|
120.00,140.00,19.00,19.00,129.50,149.50
|
||||||
|
120.00,148.00,19.00,19.00,129.50,157.50
|
||||||
|
116.00,144.00,19.00,19.00,125.50,153.50
|
||||||
|
116.00,152.00,19.00,19.00,125.50,161.50
|
||||||
|
108.00,148.00,19.00,19.00,117.50,157.50
|
||||||
|
100.00,152.00,19.00,19.00,109.50,161.50
|
||||||
|
100.00,144.00,19.00,19.00,109.50,153.50
|
||||||
|
96.00,148.00,19.00,19.00,105.50,157.50
|
||||||
|
108.00,152.00,19.00,19.00,117.50,161.50
|
||||||
|
112.00,172.00,19.00,19.00,121.50,181.50
|
||||||
|
100.00,168.00,19.00,19.00,109.50,177.50
|
||||||
|
92.00,164.00,19.00,19.00,101.50,173.50
|
||||||
|
84.00,156.00,19.00,19.00,93.50,165.50
|
||||||
|
80.00,148.00,19.00,19.00,89.50,157.50
|
||||||
|
76.00,136.00,19.00,19.00,85.50,145.50
|
||||||
|
76.00,124.00,19.00,19.00,85.50,133.50
|
||||||
|
72.00,108.00,19.00,19.00,81.50,117.50
|
||||||
|
72.00,96.00,19.00,19.00,81.50,105.50
|
||||||
|
120.00,168.00,19.00,19.00,129.50,177.50
|
||||||
|
128.00,160.00,19.00,19.00,137.50,169.50
|
||||||
|
136.00,152.00,19.00,19.00,145.50,161.50
|
||||||
|
140.00,136.00,19.00,19.00,149.50,145.50
|
||||||
|
144.00,128.00,19.00,19.00,153.50,137.50
|
||||||
|
148.00,120.00,19.00,19.00,157.50,129.50
|
||||||
|
156.00,108.00,19.00,19.00,165.50,117.50
|
||||||
|
156.00,96.00,19.00,19.00,165.50,105.50
|
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 7.6 KiB |
|
@ -0,0 +1,2 @@
|
||||||
|
x,y,dx,dy,score,angle,type
|
||||||
|
61.0,62.0,132.0,132.0,344,0.0,haar
|
After Width: | Height: | Size: 418 KiB |
|
@ -0,0 +1,5 @@
|
||||||
|
x,y,dx,dy,score,angle,type
|
||||||
|
327.0,101.0,121.0,121.0,154,0.0,lbp
|
||||||
|
237.0,106.0,113.0,113.0,139,0.0,lbp
|
||||||
|
164.0,49.0,91.0,91.0,49,0.0,lbp
|
||||||
|
434.0,86.0,94.0,94.0,95,0.0,lbp
|
|
@ -0,0 +1,70 @@
|
||||||
|
208,0
|
||||||
|
x,y,dx,dy,x_c,y_c
|
||||||
|
106.25,131.25,29.69,29.69,121.09,146.09
|
||||||
|
106.25,131.25,29.69,29.69,121.09,146.09
|
||||||
|
106.25,131.25,29.69,29.69,121.09,146.09
|
||||||
|
112.50,131.25,29.69,29.69,127.34,146.09
|
||||||
|
118.75,131.25,29.69,29.69,133.59,146.09
|
||||||
|
106.25,118.75,29.69,29.69,121.09,133.59
|
||||||
|
106.25,112.50,29.69,29.69,121.09,127.34
|
||||||
|
106.25,100.00,29.69,29.69,121.09,114.84
|
||||||
|
106.25,93.75,29.69,29.69,121.09,108.59
|
||||||
|
93.75,93.75,29.69,29.69,108.59,108.59
|
||||||
|
93.75,100.00,29.69,29.69,108.59,114.84
|
||||||
|
87.50,100.00,29.69,29.69,102.34,114.84
|
||||||
|
87.50,93.75,29.69,29.69,102.34,108.59
|
||||||
|
87.50,93.75,29.69,29.69,102.34,108.59
|
||||||
|
81.25,100.00,29.69,29.69,96.09,114.84
|
||||||
|
68.75,87.50,29.69,29.69,83.59,102.34
|
||||||
|
75.00,81.25,29.69,29.69,89.84,96.09
|
||||||
|
87.50,75.00,29.69,29.69,102.34,89.84
|
||||||
|
93.75,81.25,29.69,29.69,108.59,96.09
|
||||||
|
100.00,81.25,29.69,29.69,114.84,96.09
|
||||||
|
118.75,100.00,29.69,29.69,133.59,114.84
|
||||||
|
125.00,100.00,29.69,29.69,139.84,114.84
|
||||||
|
131.25,100.00,29.69,29.69,146.09,114.84
|
||||||
|
125.00,93.75,29.69,29.69,139.84,108.59
|
||||||
|
131.25,93.75,29.69,29.69,146.09,108.59
|
||||||
|
137.50,100.00,29.69,29.69,152.34,114.84
|
||||||
|
150.00,87.50,29.69,29.69,164.84,102.34
|
||||||
|
143.75,81.25,29.69,29.69,158.59,96.09
|
||||||
|
131.25,81.25,29.69,29.69,146.09,96.09
|
||||||
|
125.00,81.25,29.69,29.69,139.84,96.09
|
||||||
|
112.50,81.25,29.69,29.69,127.34,96.09
|
||||||
|
106.25,137.50,29.69,29.69,121.09,152.34
|
||||||
|
100.00,137.50,29.69,29.69,114.84,152.34
|
||||||
|
100.00,137.50,29.69,29.69,114.84,152.34
|
||||||
|
93.75,143.75,29.69,29.69,108.59,158.59
|
||||||
|
93.75,143.75,29.69,29.69,108.59,158.59
|
||||||
|
100.00,143.75,29.69,29.69,114.84,158.59
|
||||||
|
106.25,143.75,29.69,29.69,121.09,158.59
|
||||||
|
118.75,137.50,29.69,29.69,133.59,152.34
|
||||||
|
125.00,137.50,29.69,29.69,139.84,152.34
|
||||||
|
131.25,143.75,29.69,29.69,146.09,158.59
|
||||||
|
125.00,143.75,29.69,29.69,139.84,158.59
|
||||||
|
118.75,143.75,29.69,29.69,133.59,158.59
|
||||||
|
125.00,150.00,29.69,29.69,139.84,164.84
|
||||||
|
118.75,143.75,29.69,29.69,133.59,158.59
|
||||||
|
118.75,156.25,29.69,29.69,133.59,171.09
|
||||||
|
106.25,150.00,29.69,29.69,121.09,164.84
|
||||||
|
100.00,156.25,29.69,29.69,114.84,171.09
|
||||||
|
100.00,143.75,29.69,29.69,114.84,158.59
|
||||||
|
93.75,150.00,29.69,29.69,108.59,164.84
|
||||||
|
106.25,156.25,29.69,29.69,121.09,171.09
|
||||||
|
112.50,181.25,29.69,29.69,127.34,196.09
|
||||||
|
100.00,181.25,29.69,29.69,114.84,196.09
|
||||||
|
87.50,168.75,29.69,29.69,102.34,183.59
|
||||||
|
75.00,150.00,29.69,29.69,89.84,164.84
|
||||||
|
68.75,137.50,29.69,29.69,83.59,152.34
|
||||||
|
62.50,118.75,29.69,29.69,77.34,133.59
|
||||||
|
62.50,106.25,29.69,29.69,77.34,121.09
|
||||||
|
56.25,87.50,29.69,29.69,71.09,102.34
|
||||||
|
56.25,75.00,29.69,29.69,71.09,89.84
|
||||||
|
125.00,175.00,29.69,29.69,139.84,189.84
|
||||||
|
137.50,168.75,29.69,29.69,152.34,183.59
|
||||||
|
143.75,162.50,29.69,29.69,158.59,177.34
|
||||||
|
150.00,150.00,29.69,29.69,164.84,164.84
|
||||||
|
156.25,137.50,29.69,29.69,171.09,152.34
|
||||||
|
156.25,125.00,29.69,29.69,171.09,139.84
|
||||||
|
162.50,106.25,29.69,29.69,177.34,121.09
|
||||||
|
162.50,93.75,29.69,29.69,177.34,108.59
|
After Width: | Height: | Size: 7.6 KiB |