2013-04-15 3 views
3

Я пытаюсь реализовать распознавание лиц с помощью анализа основных компонентов (PCA) с использованием python. Одним из этапов является нормализация входного (тестового) изображения T путем вычитания среднего вектора лица m: n = T - m.Python - ValueError: операнды не могут быть переданы вместе с фигурами

Вот мой код:

#Step1: put database images into a 2D array 
filenames = glob.glob('C:\\Users\\Karim\\Downloads\\att_faces\\New folder/*.pgm') 
filenames.sort() 
img = [Image.open(fn).convert('L').resize((90, 90)) for fn in filenames] 
images = np.asarray([np.array(im).flatten() for im in img]) 

#Step 2: find the mean image and the mean-shifted input images 
m = images.mean(axis=0) 
shifted_images = images - m 

#Step 7: input image 
input_image = Image.open('C:\\Users\\Karim\\Downloads\\att_faces\\1.pgm').convert('L').resize((90, 90)) 
T = np.asarray(input_image) 
n = T - mean_image 

Но я получаю сообщение об ошибке Traceback (most recent call last): File "C:/Users/Karim/Desktop/Bachelor 2/New folder/new3.py", line 46, in <module> n = T - m ValueError: operands could not be broadcast together with shapes (90,90) (8100)

ответ

3

mean_image был вычислен для плоских массивов:

images = np.asarray([np.array(im).flatten() for im in img]) 
mean_image = images.mean(axis=0) 

и input_image является 90х90. Отсюда и ошибка. Вы должны либо сгладить входное изображение, либо не сгладить исходные изображения (я не совсем понимаю, почему вы это сделали), либо изменить размер mean_image на 90x90 только для этой операции.

+0

изображения должны быть сплющены, чтобы быть 2D-матрицей вместо 3D, чтобы иметь возможность вычислять среднее, ковариацию, собственные значения и собственные векторы. С другой стороны, если входное изображение будет сплющено, это будет 1D-массив, и я также не смогу вычислить среднее, ковариацию, собственные значения и собственные векторы. – user2229953

+2

@ user2229953 Я не думаю, что это необходимо для любых функций, которые принимают аргумент 'axis', как примечания @askewchan. Во всяком случае, прямо сейчас вы вычитаете массив 8100 1D из массива 90x90, который должен быть исправлен так или иначе. –

3

Как говорит @Lev, вы сплющили свои массивы. Вам действительно не нужно делать это, чтобы выполнить среднее значение. Скажем, у вас есть массив из 2 3х4 изображений, то вы бы что-то вроде этого:

In [291]: b = np.random.rand(2,3,4) 

In [292]: b.shape 
Out[292]: (2, 3, 4) 

In [293]: b 
Out[293]: 
array([[[ 0.18827554, 0.11340471, 0.45185287, 0.47889188], 
     [ 0.35961448, 0.38316556, 0.73464482, 0.37597429], 
     [ 0.81647845, 0.28128797, 0.33138755, 0.55403119]], 

     [[ 0.92025024, 0.55916671, 0.23892798, 0.59253267], 
     [ 0.15664109, 0.12457157, 0.28139198, 0.31634361], 
     [ 0.33420446, 0.27599807, 0.40336601, 0.67738928]]]) 

Perform среднего по первой оси, оставляя форму массивов:

In [300]: b.mean(0) 
Out[300]: 
array([[ 0.55426289, 0.33628571, 0.34539042, 0.53571227], 
     [ 0.25812778, 0.25386857, 0.5080184 , 0.34615895], 
     [ 0.57534146, 0.27864302, 0.36737678, 0.61571023]]) 

In [301]: b - b.mean(0) 
Out[301]: 
array([[[-0.36598735, -0.222881 , 0.10646245, -0.0568204 ], 
     [ 0.10148669, 0.129297 , 0.22662642, 0.02981534], 
     [ 0.24113699, 0.00264495, -0.03598923, -0.06167904]], 

     [[ 0.36598735, 0.222881 , -0.10646245, 0.0568204 ], 
     [-0.10148669, -0.129297 , -0.22662642, -0.02981534], 
     [-0.24113699, -0.00264495, 0.03598923, 0.06167904]]]) 

Для многих , это также будет быстрее, чем сохранение ваших изображений в виде списка массивов, поскольку операции numpy выполняются в одном массиве, а не через список массивов. Большинство методов, таких как mean, cov и т. Д., Принимают аргумент axis, и вы можете перечислить все размеры для его выполнения без необходимости сглаживания.

Чтобы применить это в сценарий, я хотел бы сделать что-то вроде этого, сохраняя оригинальные размерности:

images = np.asarray([Image.open(fn).convert('L').resize((90, 90)) for fn in filenames]) 
# so images.shape = (len(filenames), 90, 90) 

m = images.mean(0) 
# numpy broadcasting will automatically subract the (90, 90) mean image from each of the `images` 
# m.shape = (90, 90) 
# shifted_images.shape = images.shape = (len(filenames), 90, 90) 
shifted_images = images - m 

#Step 7: input image 
input_image = Image.open(...).convert('L').resize((90, 90)) 
T = np.asarray(input_image) 
n = T - m 

В качестве последнего комментария, если скорость является проблемой, это будет быстрее использовать np.dstack присоединиться изображения:

In [354]: timeit b = np.asarray([np.empty((50,100)) for i in xrange(1000)]) 
1 loops, best of 3: 824 ms per loop 

In [355]: timeit b = np.dstack([np.empty((50,100)) for i in xrange(1000)]).transpose(2,0,1) 
10 loops, best of 3: 118 ms per loop 

Но это, вероятно, что загрузка изображений занимает большую часть времени, и если это так, вы можете проигнорировать это.

+1

Я пытаюсь использовать то, что вы предложили, но я беру ошибку «Traceback (последний последний звонок): Файл« C:/Users/Karim/Desktop/Bachelor 2/Новая папка/new4.py », строка 12, в images = np.asarray ([Image.open (fn) .convert ('L'). Resize ((90, 90)) для fn в именах файлов]) Файл «C: \ Python27 \ lib \ site-packages \ numpy \ core \ numeric.py ", строка 320, в asarray return array (a, dtype, copy = False, order = order) SystemError: ошибка возврата без исключения set' – user2229953

+0

OK Я не понимаю эту ошибку, но попробуйте изменить 'np.asarray' на' np.array'. – askewchan

+0

Попробуйте то, что у вас есть, но избавьтесь от '.flatten':' imgs = [Image.open (fn) .convert ('L'). Resize ((90, 90)) для fn в именах файлов] '; 'images = np.asarray ([np.array (img) для img в imgs])' – askewchan