+------------------------------------------------------------------------------+ | | | 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}") | +------------------------------------------------------------------------------+ ________________________________________________________________________________