Before Discuss my problem, I described what I want to do. I want to recognize every user based on profile image with single face and determine if the user is fake or not.
The given dataset contains training dataset consist of 10 profile images of each user that already uploaded from the applications and testing images consisting of 6 random user’s profile images.
Here is my Code:
import os
import cv2 as cv
import numpy as np
def get_path_list(root_path):
'''
To get a list of path directories from root path
Parameters
----------
root_path : str
Location of root directory
Returns
-------
list
List containing the names of the sub-directories in the
root directory
'''
names = os.listdir(root_path)
return names
def get_class_id(root_path, train_names):
'''
To get a list of train images and a list of image classes id
Parameters
----------
root_path : str
Location of images root directory
train_names : list
List containing the names of the train sub-directories
Returns
-------
list
List containing all image in the train directories
list
List containing all image classes id
'''
image_list = []
class_ids = []
for id, person_name in enumerate(train_names):
person_dir = root_path + "/" + person_name
for person_img_sample in os.listdir(person_dir):
img = cv.imread(person_dir + "/" + person_img_sample)
h, w, _ = img.shape
ratio = 600 / w
new_h = h * ratio
img = cv.resize(img, (600, int(new_h)))
image_list.append(img)
class_ids.append(id)
# print(person_dir + "/" + person_img_sample, id)
return image_list, class_ids
def detect_faces_and_filter(image_list, image_classes_list=None):
'''
To detect a face from given image list and filter it if the face on
the given image is less than one
Parameters
----------
image_list : list
List containing all loaded images
image_classes_list : list, optional
List containing all image classes id
Returns
-------
list
List containing all filtered and cropped face images in grayscale
list
List containing all filtered faces location saved in rectangle
list
List containing all filtered image classes id
'''
cropped_face_images = []
face_locations = []
image_class_ids = []
if image_classes_list is None:
image_classes_list = [-1] * len(image_list)
face_cascade = cv.CascadeClassifier('haarcascade_frontalface_default.xml')
for img, id in zip(image_list, image_classes_list):
img = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
faces = face_cascade.detectMultiScale(img, scaleFactor=1.3,
minNeighbors=7)
if len(faces) == 1:
for (x, y, w, h) in faces:
cropped_face = img[y:y + h, x:x + w]
cropped_face_images.append(cropped_face)
face_locations.append((x, y, w, h))
image_class_ids.append(id)
else:
pass
return cropped_face_images, face_locations, image_class_ids
def train(train_face_grays, image_classes_list):
'''
To create and train face recognizer object
Parameters
----------
train_face_grays : list
List containing all filtered and cropped face images in grayscale
image_classes_list : list
List containing all filtered image classes id
Returns
-------
object
Recognizer object after being trained with cropped face images
'''
recognizer = cv.face.LBPHFaceRecognizer_create()
recognizer.train(train_face_grays, np.array(image_classes_list))
return recognizer
def get_test_images_data(test_root_path):
'''
To load a list of test images from given path list
Parameters
----------
test_root_path : str
Location of images root directory
Returns
-------
list
List containing all loaded gray test images
'''
test_imgs = []
for img_loc in os.listdir(test_root_path):
img = cv.imread(test_root_path + "/" + img_loc)
h, w, _ = img.shape
ratio = 600 / w
new_h = h * ratio
img = cv.resize(img, (600, int(new_h)))
test_imgs.append(img)
return test_imgs
def predict(recognizer, test_faces_gray):
'''
To predict the test image with the recognizer
Parameters
----------
recognizer : object
Recognizer object after being trained with cropped face images
train_face_grays : list
List containing all filtered and cropped face images in grayscale
Returns
-------
list
List containing all prediction results from given test faces
'''
results = []
for face in test_faces_gray:
class_id, c = recognizer.predict(face)
results.append(class_id)
print(class_id, c)
return results
def draw_prediction_results(predict_results, test_image_list, test_faces_rects, train_names):
'''
To draw prediction results on the given test images and acceptance status
Parameters
----------
predict_results : list
List containing all prediction results from given test faces
test_image_list : list
List containing all loaded test images
test_faces_rects : list
List containing all filtered faces location saved in rectangle
train_names : list
List containing the names of the train sub-directories
Returns
-------
list
List containing all test images after being drawn with
final result
'''
verification_statuses = []
unverified_agent = ['Riza', 'High T']
for i, pred in enumerate(predict_results):
name = train_names[pred]
if name in unverified_agent:
verification_statuses.append([name, 0])
else:
verification_statuses.append([name, 1])
drawn_imgs = []
font = cv.FONT_HERSHEY_SIMPLEX
for ver, img, (x, y, w, h) in zip(verification_statuses, test_image_list, test_faces_rects):
if ver[1] == 1:
img = cv.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 8)
img = cv.putText(img, ver[0], (x, y + h + 55), font, 2, (0, 255, 0), 5, cv.FONT_HERSHEY_SIMPLEX)
else:
img = cv.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 8)
img = cv.putText(img, ver[0] + " (Fake)", (x, y + h + 55), font, 2, (0, 0, 255), 5, cv.FONT_HERSHEY_SIMPLEX)
img = cv.resize(img, (250, 250))
drawn_imgs.append([img, ver[1]])
return drawn_imgs
def combine_and_show_result(image_list):
'''
To show the final image that already combine into one image
Parameters
----------
image_list : nparray
Array containing image data
'''
verified_imgs = []
unverified_imgs = []
white_img = np.zeros([250, 250, 3], dtype=np.uint8)
white_img.fill(255)
first_row_odd = []
second_row_even = []
indexs = 1
for img, ver in image_list:
if (indexs % 2) == 1:
first_row_odd.append(img)
else:
second_row_even.append(img)
indexs = indexs + 1
row2 = cv.hconcat(second_row_even)
row1 = cv.hconcat(first_row_odd)
result = cv.vconcat([row1, row2])
cv.imshow("MIB: International", result)
cv.waitKey(0)
cv.destroyAllWindows()
if __name__ == '__main__':
'''
Please modify train_root_path value according to the location of
your data train root directory
-------------------
Modifiable
-------------------
'''
train_root_path = 'dataset/train'
'''
-------------------
End of modifiable
-------------------
'''
train_names = get_path_list(train_root_path)
train_image_list, image_classes_list = get_class_id(train_root_path, train_names)
train_face_grays, _, filtered_classes_list = detect_faces_and_filter(train_image_list, image_classes_list)
# print(filtered_classes_list)
recognizer = train(train_face_grays, filtered_classes_list)
'''
Please modify train_root_path value according to the location of
your data train root directory
-------------------
Modifiable
-------------------
'''
test_root_path = 'dataset/test'
'''
-------------------
End of modifiable
-------------------
'''
test_image_list = get_test_images_data(test_root_path)
test_faces_gray, test_faces_rects, _ = detect_faces_and_filter(test_image_list)
predict_results = predict(recognizer, test_faces_gray)
predicted_test_image_list = draw_prediction_results(predict_results, test_image_list, test_faces_rects, train_names)
combine_and_show_result(predicted_test_image_list)
Here is my Result:
But in the first row of column 2, it’s recognize as Riza (Fake), the actual result must be recognize as Agent M, what can I do to hyperparameter tuning? any recommendation and what value should I used? thank you