mysociety / yournextrepresentative

A website for crowd-sourcing structured election candidate data
https://candidates.democracyclub.org.uk/
GNU Affero General Public License v3.0
56 stars 21 forks source link

Make face recognition work under Python 3 #889

Open wfdd opened 8 years ago

wfdd commented 8 years ago

OpenCV 3 supports Python 3 but has a different API. This seemed to work for me:

diff --git a/moderation_queue/faces.py b/moderation_queue/faces.py
index 7292566..c9d2bed 100644
--- a/moderation_queue/faces.py
+++ b/moderation_queue/faces.py
@@ -3,8 +3,8 @@ from __future__ import unicode_literals
 # easy_thumbnails face cropping processor
 # Much of the below taken from http://stackoverflow.com/a/13243712/669631

-import cv
-faceCascade = cv.Load('/usr/share/opencv/haarcascades/haarcascade_frontalface_alt.xml')
+import cv2
+import numpy

 # Select one of the haarcascade files:
 #   haarcascade_frontalface_alt.xml  <-- Best one?
@@ -12,42 +12,32 @@ faceCascade = cv.Load('/usr/share/opencv/haarcascades/haarcascade_frontalface_al
 #   haarcascade_frontalface_alt_tree.xml
 #   haarcascade_frontalface_default.xml
 #   haarcascade_profileface.xml
+face_cascade = cv2.CascadeClassifier('/usr/share/opencv/haarcascades/haarcascade_frontalface_alt.xml')

-def detectFaces(im):
+def detect_faces(im):
     # This function takes a PIL image and finds the patterns defined in the
     # haarcascade function modified from: http://www.lucaamore.com/?p=638

     # Convert a PIL image to a greyscale cv image
-    # from: http://pythonpath.wordpress.com/2012/05/08/pil-to-opencv-image/
-    im = im.convert('L')
-    cv_im = cv.CreateImageHeader(im.size, cv.IPL_DEPTH_8U, 1)
-    cv.SetData(cv_im, im.tostring(), im.size[0])
-
-    # variables
-    min_size = (20, 20)
-    haar_scale = 1.1
-    min_neighbors = 3
-    haar_flags = 0
-
+    cv_im = cv2.cvtColor(numpy.array(im), cv2.COLOR_RGB2GRAY)
     # Equalize the histogram
-    cv.EqualizeHist(cv_im, cv_im)
+    cv_im = cv2.equalizeHist(cv_im)

     # Detect the faces
-    faces = cv.HaarDetectObjects(
-        cv_im, faceCascade, cv.CreateMemStorage(0),
-        haar_scale, min_neighbors, haar_flags, min_size
+    faces = face_cascade.detectMultiScale(
+        cv_im,
+        scaleFactor=1.1, minNeighbors=3, minSize=(20, 20)
         )
-
     return faces

 def face_crop_bounds(im):
     source_x, source_y = [int(v) for v in im.size]
-    faces = detectFaces(im)
+    faces = detect_faces(im).tolist()
     if not faces:
         return None
     cropBox = [0, 0, 0, 0]
-    for face, n in faces:
+    for face in faces:
         if face[2] > cropBox[2] or face[3] > cropBox[3]:
             cropBox = face
wfdd commented 8 years ago

neavouli/yournextrepresentative@5a0acc2 should you ever wish to cherry-pick it (though that might be a few years still if you're using Debian/Ubuntu and would rather not build from source).