120 lines
3.4 KiB
Python
120 lines
3.4 KiB
Python
|
import cv2
|
||
|
import numpy as np
|
||
|
import os
|
||
|
import uz_framework.image as uz
|
||
|
|
||
|
IMAGES_FOLDER = './datam/me/'
|
||
|
|
||
|
|
||
|
|
||
|
def read_images(path):
|
||
|
# Get all the path to the images and save them in a list
|
||
|
image_paths = [os.path.join(path, f) for f in os.listdir(path)]
|
||
|
|
||
|
images = []
|
||
|
|
||
|
for image_path in image_paths:
|
||
|
# Read the image and convert to grayscale
|
||
|
image_pil = cv2.imread(image_path, 0)
|
||
|
# Convert the image format into numpy array
|
||
|
image = np.array(image_pil, 'uint8')
|
||
|
|
||
|
images.append(image)
|
||
|
|
||
|
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
|
||
|
|
||
|
faces = []
|
||
|
for image in images:
|
||
|
# Detect face in the image
|
||
|
face = face_cascade.detectMultiScale(image, 1.3, 5)
|
||
|
|
||
|
for (x, y, w, h) in face:
|
||
|
# Crop the face out
|
||
|
H = 300
|
||
|
W = 280
|
||
|
y_offset = 20
|
||
|
x_offset = 30
|
||
|
face = image[y-y_offset:(y-y_offset)+H, x-x_offset:(x-x_offset)+W].copy()
|
||
|
faces.append(face)
|
||
|
|
||
|
return np.array(faces)
|
||
|
|
||
|
def train(faces):
|
||
|
# Construct PCA of the faces
|
||
|
# Reshape all the images into a single matrix of size (n, m)
|
||
|
|
||
|
# Downsample the images
|
||
|
fcc = np.array([])
|
||
|
for face in faces:
|
||
|
face = cv2.pyrDown(face)
|
||
|
face = face.reshape((face.shape[0] * face.shape[1]), 1)
|
||
|
if fcc.size == 0:
|
||
|
fcc = face
|
||
|
else:
|
||
|
fcc = np.hstack((fcc, face))
|
||
|
|
||
|
print(fcc.shape)
|
||
|
U, _, _, mean = uz.dual_PCA(fcc.T)
|
||
|
|
||
|
return U, mean
|
||
|
|
||
|
def recognize(U, mean):
|
||
|
# Open webcam stream
|
||
|
cam = cv2.VideoCapture(0)
|
||
|
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
|
||
|
|
||
|
while True:
|
||
|
# Read the frame
|
||
|
_, frame = cam.read()
|
||
|
# Convert to grayscale
|
||
|
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
|
||
|
# Detect faces
|
||
|
face = face_cascade.detectMultiScale(gray, 1.3, 5)
|
||
|
|
||
|
for (x, y, w, h) in face:
|
||
|
# Crop the face
|
||
|
H = 300
|
||
|
W = 280
|
||
|
y_offset = 20
|
||
|
x_offset = 30
|
||
|
face = gray[y-y_offset:(y-y_offset)+H, x-x_offset:(x-x_offset)+W].copy()
|
||
|
|
||
|
if face.shape[0] != H or face.shape[1] != W:
|
||
|
continue
|
||
|
|
||
|
# Project the face into the PCA subspace
|
||
|
# Project images into PCA subspace
|
||
|
# Downsample the image
|
||
|
face = cv2.pyrDown(face)
|
||
|
face = face.reshape(-1) # Reshape it into a vector
|
||
|
y_i = np.matmul(face - mean, U)
|
||
|
|
||
|
# Project images back into original subspace
|
||
|
x_i = np.matmul(y_i, U.T) + mean
|
||
|
|
||
|
# Compute the L2 norm between the original image and the reconstructed image
|
||
|
norm = np.linalg.norm(face - x_i)
|
||
|
|
||
|
# If the norm is less than 1000, then the face is recognized
|
||
|
if norm < 8000:
|
||
|
cv2.putText(frame, 'Recognized Gasper', (x, y), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 0), 2)
|
||
|
# Plot the rectangle around the face
|
||
|
cv2.rectangle(frame, (x, y), (x+w, y+h), (255, 0, 0), 2)
|
||
|
|
||
|
# Display the frame
|
||
|
cv2.imshow('frame', frame)
|
||
|
|
||
|
# Exit if 'q' is pressed
|
||
|
if cv2.waitKey(1) & 0xFF == ord('q'):
|
||
|
break
|
||
|
|
||
|
def main():
|
||
|
faces = read_images(IMAGES_FOLDER)
|
||
|
U, mean = train(faces)
|
||
|
recognize(U, mean)
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
main()
|
||
|
|