I am trying out a code for face and eye detection in Open CV using Python. The code works well for image size 2848 X 4272 and even when I resized it by a factor of 0.5. But whenever I am resizing it with another factors such as 0.2,0.4 etc , it gives me ambiguous results for eyes(such as few regions of forehead, nose).In that case I am not able to get a generalised code for all image sizes. Is there any code so that I get correct detections with any image size as its very difficult to process such big images. The code is as such
import numpy as np
import cv2
import cv2.cv as cv
#attaching the haar cascade files
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
eye_cascade = cv2.CascadeClassifier('haarcascade_eye.xml')
# reading the image
img11 = cv2.imread('IMG_0347.JPG')
if img11 !=None:
# resizing the image
w,h,c= img11.shape
print "dimension"
print w,h
img = cv2.resize(img11,None,fx=0.4, fy=0.3, interpolation = cv2.INTER_LINEAR)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # converting into grayscale
gray = cv2.equalizeHist(gray)
#cv2.imshow('histo',gray)
w,h,c= img.shape # finding out the dimensions of the image i.e width, height and number of channels
# creating a white background of same dimensions as input image for pasting the eyes detected by 'haarcascade_eye.xml'
im = np.zeros((w,h,c),np.uint8)
im[:]=[255,255,255]
# creating a white background of same dimensions as input image for pasting the masked eyes
im_mask = np.zeros((w,h,c),np.uint8)
im_mask[:]=[255,255,255]
# faces gives the top left coordinates of the detected face and width and height of the rectangle
faces = face_cascade.detectMultiScale(gray, 1.5, 5)
# taking face as the ROI
for (x,y,w,h) in faces:
cv2.rectangle(img,(x,y),(x+w,y+h),(255,0,0),1) # Draws the rectangle around the detected face
roi_gray = gray[y:y+h, x:x+w]
roi_color = img[y:y+h, x:x+w]
#cv2.imshow('image1',img) # shows the original image with face detected
#cv2.imshow('image1',roi_color) # shows only the face detected (colored)
# searching for eyes in the detected face i.e in the roi gray
eyes = eye_cascade.detectMultiScale(roi_gray)
#print eyes # prints the top left coordinates of the detected eyes and width and height of the rectangle
if eyes.any():
for (ex,ey,ew,eh)in eyes:
cv2.rectangle(roi_color,(ex,ey),(ex+ew,ey+eh),(0,255,0),1) # draws rectangle around the masked eyes
eye_mask= roi_color[ey+1:u, ex+1:ex+ew] # eye_mask is the masked portion of the detected eye extracted from roi_color
im_mask[ey+1+y:y+u, ex+x+1:ex+ew+x]=eye_mask #pasting the eye_mask on the white background called im_mask
else:
print ("eyes could not be detected")
cv2.imshow('image',im_mask) #shows the im-mask white background with masked eyes pasted on it
It is logical that as the image gets smaller and smaller, it becomes harder to differentiate an eye from a nose, for example. So unless you understand fundamentally what your image analysis functions are looking for (I don't) it's hard to know the best way to downsize your images while retaining the type of information that the analysis needs.
Having said that, I believe cv2.INTER_AREA
is used for shrinking images more commonly than cv2.INTER_LINEAR
etc.
Try this instead of the resize you have:
img = cv2.resize(img11, None, fx=0.4, fy=0.3, interpolation=cv2.INTER_AREA)
Also, aren't you making it harder to identify eyes by changing the aspect ratio of your images (fx != fy)? If you don't have a special reason for that, you can just choose the target size explicitly with the second position argument, size. For example:
effective_but_smaller_size = (640, 480) # or whatever you find works
img = cv2.resize(img11, effective_but_smaller_size, interpolation=cv2.INTER_AREA)