From 1a0249c4ebd370138141a0bc96bc9cbce3d4d5d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9F=D0=B0=D1=80=D1=88=D0=B8=D0=BD=D0=B0=20=D0=95=D0=BA?= =?UTF-8?q?=D0=B0=D1=82=D0=B5=D1=80=D0=B8=D0=BD=D0=B0=20=D0=A1=D0=B5=D1=80?= =?UTF-8?q?=D0=B3=D0=B5=D0=B5=D0=B2=D0=BD=D0=B0?= <esparshina@miem.hse.ru> Date: Sat, 1 Feb 2025 20:16:03 +0000 Subject: [PATCH] Upload New File --- HW 4/Task3/task_3.ipynb | 398 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 398 insertions(+) create mode 100644 HW 4/Task3/task_3.ipynb diff --git a/HW 4/Task3/task_3.ipynb b/HW 4/Task3/task_3.ipynb new file mode 100644 index 0000000..209b961 --- /dev/null +++ b/HW 4/Task3/task_3.ipynb @@ -0,0 +1,398 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "7b42cfcb-38f0-425b-abc0-e7c27fe9e3af", + "metadata": {}, + "source": [ + "#Задание 3. Часть 2" + ] + }, + { + "cell_type": "markdown", + "id": "f53c99ca-93cd-4324-a643-69c0cbbb670d", + "metadata": {}, + "source": [ + "Необходимо собрать собственный набор данных РёР· **различных** изображений Вашего лица СЃ разных ракурсов, желательно настоящие фотографии РёР· личного архива (20 штук)\\\n", + "Возьмите эталонное изображение (как РІ паспорте) Рё РїСЂРё помощи библиотеки [DeepFace](https://github.com/serengil/deepface) проверьте его РЅР° соответствие всему датасету. Посчитайте метрику Precision. \\\n", + "\\\n", + "Примените каждую РёР· перечисленных ниже аугментаций (**РїРѕ-отдельности**) РєРѕ всему датасету Рё измерьте метрику Precision для измененнного датасета:\n", + "* РџРѕРІРѕСЂРѕС‚ изображения РЅР° 45В° Рё 90В°.\n", + "* Добавление шума (Gaussian Noise).\n", + "* Рзменение яркости (увеличение Рё уменьшение РЅР° 50%).\n", + "* Размытие СЃ различными параметрами.\n", + "\\\n", + "Реузультаты соберите РІ таблицу РІРёРґР°:\n", + "\n", + "Метод | Рсходный датасет | РџРѕРІРѕСЂРѕС‚ РЅР° 45В° | РџРѕРІРѕСЂРѕС‚ РЅР° 90В° | Рзображение СЃ шумом |\n", + "--- | ----|--- | --- | --- |\n", + "VGG-Face | 0 | 0 | 0 | 0 |\n", + "Facenet | 0 | 0 | 0 | 0 |\n", + "Facenet512 | 0 | 0 | 0 | 0 |\n", + "OpenFace | 0 | 0 | 0 | 0 |\n", + "DeepFace | 0 | 0 | 0 | 0 |\n", + "DeepID | 0 | 0 | 0 | 0 |\n", + "ArcFace | 0 | 0 | 0 | 0 |\n", + "Dlib | 0 | 0 | 0 | 0 |\n", + "SFace | 0 | 0 | 0 | 0 |\n", + "GhostFaceNet | 0 | 0 | 0 | 0 |" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "6d82b3d9-2e3c-4726-9bdb-72d340c29e5a", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-02-01 14:08:36.104207: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.\n", + "2025-02-01 14:08:36.113857: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:477] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n", + "WARNING: All log messages before absl::InitializeLog() is called are written to STDERR\n", + "E0000 00:00:1738408116.124793 227811 cuda_dnn.cc:8310] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n", + "E0000 00:00:1738408116.128118 227811 cuda_blas.cc:1418] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n", + "2025-02-01 14:08:36.139691: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", + "To enable the following instructions: AVX2 AVX_VNNI FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", + "W0000 00:00:1738408118.299641 227811 gpu_device.cc:2344] Cannot dlopen some GPU libraries. Please make sure the missing libraries mentioned above are installed properly if you would like to use GPU. Follow the guide at https://www.tensorflow.org/install/gpu for how to download and setup the required libraries for your platform.\n", + "Skipping registering GPU devices...\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Метод Рсходный набор РџРѕРІРѕСЂРѕС‚ РЅР° 45В° РџРѕРІРѕСЂРѕС‚ РЅР° 90В° \\\n", + "0 VGG-Face 0.60 0.05 0.00 \n", + "1 Facenet512 0.20 0.00 0.00 \n", + "2 OpenFace 0.00 0.00 0.00 \n", + "3 DeepID 0.15 0.05 0.05 \n", + "4 ArcFace 0.55 0.05 0.00 \n", + "5 Dlib 0.60 0.05 0.00 \n", + "6 SFace 0.45 0.05 0.00 \n", + "7 GhostFaceNet 0.50 0.05 0.00 \n", + "\n", + " Рзображение СЃ шумом Увеличенная яркость Уменьшенная яркость Размытие \n", + "0 0.05 0.55 0.65 0.60 \n", + "1 0.00 0.35 0.15 0.25 \n", + "2 0.00 0.00 0.00 0.05 \n", + "3 0.00 0.15 0.15 0.15 \n", + "4 0.00 0.55 0.65 0.60 \n", + "5 0.10 0.50 0.70 0.65 \n", + "6 0.00 0.45 0.60 0.50 \n", + "7 0.05 0.40 0.55 0.55 \n" + ] + } + ], + "source": [ + "import os\n", + "import cv2\n", + "import numpy as np\n", + "import pandas as pd\n", + "from deepface import DeepFace\n", + "from sklearn.metrics import recall_score\n", + "\n", + "image_dir = \"kate\"\n", + "reference_image_path = \"user.jpg\"\n", + "\n", + "models = ['VGG-Face', 'Facenet512', 'OpenFace', 'DeepID', 'ArcFace', 'Dlib', 'SFace', 'GhostFaceNet']\n", + "\n", + "def rotate_image(image, angle):\n", + " center = tuple(np.array(image.shape[1::-1]) / 2)\n", + " rot_mat = cv2.getRotationMatrix2D(center, angle, 1.0)\n", + " return cv2.warpAffine(image, rot_mat, image.shape[1::-1], flags=cv2.INTER_LINEAR)\n", + "\n", + "def add_noise(image):\n", + " noise = np.random.normal(loc=0, scale=25, size=image.shape)\n", + " noisy_image = cv2.add(image, noise.astype(np.uint8))\n", + " return np.clip(noisy_image, 0, 255)\n", + "\n", + "def change_brightness(image, factor):\n", + " return cv2.convertScaleAbs(image, alpha=factor, beta=0)\n", + "\n", + "def blur_image(image, kernel_size):\n", + " return cv2.GaussianBlur(image, (kernel_size, kernel_size), 0)\n", + "\n", + "def evaluate_images(reference_image, images, model_name):\n", + " matches = []\n", + " for i, img in enumerate(images):\n", + " try:\n", + " result = DeepFace.verify(reference_image, img, model_name=model_name, enforce_detection=False)\n", + " matches.append(result[\"verified\"])\n", + " except Exception as e:\n", + " print(f\"Ошибка СЃ изображением номер {i}: {e}\")\n", + " matches.append(False)\n", + " return matches\n", + "\n", + "reference_image = cv2.imread(reference_image_path)\n", + "\n", + "if reference_image is None:\n", + " raise ValueError(f\"РќРµ удалось загрузить эталонное изображение: {reference_image_path}\")\n", + "\n", + "images = []\n", + "for img_name in os.listdir(image_dir):\n", + " if img_name.endswith('.JPG') or img_name.endswith('.jpg'):\n", + " img_path = os.path.join(image_dir, img_name)\n", + " img = cv2.imread(img_path)\n", + " if img is not None:\n", + " images.append(img)\n", + " else:\n", + " print(f\"РќРµ удалось загрузить изображение: {img_path}\")\n", + "\n", + "if not images:\n", + " raise ValueError(\"РќРµ удалось загрузить изображения РёР· директории.\")\n", + "\n", + "results = []\n", + "\n", + "for model in models:\n", + " original_matches = evaluate_images(reference_image, images, model)\n", + " original_recall = recall_score([1]*len(original_matches), original_matches)\n", + " \n", + " rotated_45 = [rotate_image(img, 45) for img in images]\n", + " recall_45 = recall_score([1]*len(rotated_45), evaluate_images(reference_image, rotated_45, model))\n", + " \n", + " rotated_90 = [rotate_image(img, 90) for img in images]\n", + " recall_90 = recall_score([1]*len(rotated_90), evaluate_images(reference_image, rotated_90, model))\n", + " \n", + " noisy_images = [add_noise(img) for img in images]\n", + " recall_noise = recall_score([1]*len(noisy_images), evaluate_images(reference_image, noisy_images, model))\n", + " \n", + " bright_images_up = [change_brightness(img, 1.5) for img in images]\n", + " recall_bright_up = recall_score([1]*len(bright_images_up), evaluate_images(reference_image, bright_images_up, model))\n", + " \n", + " bright_images_down = [change_brightness(img, 0.5) for img in images]\n", + " recall_bright_down = recall_score([1]*len(bright_images_down), evaluate_images(reference_image, bright_images_down, model))\n", + " \n", + " blurred_images = [blur_image(img, 5) for img in images]\n", + " recall_blur = recall_score([1]*len(blurred_images), evaluate_images(reference_image, blurred_images, model))\n", + " \n", + " results.append([\n", + " model,\n", + " original_recall,\n", + " recall_45, \n", + " recall_90,\n", + " recall_noise,\n", + " recall_bright_up,\n", + " recall_bright_down,\n", + " recall_blur\n", + " ])\n", + "\n", + "df_results = pd.DataFrame(\n", + " results, \n", + " columns=[\n", + " 'Метод', \n", + " 'Рсходный набор', \n", + " 'РџРѕРІРѕСЂРѕС‚ РЅР° 45В°', \n", + " 'РџРѕРІРѕСЂРѕС‚ РЅР° 90В°', \n", + " 'Рзображение СЃ шумом',\n", + " 'Увеличенная яркость',\n", + " 'Уменьшенная яркость',\n", + " 'Размытие'\n", + " ]\n", + ")\n", + "print(df_results)" + ] + }, + { + "cell_type": "markdown", + "id": "4d4e15a8-aa3c-454a-8aba-c65a29bda5ec", + "metadata": {}, + "source": [ + "#Задание 3. Часть 2" + ] + }, + { + "cell_type": "markdown", + "id": "1e002360-3c96-4393-8cc1-e5e68bedcb8b", + "metadata": {}, + "source": [ + "Р’ данном задании предлагается рассмотреть задачу распознавания лиц как задачу классификации для оценки точности.\n", + "Вам даны [видео](https://drive.google.com/drive/folders/1z_YCdJF2Rf9WzlNSY3BpNFiakNisq5VB?usp=sharing), для которых представлена разметка РІ РІРёРґРµ тайм-РєРѕРґРѕРІ Рё база фотографий людей СЃ этих видео.\n", + "Необходимо взять каждый 50-Р№ кадр видео (СЃРїРѕСЃРѕР± разбиения РЅР° кадры СЃ учётом разметки - РЅР° ваше усмотрение) Рё для полученного набора изображений оценить метрику Precision РЅР° данном наборе изображений для всех лиц, присутствующих РЅР° видео Рё РІ разметке.\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "3b20127c-94a4-41b9-9971-66f92346ca32", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2025-02-01 09:08:30.181388: I tensorflow/core/util/port.cc:153] oneDNN custom operations are on. You may see slightly different numerical results due to floating-point round-off errors from different computation orders. To turn them off, set the environment variable `TF_ENABLE_ONEDNN_OPTS=0`.\n", + "2025-02-01 09:08:30.191264: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:477] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered\n", + "WARNING: All log messages before absl::InitializeLog() is called are written to STDERR\n", + "E0000 00:00:1738390110.202245 179413 cuda_dnn.cc:8310] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered\n", + "E0000 00:00:1738390110.205594 179413 cuda_blas.cc:1418] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered\n", + "2025-02-01 09:08:30.217277: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.\n", + "To enable the following instructions: AVX2 AVX_VNNI FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.\n", + "W0000 00:00:1738390111.407309 179413 gpu_device.cc:2344] Cannot dlopen some GPU libraries. Please make sure the missing libraries mentioned above are installed properly if you would like to use GPU. Follow the guide at https://www.tensorflow.org/install/gpu for how to download and setup the required libraries for your platform.\n", + "Skipping registering GPU devices...\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Видео: palmasizade_video.mp4, Recall: 0.1489\n", + "Средний Recall для всех видео: 0.1489\n" + ] + } + ], + "source": [ + "import os\n", + "import cv2\n", + "import pandas as pd\n", + "from deepface import DeepFace\n", + "\n", + "def time_to_frame(time_str, fps):\n", + " \"\"\"Преобразует строку времени формата 'HH:MM:SS' РІ номер кадра.\"\"\"\n", + " time_parts = time_str.split(':')\n", + " if len(time_parts) == 3:\n", + " hours, minutes, seconds = map(float, time_parts)\n", + " else:\n", + " raise ValueError(\"Формат времени должен быть 'HH:MM:SS'\")\n", + " \n", + " total_seconds = hours * 3600 + minutes * 60 + seconds\n", + " return int(total_seconds * fps)\n", + "\n", + "def get_labeled_persons_for_frame(labels, frame_number):\n", + " \"\"\"Возвращает СЃРїРёСЃРѕРє лиц, присутствующих РЅР° данном фрейме, РёСЃС…РѕРґСЏ РёР· разметки.\"\"\"\n", + " for start, end, persons in labels:\n", + " if start <= frame_number <= end:\n", + " return persons\n", + " return []\n", + "\n", + "def extract_labels(df, fps):\n", + " \"\"\"Рзвлекает Рё преобразует метки РёР· CSV-файла РІ формат, пригодный для РїРѕРёСЃРєР° лиц.\"\"\"\n", + " labels = [\n", + " (time_to_frame(row['from'], fps), time_to_frame(row['to'], fps), row['persons'].replace(',', ' ').split())\n", + " for _, row in df.iterrows()\n", + " ]\n", + " return labels\n", + "\n", + "def match_verified(frame, person_photos_path):\n", + " \"\"\"Проверяет, есть ли РІ текущем кадре изображение указанного человека.\"\"\"\n", + " if not os.path.exists(person_photos_path):\n", + " return False\n", + "\n", + " for filename in os.listdir(person_photos_path):\n", + " image_path = os.path.join(person_photos_path, filename)\n", + " try:\n", + " result = DeepFace.verify(image_path, frame, enforce_detection=False)\n", + " if result['verified']:\n", + " return True\n", + " except Exception:\n", + " continue\n", + "\n", + " return False\n", + "\n", + "def evaluate_frame(frame, frame_number, labels, photos_dir):\n", + " \"\"\"Оценивает текущий кадр для всех меток Рё возвращает количество верных Рё неверных сопоставлений.\"\"\"\n", + " labeled_persons = get_labeled_persons_for_frame(labels, frame_number)\n", + " tp, fn = 0, 0\n", + "\n", + " for person in labeled_persons:\n", + " person_photos_path = os.path.join(photos_dir, person)\n", + " if match_verified(frame, person_photos_path):\n", + " tp += 1\n", + " else:\n", + " fn += 1\n", + "\n", + " return tp, fn\n", + "\n", + "def process_video(video_path, labels_path, photos_dir):\n", + " \"\"\"Обрабатывает видео, возвращая количество истинных Рё ложных совпадений.\"\"\"\n", + " cap = cv2.VideoCapture(video_path)\n", + " df = pd.read_csv(labels_path)\n", + " fps = cap.get(cv2.CAP_PROP_FPS)\n", + "\n", + " labels = extract_labels(df, fps)\n", + " tp_total, fn_total = 0, 0\n", + " total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))\n", + " frame_number = 0\n", + "\n", + " while frame_number < total_frames:\n", + " ret, frame = cap.read()\n", + " if not ret:\n", + " break\n", + "\n", + " tp, fn = evaluate_frame(frame, frame_number, labels, photos_dir)\n", + " tp_total += tp\n", + " fn_total += fn\n", + "\n", + " frame_number += 50\n", + " cap.set(cv2.CAP_PROP_POS_FRAMES, frame_number)\n", + "\n", + " cap.release()\n", + " return tp_total, fn_total\n", + "\n", + "def calculate_recall(tp, fn):\n", + " return tp / (tp + fn) if (tp + fn) > 0 else 0\n", + "\n", + "def main(videos_dir, labels_dir, photos_dir):\n", + " overall_recalls = []\n", + "\n", + " for video_filename in os.listdir(videos_dir):\n", + " if not video_filename.lower().endswith('.mp4'):\n", + " continue\n", + "\n", + " video_path = os.path.join(videos_dir, video_filename)\n", + " labels_path = os.path.join(labels_dir, os.path.splitext(video_filename)[0] + \".csv\")\n", + "\n", + " tp, fn = process_video(video_path, labels_path, photos_dir)\n", + " recall = calculate_recall(tp, fn)\n", + " \n", + " overall_recalls.append(recall)\n", + " print(f\"Видео: {video_filename}, Recall: {recall:.4f}\")\n", + "\n", + " if overall_recalls:\n", + " average_recall = sum(overall_recalls) / len(overall_recalls)\n", + " print(f\"Средний Recall для всех видео: {average_recall:.4f}\")\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "\n", + "videos_dir = \"task3/videos\"\n", + "labels_dir = \"task3/labels\"\n", + "photos_dir = \"task3/photos\"\n", + "main(videos_dir, labels_dir, photos_dir)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3d113f6f-697c-4e69-9680-88e2b568c68a", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python un", + "language": "python", + "name": "un" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.16" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} -- GitLab