Artificial Intelligence 19 min read

Face Recognition with Dlib and OpenCV in Python: Building a Feature Dataset and Real‑Time Matching

This tutorial explains how to use Dlib and OpenCV in Python to capture face images, extract 128‑dimensional descriptors, store average features in CSV files, and perform real‑time face recognition by comparing Euclidean distances against a known dataset.

Python Programming Learning Circle
Python Programming Learning Circle
Python Programming Learning Circle
Face Recognition with Dlib and OpenCV in Python: Building a Feature Dataset and Real‑Time Matching

Libraries used: dlib and OpenCV with Python 3.8 in a Jupyter Notebook (Anaconda3) environment.

1. Dlib Face Feature Detection Principle

Extract facial landmarks (see image).

Capture multiple images, compute a feature dataset and average feature vector, store them in a CSV file, and compare Euclidean distances between the live face and the stored averages to identify the closest match.

1. Build Face Feature Dataset

1. Install Dlib

Refer to the official installation guide.

2. Build Your Own Dataset

2.1 Capture Face Images

Capture 20 face images of size 256×256 from a video stream and save them as the training set.

The image size can be adjusted; larger images improve accuracy but increase training time.
<code>import cv2
import dlib
import os
import sys
import random
# storage path
output_dir = 'D:/No1WorkSpace/JupyterNotebook/Facetrainset/Num&Name'  # number+name
size = 256  # image side length

if not os.path.exists(output_dir):
    os.makedirs(output_dir)

# adjust brightness and contrast
def relight(img, light=1, bias=0):
    w = img.shape[1]
    h = img.shape[0]
    for i in range(0, w):
        for j in range(0, h):
            for c in range(3):
                tmp = int(img[j, i, c] * light + bias)
                if tmp > 255:
                    tmp = 255
                elif tmp < 0:
                    tmp = 0
                img[j, i, c] = tmp
    return img

# use dlib's frontal_face_detector
detector = dlib.get_frontal_face_detector()
# open camera (0 for default)
camera = cv2.VideoCapture(0)
index = 1
while True:
    if index <= 20:
        print('Being processed picture %s' % index)
        success, img = camera.read()
        gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        dets = detector(gray_img, 1)
        for i, d in enumerate(dets):
            x1 = d.top() if d.top() > 0 else 0
            y1 = d.bottom() if d.bottom() > 0 else 0
            x2 = d.left() if d.left() > 0 else 0
            y2 = d.right() if d.right() > 0 else 0
            face = img[x1:y1, x2:y2]
            face = relight(face, random.uniform(0.5, 1.5), random.randint(-50, 50))
            face = cv2.resize(face, (size, size))
            cv2.imshow('image', face)
            cv2.imwrite(output_dir + '/' + str(index) + '.jpg', face)
            index += 1
        key = cv2.waitKey(30) & 0xff
        if key == 27:
            break
    else:
        print('Finished!')
        camera.release()
        cv2.destroyAllWindows()
        break
</code>

Resulting capture screenshots are shown below.

2.2 Analyze Each Face's Feature Values and Save to CSV

Extract 128‑D face descriptors for each image, compute the mean vector for each person, and write the results to a CSV file.

<code># extract 128‑D features from images and save into CSV
from cv2 import cv2 as cv2
import os
import dlib
from skimage import io
import csv
import numpy as np

path_images_from_camera = "D:/No1WorkSpace/JupyterNotebook/Facetrainset/"

detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("D:/No1WorkSpace/JupyterNotebook/model/shape_predictor_68_face_landmarks.dat")
face_rec = dlib.face_recognition_model_v1("D:/No1WorkSpace/JupyterNotebook/model/dlib_face_recognition_resnet_model_v1.dat")

def return_128d_features(path_img):
    img_rd = io.imread(path_img)
    img_gray = cv2.cvtColor(img_rd, cv2.COLOR_BGR2RGB)
    faces = detector(img_gray, 1)
    print("%-40s %-20s" % ("Detected image with faces:", path_img))
    if len(faces) != 0:
        shape = predictor(img_gray, faces[0])
        face_descriptor = face_rec.compute_face_descriptor(img_gray, shape)
    else:
        face_descriptor = 0
        print("no face")
    return face_descriptor

def return_features_mean_personX(path_faces_personX):
    features_list_personX = []
    photos_list = os.listdir(path_faces_personX)
    if photos_list:
        for i in range(len(photos_list)):
            with open("D:/No1WorkSpace/JupyterNotebook/feature/featuresGiao" + str(i) + ".csv", "w", newline="") as csvfile:
                writer = csv.writer(csvfile)
                print("%-40s %-20s" % ("Reading image:", path_faces_personX + "/" + photos_list[i]))
                features_128d = return_128d_features(path_faces_personX + "/" + photos_list[i])
                print(features_128d)
                writer.writerow(features_128d)
                if features_128d == 0:
                    i += 1
                else:
                    features_list_personX.append(features_128d)
    else:
        print("Warning: No images in " + path_faces_personX + '/', '\n')
    if features_list_personX:
        features_mean_personX = np.array(features_list_personX).mean(axis=0)
    else:
        features_mean_personX = '0'
    return features_mean_personX

people = os.listdir(path_images_from_camera)
people.sort()
with open("D:/No1WorkSpace/JupyterNotebook/feature/features_all.csv", "w", newline="") as csvfile:
    writer = csv.writer(csvfile)
    for person in people:
        print("##### " + person + " #####")
        features_mean_personX = return_features_mean_personX(path_images_from_camera + person)
        writer.writerow(features_mean_personX)
        print("The mean of features:", list(features_mean_personX))
        print('\n')
    print("All face data saved to: D:/myworkspace/JupyterNotebook/People/feature/features_all2.csv")
</code>

2. Recognize Faces and Match Dataset

1. Principle

Identify a face by computing the Euclidean distance between its 128‑D descriptor and the stored mean vectors; the smallest distance indicates the best match.

2. Real‑Time Face Recognition from Video Stream

The script below opens the default camera, detects faces, extracts descriptors, compares them with the CSV database, and displays the recognized name on the video feed.

<code># real‑time face recognition
import os
import dlib          # face processing library
import csv           # for writing to CSV
import time
import sys
import numpy as np   # data processing
from cv2 import cv2 as cv2   # image processing
import pandas as pd   # data handling

# face recognition model (128‑D vectors)
facerec = dlib.face_recognition_model_v1("D:/No1WorkSpace/JupyterNotebook/model/dlib_face_recognition_resnet_model_v1.dat")

def return_euclidean_distance(feature_1, feature_2):
    feature_1 = np.array(feature_1)
    feature_2 = np.array(feature_2)
    dist = np.sqrt(np.sum(np.square(feature_1 - feature_2)))
    return dist

# load known features from CSV
path_features_known_csv = "D:/No1WorkSpace/JupyterNotebook/feature/features_all.csv"
csv_rd = pd.read_csv(path_features_known_csv, header=None)
features_known_arr = []
for i in range(csv_rd.shape[0]):
    features_someone_arr = []
    for j in range(0, len(csv_rd.loc[i, :])):
        features_someone_arr.append(csv_rd.loc[i, :][j])
    features_known_arr.append(features_someone_arr)
print("Faces in Database:", len(features_known_arr))

# Dlib detector and predictor
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('D:/No1WorkSpace/JupyterNotebook/model/shape_predictor_68_face_landmarks.dat')

cap = cv2.VideoCapture(0)
cap.set(3, 480)
while cap.isOpened():
    flag, img_rd = cap.read()
    kk = cv2.waitKey(1)
    img_gray = cv2.cvtColor(img_rd, cv2.COLOR_RGB2GRAY)
    faces = detector(img_gray, 0)
    font = cv2.FONT_HERSHEY_COMPLEX
    pos_namelist = []
    name_namelist = []
    if kk == ord('q'):
        break
    if len(faces) != 0:
        features_cap_arr = []
        for i, d in enumerate(faces):
            shape = predictor(img_rd, d)
            features_cap_arr.append(facerec.compute_face_descriptor(img_rd, shape))
        for k in range(len(faces)):
            name_namelist.append("unknown")
            pos_namelist.append(tuple([faces[k].left(), int(faces[k].bottom() + (faces[k].bottom() - faces[k].top())/4)]))
            e_distance_list = []
            for i in range(len(features_known_arr)):
                if str(features_known_arr[i][0]) != '0.0':
                    e_distance_tmp = return_euclidean_distance(features_cap_arr[k], features_known_arr[i])
                    e_distance_list.append(e_distance_tmp)
                else:
                    e_distance_list.append(999999999)
            similar_person_num = e_distance_list.index(min(e_distance_list))
            if min(e_distance_list) < 0.4:
                folder_name = 'D:/No1WorkSpace/JupyterNotebook/Facetrainset/'
                sum = similar_person_num + 1
                key_id = 1
                file_names = os.listdir(folder_name)
                for name in file_names:
                    if sum == key_id:
                        name_namelist[k] = name[1:]
                    key_id += 1
                # save recognized face image
                x1 = faces[k].top() if faces[k].top() > 0 else 0
                y1 = faces[k].bottom() if faces[k].bottom() > 0 else 0
                x2 = faces[k].left() if faces[k].left() > 0 else 0
                y2 = faces[k].right() if faces[k].right() > 0 else 0
                face = img_rd[x1:y1, x2:y2]
                face = cv2.resize(face, (64, 64))
                now_time = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
                save_path = "D:/No1WorkSpace/JupyterNotebook/KnownFacetrainset/" + now_time + name_namelist[k] + '.jpg'
                cv2.imwrite(save_path, face)
                print('New save:', save_path)
            else:
                # unknown person handling
                x1 = faces[k].top() if faces[k].top() > 0 else 0
                y1 = faces[k].bottom() if faces[k].bottom() > 0 else 0
                x2 = faces[k].left() if faces[k].left() > 0 else 0
                y2 = faces[k].right() if faces[k].right() > 0 else 0
                face = img_rd[x1:y1, x2:y2]
                face = cv2.resize(face, (64, 64))
                now_time = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime())
                save_path = "D:/No1WorkSpace/JupyterNotebook/UnKnownFacetrainset/" + now_time + 'unknown.jpg'
                cv2.imwrite(save_path, face)
                print('New unknown save:', save_path)
            # draw rectangle and name
            for d in faces:
                cv2.rectangle(img_rd, (d.left(), d.top()), (d.right(), d.bottom()), (0, 255, 255), 2)
            for i in range(len(faces)):
                cv2.putText(img_rd, name_namelist[i], pos_namelist[i], font, 0.8, (0, 255, 255), 1, cv2.LINE_AA)
    cv2.putText(img_rd, "Face Recognition", (20, 40), font, 1, (0, 0, 255), 1, cv2.LINE_AA)
    cv2.putText(img_rd, "Visitors: " + str(len(faces)), (20, 100), font, 1, (0, 0, 255), 1, cv2.LINE_AA)
    cv2.imshow("camera", img_rd)
cap.release()
cv2.destroyAllWindows()
</code>
Note: Using non‑ASCII (e.g., Chinese) directory names may cause garbled characters.

Sample output screenshots are shown below.

Original article: https://blog.csdn.net/ChenJ_1012/article/details/121323101

Machine LearningPythonFace RecognitionCSVopencvdlibEuclidean distance
Python Programming Learning Circle
Written by

Python Programming Learning Circle

A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.