2013-05-02 66 views
1

我正試圖在Python中使用主成分分析(PCA)進行手勢識別(類似於人臉識別)。我有一張測試圖像,我想從一組訓練圖像中獲得最接近的匹配。人臉識別 - 如何返回正確的圖像?

這是我的代碼:

import os, sys 
import numpy as np 
import PIL.Image as Image 


def read_images(path, sz=None): 
    c = 0 
    X,y = [], [] 
    for dirname, dirnames, filenames in os.walk(path): 
     for subdirname in dirnames: 
      subject_path = os.path.join(dirname, subdirname) 
      for filename in os.listdir(subject_path): 
       try: 
        im = Image.open(os.path.join(subject_path, filename)) 
        im = im.convert("L") 
        # resize to given size (if given) 
        if (sz is not None): 
         im = im.resize(sz, Image.ANTIALIAS) 
        X.append(np.asarray(im, dtype=np.uint8)) 
        y.append(c) 
       except IOError: 
        print "I/O error({0}): {1}".format(errno, strerror) 
       except: 
        print "Unexpected error:", sys.exc_info()[0] 
        raise 
      c = c+1 
    return [X,y] 


def asRowMatrix(X): 
    if len(X) == 0: 
     return np.array([]) 
    mat = np.empty((0, X[0].size), dtype=X[0].dtype) 
    for row in X: 
     mat = np.vstack((mat, np.asarray(row).reshape(1,-1))) 
    return mat 


def asColumnMatrix(X): 
    if len(X) == 0: 
     return np.array([]) 
    mat = np.empty((X[0].size, 0), dtype=X[0].dtype) 
    for col in X: 
     mat = np.hstack((mat, np.asarray(col).reshape(-1,1))) 
    return mat 


def pca(X, y, num_components=0): 
    [n,d] = X.shape 
    if (num_components <= 0) or (num_components>n): 
     num_components = n 
    mu = X.mean(axis=0) 
    X = X - mu 
    if n>d: 
     C = np.dot(X.T,X) 
     [eigenvalues,eigenvectors] = np.linalg.eigh(C) 
    else: 
     C = np.dot(X,X.T) 
     [eigenvalues,eigenvectors] = np.linalg.eigh(C) 
     eigenvectors = np.dot(X.T,eigenvectors) 
     for i in xrange(n): 
      eigenvectors[:,i] = eigenvectors[:,i]/np.linalg.norm(eigenvectors[:,i]) 
    # or simply perform an economy size decomposition 
    # eigenvectors, eigenvalues, variance = np.linalg.svd(X.T, full_matrices=False) 
    # sort eigenvectors descending by their eigenvalue 
    idx = np.argsort(-eigenvalues) 
    eigenvalues = eigenvalues[idx] 
    eigenvectors = eigenvectors[:,idx] 
    # select only num_components 
    eigenvalues = eigenvalues[0:num_components].copy() 
    eigenvectors = eigenvectors[:,0:num_components].copy() 
    return [eigenvalues, eigenvectors, mu, X] 


#Get eigenvalues, eigenvectors, mean and shifted images (Training) 
[a, b] = read_images('C:\\Users\\Karim\\Desktop\\Training & Test images\\AT&T\\att_faces', (90,90)) 
[evalues, evectors, mean_image, shifted_images] = pca(asRowMatrix(a), b) 


#Input(Test) image 
input_image = Image.open('C:\\Users\\Karim\\Desktop\\Training & Test images\\AT&T\\Test\\4.pgm').convert('L').resize((90, 90)) 
input_image = np.asarray(input_image).flatten() 


#Normalizing input image 
shifted_in = input_image - mean_image 


#Finding weights 
w = evectors.T * shifted_images 
w = np.asarray(w) 
w_in = evectors.T * shifted_in 
w_in = np.asarray(w_in) 


#Euclidean distance 
df = np.asarray(w - w_in)    # the difference between the images 
dst = np.sqrt(np.sum(df**2, axis=1))  # their euclidean distances 

現在我有包括測試圖像,並且在該組訓練圖像的每一個圖像之間的歐幾里德距離的距離dst的陣列。

如何獲取最近(最小)距離及其路徑(或子目錄名稱)的圖像?不是數組中的最小距離和索引的值dst

回答

3

dst.argmin()會告訴您dst中元素的索引,它是最小的。

所以最接近的圖像會

idx = dst.argmin() 
closest = a[idx] 

因爲a是代表培訓面陣列的列表。

爲了顯示最接近的圖像,你可以使用:

img = Image.fromarray(closest, 'L') 
img.show() 

要找到最接近的圖像文件的路徑,我會改變read_images返回的所有文件路徑列表,所以它可以像圖像列表一樣進行索引。

def read_images(path, sz=None): 
    X, y = [], [] 
    for dirname, dirnames, filenames in os.walk(path): 
     for filename in filenames: 
      subject_path = os.path.join(dirname, filename) 
      try: 
       im = Image.open(subject_path) 
      except IOError as err: 
       print "I/O error: {e}: {f}".format(e=err, f=subject_path) 
      except: 
       print "Unexpected error:", sys.exc_info()[0] 
       raise 
      else: 
       im = im.convert("L") 
       # resize to given size (if given) 
       if (sz is not None): 
        im = im.resize(sz, Image.ANTIALIAS) 
       X.append(np.asarray(im, dtype=np.uint8)) 
       y.append(subject_path) 
    return [X, y] 

下面,這樣稱呼它:

images, paths = read_images(TRAINING_DIR, (90, 90)) 

然後,您可以得到充分的路徑到最近的圖像與

idx = dst.argmin() 
filename = paths[idx] 

如果你想子目錄人的路,使用

os.path.dirname(filename) 

而對於子目錄的名稱,使用

os.path.basename(os.path.dirname(filename)) 
+0

我想獲得它的路徑或打印圖像 – user2229953 2013-05-02 02:15:33

+0

你能告訴我怎麼走了圖像存儲在子文件夾的名字嗎? – user2229953 2013-05-02 12:00:39

+0

我在文件夾名稱前出現兩次'I/O錯誤:無法識別圖像文件'。輸出如下所示: 'I/O錯誤:無法識別映像文件 I/O錯誤:無法識別映像文件 新文件夾# 您知道爲什麼嗎? – user2229953 2013-05-05 12:13:52