Jupyter Notebook / Python · декември 8, 2023

Лицево разпознаване с коефициенти на корелация и евклидово разстояние

Целта на този проект е въз основа на снимки на човек, които имаме и знаем, че са негови, да установим нови тестови снимки дали са на същия човек или не.

Разпознаването на лица има редица приложения. Например идентифициране на извършител на престъпление по база данни със снимкии и проверка в приложения с разпознаване на лица. Отключване на устройства с лицево разпознаване и много други приложения.


Целта на този проект е въз основа на снимки на човек, които имаме и знаем, че са негови, да установим нови тестови снимки дали са на същия човек или не.

Ще сравним изображенията по корелационен коефициент, както и по евклидово разстояние. Представяйки техните резултати, ще разберем кой метод дава правилни резултати. След това ще сравним ефективността на двата метода, като я изобразим на графика и след това я измерим.

За целта на проекта ще използваме снимки на известни актьори. Лицето, което ще разознаваме е на Джейсън Стейтъм, като за целта усредняваме няколко негоси снимки.

# Create a list of file names in the images folder
files = os.listdir('images-nobkg')

# Load the first image and determine the size of the matrix to store the sum of the images
img = Image.open('images-nobkg/'+files[0]).convert('L')
img_arr = np.array(img, dtype=float)
img_sum = np.zeros_like(img_arr, dtype=float)

# Adding all images to the sum and turning them into NumPy arrays
for file in files[1:]:
     img = Image.open('images-nobkg/'+file).convert('L')
     img_arr = np.array(img, dtype=float)
     img_sum += img_arr

# Calculate the averaged image
avg_img = img_sum / len(files)

# Rescale the image to the range [0, 255] and convert to a NumPy array
avg_img = np.uint8(avg_img / np.max(avg_img) * 255)

По този начин получаваме неговоро усреднено изображение, което ще сравним с тестовите изображения.

Като тестови изображения използваме 4 снимки на същия актьор и по една на Уил Смит, Киано Рийвс, Джеки Чан, както и една моя снимка.

Евклидово разстояние

В математиката евклидовото разстояние между две точки в евклидовото пространство е дължината на отсечка между двете точки. Може да се изчисли от декартовите координати на точките с помощта на Питагоровата теорема. По този начин изчисляваме разстоянията на тестовите изображения, спрямо усредненото.

distances = {
    'test_01_js': np.linalg.norm(avg_img.flatten() - test_01_js.flatten()),
    'test_02_js': np.linalg.norm(avg_img.flatten() - test_02_js.flatten()),
    'test_03_js': np.linalg.norm(avg_img.flatten() - test_03_js.flatten()),
    'test_04_js': np.linalg.norm(avg_img.flatten() - test_04_js.flatten()),
    'test_05_ws': np.linalg.norm(avg_img.flatten() - test_05_ws.flatten()),
    'test_06_kr': np.linalg.norm(avg_img.flatten() - test_06_kr.flatten()),
    'test_07_jc': np.linalg.norm(avg_img.flatten() - test_07_jc.flatten()),
    'test_08_ip': np.linalg.norm(avg_img.flatten() - test_08_ip.flatten())
}

# Print the results
for test, distance in distances.items():
    print(f"{test}: {distance:.2f}")

Получаваме следният резултат:

  • test_01_js: 28681.32
  • test_02_js: 32720.78
  • test_03_js: 30015.33
  • test_04_js: 26996.64
  • test_05_ws: 21428.31
  • test_06_kr: 23341.63
  • test_07_jc: 25081.12
  • test_08_ip: 24237.01

Когато разгледам резултатите графично виждаме, че изображенията, в които фигурира Джейсън Стейтъм са в различен диапазон по вертикалата, което означава, че методът с Евклидово пространство дава правилни резултати.

Коефициент на корелация

Коефициент на корелация на Пиърсън е може би най-широко използваната мярка за линейни връзки между две нормално разпределени променливи и затова често се нарича просто „коефициент на корелация“

correlations = {
    'test_01_js': np.corrcoef(avg_img.flatten(), test_01_js.flatten())[0][1],
    'test_02_js': np.corrcoef(avg_img.flatten(), test_02_js.flatten())[0][1],
    'test_03_js': np.corrcoef(avg_img.flatten(), test_03_js.flatten())[0][1],
    'test_04_js': np.corrcoef(avg_img.flatten(), test_04_js.flatten())[0][1],
    'test_05_ws': np.corrcoef(avg_img.flatten(), test_05_ws.flatten())[0][1],
    'test_06_kr': np.corrcoef(avg_img.flatten(), test_06_kr.flatten())[0][1],
    'test_07_jc': np.corrcoef(avg_img.flatten(), test_07_jc.flatten())[0][1],
    'test_08_ip': np.corrcoef(avg_img.flatten(), test_08_ip.flatten())[0][1]
}

for test, correlation in correlations.items():
    print(f"{test}: {correlation}")

Резултатите, които получаваме са

  • test_01_js: 0.730313023186747
  • test_02_js: 0.6826169366400802
  • test_03_js: 0.6568069866470114
  • test_04_js: 0.690489963965318
  • test_05_ws: 0.6064701537272597
  • test_06_kr: 0.5430505551519634
  • test_07_jc: 0.5177718611581393
  • test_08_ip: 0.5419241830669719

Виждаме, че тук също се оформят две групи, които заемат различни диапазони по вертикала. Това означава, че методът с коефициенти на корелация, също е успешен.

Сравнение на двата метода

След като стигнахме до заключение, че двата метода работят правилно за нашата цел, следва да уточним кой от тях работи по-точно.

Когато плотнем резултатите от двата метода в boxplot можем да сравним визуално разстоянието, между зоните, които се оформят. Виждаме, че при коефициента на корелация има по-голяма дистанция между тях.

За да изчислим тази рзстоянието между двата метода ще приемем, че разликата, между максималната и минималната стойност на двата метода е 100%, за да изчислим какъв е диапазона, между разпознатите и неразпознатите изображения.

distances_range = max_distances_js - min_distances_not_js
distances_difference = min_distances_js - max_distances_not_js
distances_difference_percent = distances_difference / distances_range

correlations_range = max_correlations_js - min_correlations_not_js
correlations_difference = min_correlations_js - max_correlations_not_js
correlations_difference_percent = correlations_difference / correlations_range

print(f"At the Euclidean distance we get a difference {distances_difference_percent * 100:.2f}%")
print(f"In Correlation coefficients we get a difference {correlations_difference_percent * 100 :.2f}%")
print(f"The difference between them is {(correlations_difference_percent - distances_difference_percent) * 100 :.2f}% more in favor of the Correlation coefficients")

При Евклидовото разстояние получаваме дистанция от 16.96%

При Корелационния коефициент получаваме дистанция от 23.68%

Разликата между дистанциите е 6.72% в полза на коефициента на корелация. Това ни позволява да стигнем до заключение, че той е по-ефективният метод.

Подробният код на това изследване може да видите ТУК.