Python OpenCV face detection code sometimes raises `'tuple' object has no attribute 'shape'` -
i trying build face detection application in python using opencv.
please see below code snippets:
# loading haar cascade classifier cascadepath = "/home/work/haarcascade_frontalface_default.xml" facecascade = cv2.cascadeclassifier(cascadepath) # dictionary store image name & number of face detected in num_faces_dict = {} # iterate on image directory. # read image, convert in grayscale, detect faces using haarcascade classifier # draw rectangle on image img_fname in os.listdir('/home/work/images/caltech_face_dataset/'): img_path = '/home/work/images/caltech_face_dataset/' + img_fname im = imread(img_path) gray = cv2.cvtcolor(im, cv2.color_rgb2gray) faces = facecascade.detectmultiscale(im) print "number of faces found in-> ", img_fname, " ", faces.shape[0] num_faces_dict[img_fname] = faces.shape[0] (x,y,w,h) in faces: cv2.rectangle(im, (x,y), (x+w,y+h), (255,255,255), 3) rect_img_path = '/home/work/face_detected/rect_' + img_fname cv2.imwrite(rect_img_path,im)
this code works fine of images of them throws error -
i error in line print number of faces. appreciated.
the cause of problem detectmultiscale
returns empty tuple ()
when there's no matches, numpy.ndarray
when there matches.
>>> faces = classifier.detectmultiscale(cv2.imread('face.jpg')) >>> print(type(faces), faces) <class 'numpy.ndarray'> [[ 30 150 40 40]] >>> faces = classifier.detectmultiscale(cv2.imread('wall.jpg')) >>> print(type(faces), faces) <class 'tuple'> ()
you might expect negative result ndarray of shape (0,4), that's not case.
this behaviour , reasoning behind not explained in documentation, instead indicates return value should "objects".
opencv has lot of warts this, , cryptic error messages doesn't help. 1 way deal add logging statements or asserts code check type expected.
it's useful explore how library works in repl such ipython. used in rahul k p's answer.
in case, can solve problem not using shape
. python has many data types sequences or collections, example tuple
, list
, dict
. of these implement len()
built-in function , can loop on them using for x in y
. in contrast shape
property of numpy.ndarray
, , not found in of built-in python data types.
your code should work if rewrite use len(faces)
instead of faces.shape[0]
, since former works both tuple , ndarray.
for img_fname in os.listdir('/home/work/images/caltech_face_dataset/'): img_path = '/home/work/images/caltech_face_dataset/' + img_fname im = imread(img_path) gray = cv2.cvtcolor(im, cv2.color_rgb2gray) faces = facecascade.detectmultiscale(gray) # use grayscale image print "number of faces found in-> {} {}".format( img_fname, len(faces)) # len() works both tuple , ndarray num_faces_dict[img_fname] = len(faces) # when faces (), following loop never run, it's safe. (x,y,w,h) in faces: cv2.rectangle(im, (x,y), (x+w,y+h), (255,255,255), 3) rect_img_path = '/home/work/face_detected/rect_' + img_fname cv2.imwrite(rect_img_path,im)
Comments
Post a Comment