Python 属性错误:'numpy.ndarray
你好,我正在做一个小脚本,目的是让重复的图片裁剪变得更简单。
我写了一个小脚本,可以通过鼠标事件获取图片的 x 和 y 坐标。然后我尝试使用在 openCV 教程中找到的一段代码,来把包含人脸的图片裁剪成特定的大小,以便用于人脸数据库。
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")
我遇到的错误是:
AttributeError: 'numpy.ndarray' object has no attribute 'transform'
这个错误出现在这行代码:
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")
并在这行代码结束:
return image.transform(image.size, Image.AFFINE, (a,b,c,d,e,f), resample=resample)
不过,当我只运行裁剪人脸的代码时(这些坐标是之前用第一个脚本获取并保存到文本文件中的),一切都运行得很好。
1 个回答
2
OpenCV和PIL在处理图像时是有区别的。OpenCV把图像当作NumPy数组来处理,而PIL则把图像存储为一个PIL.Image
对象。
NumPy数组对象没有变换功能,但PIL图像对象是有的。
如果你不想自己实现裁剪人脸的功能,首先要把NumPy数组转换成PIL图像,然后再把PIL图像转换回NumPy数组。
把
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.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")