1

Hi I am am working on a small script that would make repetitive picture cropping easier. I wrote a small script that gets the x,y coordinates from the image using mouse event and I am trying to use a code that i have found in the openCV tutorials for cropping an image with a face to certain sizes for a facial database.

import sys, math
import Image
import cv2
import numpy as np
import Tkinter
import tkFileDialog
from Tkinter import Tk
from tkFileDialog import askopenfilename

def Distance(p1,p2):
    dx = p2[0] - p1[0]
    dy = p2[1] - p1[1]
    return math.sqrt(dx*dx+dy*dy)

def ScaleRotateTranslate(image, angle, center = None, new_center = None, scale = None, resample=Image.BICUBIC):
    if (scale is None) and (center is None):
        return image.rotate(angle=angle, resample=resample)
    nx,ny = x,y = center
    sx=sy=1.0
    if new_center:
        (nx,ny) = new_center
    if scale:
        (sx,sy) = (scale, scale)
    cosine = math.cos(angle)
    sine = math.sin(angle)
    a = cosine/sx
    b = sine/sx
    c = x-nx*a-ny*b
    d = -sine/sy
    e = cosine/sy
    f = y-nx*d-ny*e
    return image.transform(image.size, Image.AFFINE, (a,b,c,d,e,f), resample=resample)

def CropFace(image, eye_left=(0,0), eye_right=(0,0), offset_pct=(0.2,0.2), dest_sz = (70,70)):
     # calculate offsets in original image
     offset_h = math.floor(float(offset_pct[0])*dest_sz[0])
     offset_v = math.floor(float(offset_pct[1])*dest_sz[1])
     # get the direction
     eye_direction = (eye_right[0] - eye_left[0], eye_right[1] - eye_left[1])
     # calc rotation angle in radians
     rotation = -math.atan2(float(eye_direction[1]),float(eye_direction[0]))
     # distance between them
     dist = Distance(eye_left, eye_right)
     # calculate the reference eye-width
     reference = dest_sz[0] - 2.0*offset_h
     # scale factor
     scale = float(dist)/float(reference)
     # rotate original around the left eye
     image = ScaleRotateTranslate(image, center=eye_left, angle=rotation)
     # crop the rotated image
     crop_xy = (eye_left[0] - scale*offset_h, eye_left[1] - scale*offset_v)
     crop_size = (dest_sz[0]*scale, dest_sz[1]*scale)
     image = image.crop((int(crop_xy[0]), int(crop_xy[1]), int(crop_xy[0]+crop_size[0]), int(crop_xy[1]+crop_size[1])))
     # resize it
     image = image.resize(dest_sz, Image.ANTIALIAS)
     return image

    # mouse callback function
def getCoord(event,x,y,flags,param):
    global click
    global xs
    global ys
    global xs1
    global ys1
    if event == cv2.EVENT_LBUTTONDOWN:
        print str(x) + " " + str(y)
        with open("coords.txt", "a") as myfile:
            if click == 0:
                xs = x
                ys = y
                #myfile.write(str(x) + " " + str(y) + " ")
            if click == 1:
                xs1 = x
                ys1 = y
                #myfile.write(str(x) + " " + str(y) + "\n")
                print "Press 'Esc' to go to next picture or to exit"    
            click += 1

if __name__ == "__main__":
    global click
    global xs
    global ys
    global xs1
    global ys1
    print "\n"
    print "\n"
    click = 0
    fileList = []
    root = Tkinter.Tk()
    filez = tkFileDialog.askopenfilenames(parent=root,title='Choose a file/files')
    fileList = root.tk.splitlist(filez)
    print root.tk.splitlist(filez)
    lenght = len(fileList)
    print str(lenght)

    for num in range(0,lenght):
        if click == 0:
            print "test"
            image = cv2.imread(str(fileList[num]), cv2.IMREAD_COLOR)
            cv2.namedWindow("Find and Cropp")
            cv2.setMouseCallback("Find and Cropp", getCoord)
            cv2.imshow("Find and Cropp", image)
            if cv2.waitKey(0) & 0xFF == 27:
                    cv2.destroyWindow("Find and Cropp")
            if click > 0:
                elx = int(xs)
                #print xs
                ely = int(ys)
                #print ys
                erx = int(xs1)
                #print xs1
                ery = int(ys1)
                #print ys1
                if click == 2:  
                    #CropFace(image, eye_left=(115,115), eye_right=(168,120), offset_pct=(0.1,0.1), dest_sz=(200,200)).save("01a.jpg")
                    CropFace(image, eye_left=(elx,ely), eye_right=(erx,ery), offset_pct=(0.2,0.2), dest_sz=(200,200)).save("data/" + str(num+1) + ".jpg")
                    CropFace(image, eye_left=(elx,ely), eye_right=(erx,ery), offset_pct=(0.3,0.3), dest_sz=(200,200)).save("data/" + str(num+1) + "a.jpg")
                    #CropFace(image, eye_left=(115,115), eye_right=(168,120), offset_pct=(0.2,0.2)).save("01d.jpg")
                    print "********************" + str(num+1) + ".jpg - saved"
                    click = 0
                    cv2.destroyWindow("Find and Cropp")

Te error that I am getting is AttributeError: 'numpy.ndarray' object has no atribute 'transform'

The error starts on the line:

CropFace(image, eye_left=(elx,ely), eye_right=(erx,ery), offset_pct=(0.2,0.2), dest_sz=(200,200)).save("data/" + str(num+1) + ".jpg")

and finishesh at line:

return image.transform(image.size, Image.AFFINE, (a,b,c,d,e,f), resample=resample)

But when i run the code just for cropping the face (the coordinates were obtained earlier using a first script and saved to a text file) everything is running fine.

3
  • I don't immediately see the problem, but that's also a bit hard because it's just so much code. If you could narrow down your code to the minimal sample that shows when it works and doesn't work, it would be easier to help, plus you might come across the problem along the way yourself. Commented Apr 19, 2014 at 22:43
  • @Nicolas78: Added some comments... Commented Apr 20, 2014 at 0:37
  • Did you trace your code line by line, seeing the value of every variables and making sure that they have the right value?! Commented Apr 20, 2014 at 11:46

1 Answer 1

2

There is a difference between OpenCV and PIL dealing with images. OpenCV is dealing with images as a NumPy array, but PIL stores it as a PIL.Image object.

A NumPy array object doesn't have a transform function, but a PIL Image object has.

If you don't wish to implement the crop face function yourself, first change the NumPy array into a PIL image, and the change the PIL image into a NumPy array.

Change

CropFace(image, eye_left=(elx,ely), eye_right=(erx,ery), offset_pct=(0.3,0.3), dest_sz=(200,200)).save("data/" + str(num+1) + "a.jpg")

into

CropFace(Image.fromarray(np.uint8(image)), eye_left=(elx,ely), eye_right=(erx,ery), offset_pct=(0.3,0.3), dest_sz=(200,200)).save("data/" + str(num+1) + "a.jpg")
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.