+------------------------------------------------------------------------------+
|                                                                              |
|  Dhananjaya D R                   @/logs   @/software   @/resume   @/contact |
|                                                                              |
+------------------------------------------------------------------------------+


Love at First Byte
________________________________________________________________________________

I was sucked into checking out profiles all day on my phone with Matrimony, and 
I eventually got fed up and wrote a script that automates everything on 
Matrimony.

How does it work? The script builds facial models using my likes/dislikes, 
examines profile images, crops faces, and loads them into an "average" face 
representing choices. Eigenfaces are computed from average faces, and then the 
script makes future selections based on Eigenface comparison. Comparisons are 
essentially k-nearest neighbour selections (the closest matches to my 
preferences).

the results so far? The script is amazingly effective. I would estimate an 
accuracy of up to 70% in its selections. What do girls think of this? Some 
found it was borderline. And Matrimony site admins thought I was spam. If you 
are interested in the code behind this, here's a snippet key definitions.,

+------------------------------------------------------------------------------+
| Python                                                                       |
+------------------------------------------------------------------------------+
|  1  import numpy as np                                                       |
|  2  from scipy import linalg                                                 |
|  3                                                                           |
|  4  class MatrixHelpers:                                                     |
|  5    @staticmethod                                                          |
|  6    def compute_difference_matrix_pixels(pixel_matrix, mean_column):       |
|  7      diff_matrix = np.zeros_like(pixel_matrix)                            |
|  8      for i in range(len(pixel_matrix)):                                   |
|  9        for j in range(len(pixel_matrix[0])):                              |
| 10        diff_matrix[i][j] = pixel_matrix[i][j] - mean_column[i]            |
| 11      return diff_matrix                                                   |
| 12                                                                           |
| 13    @staticmethod                                                          |
| 14    def compute_covariance_matrix(pixel_matrix, diff_matrix):              |
| 15      n = len(pixel_matrix[0])                                             |
| 16      return np.dot(diff_matrix.T, diff_matrix) / n                        |
| 17                                                                           |
| 18    @staticmethod                                                          |
| 19    def compute_eigen_vectors(covariance_matrix):                          |
| 20      eigenvalues, eigenvectors = linalg.eigh(covariance_matrix)           |
| 21                                                                           |
| 22      idx = eigenvalues.argsort()[::-1]                                    |
| 23      eigenvalues = eigenvalues[idx]                                       |
| 24      eigenvectors = eigenvectors[:, idx]                                  |
| 25                                                                           |
| 26      return eigenvectors                                                  |
| 27                                                                           |
| 28    @staticmethod                                                          |
| 29    def compute_image_distance(pixels1, pixels2):                          |
| 30      pixel_count = len(pixels1)                                           |
| 31      distance = 0.0                                                       |
| 32                                                                           |
| 33      for i in range(pixel_count):                                         |
| 34        diff = pixels1[i] - pixels2[i]                                     |
| 35        distance += diff * diff                                            |
| 36                                                                           |
| 37      return np.sqrt(distance / pixel_count)                               |
| 38                                                                           |
| 39  def compute_eigen_faces(pixel_matrix, mean_column):                      |
| 40    diff_matrix = MatrixHelpers.compute_difference_matrix_pixels(pixel_matr|
| 41    ix, mean_column)                                                       |
| 42    covariance_matrix = MatrixHelpers.compute_covariance_matrix(pixel_matr|
| 43    ix, diff_matrix)                                                       |
| 44    eigen_vectors = MatrixHelpers.compute_eigen_vectors(covariance_matrix) |
| 45    return compute_eigen_faces_from_vectors(eigen_vectors, diff_matrix)    |
| 46                                                                           |
| 47  def compute_eigen_faces_from_vectors(eigen_vectors, diff_matrix):        |
| 48    pixel_count = len(diff_matrix)                                         |
| 49    image_count = eigen_vectors.shape[1]                                   |
| 50    rank = eigen_vectors.shape[0]                                          |
| 51                                                                           |
| 52    eigen_faces = np.zeros((pixel_count, rank))                            |
| 53                                                                           |
| 54    for i in range(rank):                                                  |
| 55      for j in range(pixel_count):                                         |
| 56        for k in range(image_count):                                       |
| 57          eigen_faces[j, i] += diff_matrix[j][k] * eigen_vectors[i, k]     |
| 58                                                                           |
| 59      norm = np.sqrt(np.sum(eigen_faces[:, i] ** 2))                       |
| 60      eigen_faces[:, i] /= norm                                            |
| 61                                                                           |
| 62    return eigen_faces                                                     |
| 63                                                                           |
| 64  class FaceRecognizer:                                                    |
| 65    def __init__(self, training_images):                                   |
| 66      self.pixel_matrix = np.array(training_images).T                      |
| 67      self.mean_face = np.mean(self.pixel_matrix, axis=1)                  |
| 68      self.eigen_faces = compute_eigen_faces(self.pixel_matrix, self.mean_f|
| 69      ace)                                                                 |
| 70                                                                           |
| 71      self.projected_faces = []                                            |
| 72      for i in range(len(training_images)):                                |
| 73        face = training_images[i]                                          |
| 74        projection = self.project_face(face)                               |
| 75        self.projected_faces.append(projection)                            |
| 76                                                                           |
| 77    def project_face(self, face):                                          |
| 78      normalized_face = face - self.mean_face                              |
| 79      weights = np.dot(self.eigen_faces.T, normalized_face)                |
| 80      return weights                                                       |
| 81                                                                           |
| 82    def reconstruct_face(self, weights):                                   |
| 83      face = np.dot(self.eigen_faces, weights) + self.mean_face            |
| 84      return face                                                          |
| 85                                                                           |
| 86    def recognize_face(self, face, threshold=None):                        |
| 87      projection = self.project_face(face)                                 |
| 88                                                                           |
| 89      min_distance = float('inf')                                          |
| 90      min_index = -1                                                       |
| 91                                                                           |
| 92      for i, known_projection in enumerate(self.projected_faces):          |
| 93        distance = MatrixHelpers.compute_image_distance(projection, known_p|
| 94        rojection)                                                         |
| 95                                                                           |
| 96        if distance < min_distance:                                        |
| 97          min_distance = distance                                          |
| 98          min_index = i                                                    |
| 99                                                                           |
|100      match_found = True                                                   |
|101      if threshold is not None:                                            |
|102        match_found = min_distance < threshold                             |
|103                                                                           |
|104      return min_index, min_distance, match_found                          |
|105                                                                           |
|106  if __name__ == '__main__':                                               |
|107    # Example with dummy data                                              |
|108    dummy_images = [                                                       |
|109      np.random.rand(100),                                                 |
|110      np.random.rand(100),                                                 |
|111      np.random.rand(100)                                                  |
|112    ]                                                                      |
|113                                                                           |
|114    recognizer = FaceRecognizer(dummy_images)                              |
|115    test_face = dummy_images[0] * 0.9 + np.random.rand(100) * 0.1          |
|116    match_idx, distance, match_found = recognizer.recognize_face(test_face,|
|117    threshold=0.5)                                                         |
|118                                                                           |
|119    print(f"Best match: Face #{match_idx + 1}")                            |
|120    print(f"Distance: {distance:.4f}")                                     |
|121    print(f"Match found: {match_found}")                                   |
+------------------------------------------------------------------------------+

________________________________________________________________________________