Advertisement
Guest User

Untitled

a guest
Apr 23rd, 2019
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 12.98 KB | None | 0 0
  1. import cv2
  2. import numpy as np
  3. import scipy.spatial.distance as ssd
  4. from datasets import DatasetLoader
  5.  
  6. #
  7. # In der ersten Aufgabe aus dem Bereich Gesichtserkennung sollen Sie sich mit
  8. # Eigenfaces beschaeftigen. Die entsprechenden mathematischen Grundlagen
  9. # sind auf den Folien zu finden.
  10. #
  11. # In dieser Aufgabe werden verschiedene Funktionen der OpenCV Bibliothek
  12. # verwendet. Diese benoetigen Sie aber lediglich zum Anzeigen der Bilder.
  13. # Sie selber muessen keine OpenCV Funktionen verwenden. Bei Interesse koennen
  14. # Sie aber die Dokumentation zu den verwendeten Funktionen unter
  15. # http://docs.opencv.org/ nachschlagen.
  16. #
  17. # Fuer die Eigenfaces wird angenommen, dass jedes Bild die gleiche Groesse hat
  18. # Alle Bilder werden daher auf IMG_SIZE skaliert (heigth, width)
  19. IMG_SIZE = (768, 512)
  20. # Betrachten Sie zunaechst die main Funktion und implementieren Sie die
  21. # entsprechend notwendigen Teile.
  22. #
  23.  
  24. def main():
  25.     #
  26.     # Um Gesichter zu klassifizieren, benoetigen wir zunaechst eine Menge von
  27.     # Trainingsbildern. In dieser Aufgabe kommen die Bilder aus der FERET
  28.     # Datenbank. Fuer diese Aufgabe wird davon eine kleine Untermenge benutzt.
  29.     # Die entsprechenden Bilder werden ueber den DatasetLoader geladen.
  30.     #
  31.     train_images, train_labels, test_images, test_labels = DatasetLoader.load_feret_small()
  32.            
  33.     #
  34.     # 3a)
  35.     # Im ersten Schritt sollen fuers Training das durchschnittliche Gesicht
  36.     # und die ersten 15 Eigenfaces berechnet werden. Implementieren Sie
  37.     # hierfuer die entsprechenden Abschnitte in der compute_eigenfaces
  38.     # Funktion weiter unten.
  39.     #        
  40.     avg_face, eigen_faces = compute_eigenfaces(train_images, num_eigenfaces=15)
  41.    
  42.     #
  43.     # Das durchschnittliche Gesicht anzeigen
  44.     #
  45.     avg_face_img = avg_face.reshape(IMG_SIZE).astype(np.uint8)
  46.     cv2.imshow('avg face', avg_face_img)
  47.     cv2.waitKey(0)    
  48.  
  49.     #
  50.     # Die Eigenfaces anzeigen
  51.     #
  52.     display_eigenfaces(eigen_faces)
  53.     cv2.waitKey(0)    
  54.  
  55.     #
  56.     # Im naechsten Abschnitt soll fuer ein uebergebenes Bild getestet werden,
  57.     # ob es ein Gesicht enthaelt oder nicht. Dazu werden alle Testbildern
  58.     # untersucht.
  59.     #
  60.     for i, img in enumerate(test_images):
  61.         #
  62.         # 3b)
  63.         # Um zu bestimmen, ob das aktuelle Testbild img ein Gesicht enthaelt
  64.         # oder nicht, wird das Bild in den Gesichtsraum projiziert und
  65.         # anschliessend im Bildraum wieder rekonstruiert.
  66.         # Implementieren Sie die entsprechenden Abschnitte der
  67.         # reconstruct_img Funktion weiter unten.
  68.         #
  69.         reconstructed_face = reconstruct_img(img, avg_face, eigen_faces)
  70.        
  71.         #
  72.         # Zeige das Originalbild und die Rekonstruktion an
  73.         #
  74.         cv2.imshow('original face', img)
  75.         cv2.imshow('reconstructed face', reconstructed_face)
  76.         cv2.waitKey(0)
  77.        
  78.         #
  79.         # 3c)
  80.         # In der Funktion classify_face wird mit Hilfe eines Originalbilds
  81.         # und seiner Rekonstruktion entschieden, ob es sich um ein Gesicht
  82.         # handelt.
  83.         # Implementieren sie die entsprechenden Abschnitt der Funktion
  84.         # classify_face weiter unten. Experimentieren Sie anschliessend mit dem
  85.         # threshold Parameter, um ein gutes Klassifikationsergebnis zu
  86.         # erzielen.
  87.         #
  88.         is_face, dist = classify_face(img, reconstructed_face, threshold=-1)
  89.         print (test_labels[i], "isface:", is_face, " | ", dist)        
  90.    
  91.     #
  92.     # 3d)
  93.     # Im naechsten Schritt soll ein Gesicht der entsprechenden Person
  94.     # zugeordnet werden. Dafuer muss zunaechst eine Repraesentation der
  95.     # Trainingsbilder im Gesichtsraum erzeugt werden.
  96.     # Implementieren Sie die entsprechenden Abschnitte der Funktion
  97.     # get_train_projection weiter unten.
  98.     #
  99.     train_proj = get_train_projection(train_images, avg_face, eigen_faces)
  100.      
  101.     #
  102.     # 3e)
  103.     # Die Testbilder koennen nun den Trainingsbildern zugeordnet werden, indem
  104.     # auch fuer Sie eine Repraesentation im Gesichtsraum erzeugt wird und diese
  105.     # mit den Trainingsbilderrepraesentationen verglichen wird.
  106.     # Implementieren Sie die entsprechenden Abschnitte der Funktion
  107.     # get_most_similar_face_id weiter unten.
  108.     #    
  109.     for i, img in enumerate(test_images):        
  110.         idx = get_most_similar_face_id(img, avg_face, eigen_faces, train_proj)
  111.        
  112.         #
  113.         # Im Folgenden wird ein einfacher Nearest Neighbor Klassifikator
  114.         # benutzt, um das aktuelle Bild einer Person zuzuordnen.
  115.         #
  116.         predicted_label = train_labels[idx]
  117.         real_label = test_labels[i]
  118.    
  119.        
  120.         #
  121.         # Ergebnisse anzeigen
  122.         #
  123.         cv2.imshow("pred: " + predicted_label + " | is: " + real_label, img)
  124.         cv2.waitKey(0)
  125.  
  126. def compute_eigenfaces(train_faces, num_eigenfaces):
  127.     '''
  128.    Die Methode berechnet zu den uebergebenen train_faces die ersten k Eigenfaces.
  129.    Die Anzahl k wird hier durch num_eigenfaces ausgedrueckt.
  130.    @param train_faces: Liste mit Trainingsbildern
  131.    @param num_eigenfaces: Anzahl der zu berechnenden Eigenfaces
  132.    @return: Das durchschnittliche Gesicht (in Vektorform),
  133.             Die Eigenfaces als 2D Matrix, jede Zeile bildet ein Eigenfaces
  134.    '''
  135.     #
  136.     # 3a)
  137.     # Generieren Sie eine n x m Matrix aus der train_faces List, indem Sie
  138.     # jedes Bild in einen Vektor ueberfuehren. Die Matrix hat anschliessend
  139.     # n Zeilen (Anzahl der Trainingsbilder) und m Spalten (Laenge des Gesichts-
  140.     # vektors).
  141.     # Erzeugen Sie zunaechst die Ausgabematrix mit np.zeros und speichern Sie
  142.     # anschliessend die Bilder in jeweils eine Zeile.
  143.     #
  144.    
  145.     df = np.zeros((len(train_faces), IMG_SIZE[0] * IMG_SIZE[1]))
  146.     for i in range(0, len(train_faces)):
  147.         df[i] = train_faces[i].flatten()
  148.  
  149.     #
  150.     # Berechnen Sie das durchschnittliche Gesicht und speichern Sie es in einer
  151.     # Variablen avg_face.
  152.     # Subtrahieren Sie das durchschnittliche Gesicht von allen Gesichtsbildern,
  153.     # um die mittelwertfreien Gesichtsbilder zu erhalten.
  154.     # Benutzen Sie fuer die Subtraktion das in Numpy eingebaute Broadcasting.
  155.     #
  156.     # http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html
  157.     #
  158.    
  159.     avg_face = np.sum(df, axis=0) / float(len(df))
  160.     df = df - avg_face
  161.     assert(avg_face.shape[0] == IMG_SIZE[0] * IMG_SIZE[1])
  162.    
  163.     #
  164.     # Benutzen Sie die numpy eigenvalue Funktion (np.linalg.eig),
  165.     # um so die Eigenfaces zu bestimmen. Speichern Sie die Eigenfaces in einer
  166.     # Matrix mit dem Namen e_faces.
  167.     # Achten Sie dabei darauf, dass die Eigenwerte fuer die transformierte Matrix
  168.     # berechnet werden, um das Eigenwertproblem zu vereinfachen (siehe Folien)
  169.     # und Sie daher die Eigenwerte noch Transformieren muessen.
  170.     #
  171.     # Aus welchen der Eigenvektoren werden die k Eigenfaces gebildet?
  172.     #
  173.     # http://docs.scipy.org/doc/numpy/reference/generated/numpy.linalg.eig.html
  174.     #
  175.     #
  176.  
  177.     # Bilde die 28x28 Kovarainzmatrix
  178.     df_T = np.matmul(df, df.T)
  179.  
  180.     # Bestimme die Eigenwerte und Eigenvektoren der Kovarianzmatrix
  181.     e_vals, e_vecs = np.linalg.eig(df_T)
  182.  
  183.     #
  184.     # Kovarianzmatrix im Gesichtsraum bestimmen
  185.     # ACHTUNG: Trick aus den Folien benutzen
  186.     #
  187.  
  188.     e_faces = np.matmul(df.T, e_vecs).T
  189.    
  190.     # Normalisiere die Vektoren
  191.     e_faces = e_faces/np.linalg.norm(e_faces, ord=2, axis=1, keepdims=True)
  192.    
  193.     indices = np.argsort(e_vals)[::-1]
  194.     e_vals = e_vals[indices]
  195.    
  196.     #
  197.     # Eigenfaces bestimmen
  198.     #
  199.     e_faces = e_faces[indices][:num_eigenfaces]
  200.    
  201.     assert(e_faces.shape[0] == num_eigenfaces)
  202.     return avg_face, e_faces  
  203.    
  204. def reconstruct_img(img, avg_face, e_faces):
  205.     '''
  206.    Die Funktion projiziert das Eingabebild in den Gesichtsraum und
  207.    rekonstruiert es schliesslich wieder.
  208.    @param img: Eingabebild
  209.    @param avg_face: das durchschnittliche Gesicht als Vektor
  210.    @param e_faces: 2D Matrix von Eigenfaces, jede Zeile ist ein Eigenface
  211.    @return: Die Rekonstruktion von img mit gleicher Bildgroesse
  212.    '''    
  213.     #
  214.     # Projiziere das Eingabebild in den Gesichtsraum
  215.     #
  216.     proj_img = get_projection(img, avg_face, e_faces)
  217.    
  218.     #
  219.     # Benutzen Sie die Projektion, um das Bild aus dem Gesichtsraum
  220.     # zurueck in den Eingaberaum zu transformieren
  221.     #
  222.     print img.shape
  223.     print avg_face.shape
  224.     print e_faces.shape
  225.     print proj_img.shape
  226.  
  227.     proj_img = np.matmul(proj_img, e_faces)
  228.  
  229.     proj_img = proj_img.reshape((IMG_SIZE[0],IMG_SIZE[1]))
  230.  
  231.     #
  232.     # Skalieren Sie das Bild zurueck auf IMG_SIZE
  233.     # und konvertieren Sie die Pixelwerte in den Bereich [0,255]
  234.     # Tipp: Sie koennen hier die matrix_to_img Funktion benutzen
  235.     #
  236.  
  237.     reconst_img = matrix_to_img(proj_img)
  238.    
  239.     return reconst_img
  240.  
  241. def classify_face(img, reconstructed_img, threshold=1000):
  242.     '''
  243.    Klassifiziert ein Bild mit Hilfe seiner Rekonstruktion aus dem Gesichtsraum
  244.    als Gesicht oder kein Gesicht.
  245.    @param img: das Originalbild
  246.    @param reconstructed_img: das ueber die Eigenfaces rekonstruierte Bild
  247.    @param threshold: der Schwellwert, ab dem ein Bild als kein Gesicht klassifiziert wird
  248.    @return: true (Bild enthaelt ein Gesicht) | false (Bild enthaelt kein GEsicht),
  249.             Unterschied zwischen Rekonstruktion und Originalbild
  250.    '''    
  251.     #
  252.     # 3c)
  253.     # Berechnen Sie die Differenz zwischen Originalbild und seiner Rekonstruktion
  254.     # und geben Sie (true, differenz) zurueck falls es sich um ein Gesicht handelt.
  255.     # Anderfalls geben Sie (false, differenz) zurueck.
  256.     #
  257.     raise NotImplementedError('Implement me')
  258.  
  259. def get_train_projection(train_images, avg_face, e_faces):
  260.     '''
  261.    Die Funktion berechnet fuer jedes Bild die Projektion in den Gesichtsraum.
  262.    @param train_images: Liste von Trainingsbildern
  263.    @param avg_face: das durchschnittliche Gesicht
  264.    @param e_faces: die Eigenfaces als 2D Matrix
  265.    @return: 2D Matrix von Projektionsgewichten  
  266.    '''
  267.     #
  268.     # 3d)
  269.     # Berechnen Sie fuer jedes Bild aus train_images die Projektion
  270.     # und speichern Sie sie in der Liste train_proj ab.
  271.     # Diese wird weiter unten dann in eine Matrix konvertiert.
  272.     #
  273.     train_proj = []
  274.     raise NotImplementedError('Implement me')
  275.    
  276.     train_proj_weights = np.array(train_proj)
  277.     return train_proj_weights
  278.  
  279. def get_most_similar_face_id(img, avg_face, e_faces, train_proj_weights):
  280.     '''
  281.    Die Funktion projiziert das Testbild in den Gesichtsraum und vergleicht
  282.    es dann mit den Trainingsbildern, um so das aehnlichste Gesicht zu erhalten.
  283.    @param img: das Testbild
  284.    @param avg_face: das durchschnittliche Gesicht
  285.    @param e_faces: die Eigenfaces
  286.    @param train_proj_weights: Matrix von Projektionsgewichten fuer die Trainingsbilder    
  287.    @return: id des naechsten Trainingsbildes
  288.    '''    
  289.     #
  290.     # 3e)
  291.     # Benutzen Sie die ssd.cdist Funktion, um die Distanz
  292.     # des projizierten Testbilds zu allen Trainingsbildern zu erhalten.
  293.     # Verwenden Sie die cityblock Metrik als Distanzmass.
  294.     #
  295.     # Beachten Sie, dass die Funktion zwei 2D Matrizen als Eingabe erwartet.
  296.     # Sie koennen entweder den Vektor der Gewichte in eine Liste mit nur einem
  297.     # Element einbetten oder die numpy Funktion atleast_2d benutzen.
  298.     #
  299.     # Nuetzliche Links:
  300.     # http://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.distance.cdist.html
  301.     # http://docs.scipy.org/doc/numpy/reference/generated/numpy.atleast_2d.html
  302.     #
  303.    
  304.     raise NotImplementedError('Implement me')
  305.     return idx
  306.  
  307. def matrix_to_img(mat):
  308.     '''
  309.    Konvertiert die Matrix mat zu einem
  310.    Graustufenbild mit Pixelwerten [0,255]
  311.    @param mat: Eingabematrix mit beliebigen float Typ
  312.    @return: mat konvertiert mit Pixelwerten aus dem Bereich [0, 255]
  313.    '''
  314.     img = np.copy(mat)
  315.     img -= np.min(img)
  316.     img /= np.max(img)
  317.     img *= 255
  318.     img = img.astype(np.uint8)
  319.     return img
  320.  
  321. def get_projection(img, avg_face, e_faces):
  322.     '''
  323.    Die Funktion berechnet ein durchschnittsbereinigtes Bild aus
  324.    img und projiziert es in den Gesichtsraum.
  325.    @param img: Eingabebild
  326.    @param avg_face: das durchschnittliche Gesicht als Vektor
  327.    @param e_faces: 2D Matrix von Eigenfaces, jede Zeile ist ein Eigenface
  328.    @return: Die Projektionsgewichte als Vektor der Laenge num_eigenfaces
  329.    '''
  330.     mean_free_img_vec = (img.flatten() - avg_face)
  331.     proj_weigths = np.dot(e_faces, mean_free_img_vec)
  332.     return proj_weigths  
  333.  
  334. def display_eigenfaces(eigen_faces):
  335.     '''
  336.    Visualisiert die uebergebenen Eigenfaces
  337.    '''
  338.     e_face_images = []
  339.     for e_face in eigen_faces:
  340.         e_face_img = e_face.reshape(IMG_SIZE)
  341.         e_face_img = matrix_to_img(e_face_img)
  342.         resized_face = cv2.resize(e_face_img, (IMG_SIZE[1]/4, IMG_SIZE[0]/4))
  343.         e_face_images.append(resized_face)
  344.    
  345.     e_face_images = np.hstack(e_face_images)
  346.     cv2.imshow('eigen faces', e_face_images)
  347.     return
  348.  
  349. if __name__ == '__main__':
  350.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement