|
| 1 | +{ |
| 2 | + "cells": [ |
| 3 | + { |
| 4 | + "cell_type": "markdown", |
| 5 | + "id": "759f9ec0", |
| 6 | + "metadata": {}, |
| 7 | + "source": [ |
| 8 | + "# Face Samples" |
| 9 | + ] |
| 10 | + }, |
| 11 | + { |
| 12 | + "cell_type": "markdown", |
| 13 | + "id": "61534b8b", |
| 14 | + "metadata": {}, |
| 15 | + "source": [ |
| 16 | + "## Objective\n", |
| 17 | + "\n", |
| 18 | + " This script builds a Person Directory by enrolling multiple faces for each person from a directory where each subfolder represents a different person. It creates a person for each subfolder and adds all face images within that subfolder to the created person.\n", |
| 19 | + "\n", |
| 20 | + " \n" |
| 21 | + ] |
| 22 | + }, |
| 23 | + { |
| 24 | + "cell_type": "markdown", |
| 25 | + "id": "80a375ca", |
| 26 | + "metadata": {}, |
| 27 | + "source": [ |
| 28 | + "## Create Azure content understanding face client\n", |
| 29 | + ">The [AzureContentUnderstandingFaceClient](../../python/content_understanding_face_client.py) is utility Class which contain the functions to interact with the Content Understanding face server. Before Content Understanding SDK release, we can regard it as a lightweight SDK. Fill the constant **AZURE_AI_ENDPOINT**, **AZURE_AI_API_VERSION**, **AZURE_AI_API_KEY** with the information from your Azure AI Service." |
| 30 | + ] |
| 31 | + }, |
| 32 | + { |
| 33 | + "cell_type": "code", |
| 34 | + "execution_count": null, |
| 35 | + "id": "a5b1fa11", |
| 36 | + "metadata": {}, |
| 37 | + "outputs": [], |
| 38 | + "source": [ |
| 39 | + "import logging\n", |
| 40 | + "import os\n", |
| 41 | + "import sys\n", |
| 42 | + "from pathlib import Path\n", |
| 43 | + "from dotenv import find_dotenv, load_dotenv\n", |
| 44 | + "from azure.identity import DefaultAzureCredential, get_bearer_token_provider\n", |
| 45 | + "\n", |
| 46 | + "# import utility package from python samples root directory\n", |
| 47 | + "parent_dir = Path(Path.cwd()).parent.parent\n", |
| 48 | + "sys.path.append(str(parent_dir))\n", |
| 49 | + "from python.content_understanding_face_client import AzureContentUnderstandingFaceClient\n", |
| 50 | + "\n", |
| 51 | + "load_dotenv(find_dotenv())\n", |
| 52 | + "logging.basicConfig(level=logging.INFO)\n", |
| 53 | + "\n", |
| 54 | + "credential = DefaultAzureCredential()\n", |
| 55 | + "token_provider = get_bearer_token_provider(credential, \"https://cognitiveservices.azure.com/.default\")\n", |
| 56 | + "\n", |
| 57 | + "client = AzureContentUnderstandingFaceClient(\n", |
| 58 | + " endpoint=os.getenv(\"AZURE_AI_ENDPOINT\"),\n", |
| 59 | + " api_version=os.getenv(\"AZURE_AI_API_VERSION\", \"2025-05-01-preview\"),\n", |
| 60 | + " token_provider=token_provider,\n", |
| 61 | + " x_ms_useragent=\"azure-ai-content-understanding-python/build_person_directory\", # This header is used for sample usage telemetry, please comment out this line if you want to opt out.\n", |
| 62 | + ")" |
| 63 | + ] |
| 64 | + }, |
| 65 | + { |
| 66 | + "cell_type": "markdown", |
| 67 | + "id": "c76fa3c2", |
| 68 | + "metadata": {}, |
| 69 | + "source": [ |
| 70 | + "## Build a Person Directory" |
| 71 | + ] |
| 72 | + }, |
| 73 | + { |
| 74 | + "cell_type": "code", |
| 75 | + "execution_count": null, |
| 76 | + "id": "821406a6", |
| 77 | + "metadata": {}, |
| 78 | + "outputs": [], |
| 79 | + "source": [ |
| 80 | + "import os\n", |
| 81 | + "folder_path = \"path_to_your_folder\" # Replace with the path to your folder containing subfolders of images\n", |
| 82 | + "\n", |
| 83 | + "# Create a person directory\n", |
| 84 | + "person_directory_id = \"person_directory_id\"\n", |
| 85 | + "client.create_person_directory(person_directory_id)\n", |
| 86 | + "\n", |
| 87 | + "person_ids = []\n", |
| 88 | + "# Iterate through all subfolders in the folder_path\n", |
| 89 | + "for subfolder_name in os.listdir(folder_path):\n", |
| 90 | + " subfolder_path = os.path.join(folder_path, subfolder_name)\n", |
| 91 | + " if os.path.isdir(subfolder_path):\n", |
| 92 | + " person_name = subfolder_name\n", |
| 93 | + " # Add a person for each subfolder\n", |
| 94 | + " person = client.add_person(person_directory_id, tags={\"name\": person_name})\n", |
| 95 | + " print(f\"Created person {person_name} with person_id: {person['personId']}\")\n", |
| 96 | + " if person:\n", |
| 97 | + " person_ids.append(person['personId'])\n", |
| 98 | + " # Iterate through all images in the subfolder\n", |
| 99 | + " for filename in os.listdir(subfolder_path):\n", |
| 100 | + " if filename.lower().endswith(('.png', '.jpg', '.jpeg')):\n", |
| 101 | + " image_path = os.path.join(subfolder_path, filename)\n", |
| 102 | + " # Convert image to base64\n", |
| 103 | + " image_data = AzureContentUnderstandingFaceClient.read_file_to_base64(image_path)\n", |
| 104 | + " # Add a face to the Person Directory and associate it to the added person\n", |
| 105 | + " face = client.add_face(person_directory_id, image_data, person['personId'])\n", |
| 106 | + " if face:\n", |
| 107 | + " print(f\"Added face from {filename} with face_id: {face['faceId']} to person_id: {person['personId']}\")\n", |
| 108 | + " else:\n", |
| 109 | + " print(f\"Failed to add face from {filename} to person_id: {person['personId']}\")\n", |
| 110 | + "\n", |
| 111 | + "# Output the person IDs created\n", |
| 112 | + "print(f\"Person IDs: {person_ids}\")\n", |
| 113 | + "\n", |
| 114 | + "print(\"Done\")" |
| 115 | + ] |
| 116 | + }, |
| 117 | + { |
| 118 | + "cell_type": "markdown", |
| 119 | + "id": "de736d94", |
| 120 | + "metadata": {}, |
| 121 | + "source": [ |
| 122 | + "### Adding and associating a new face\n", |
| 123 | + "You can add an additional face to a Person Directory and associate it with an already enrolled person." |
| 124 | + ] |
| 125 | + }, |
| 126 | + { |
| 127 | + "cell_type": "code", |
| 128 | + "execution_count": null, |
| 129 | + "id": "19fe3aff", |
| 130 | + "metadata": {}, |
| 131 | + "outputs": [], |
| 132 | + "source": [ |
| 133 | + "new_face_image_path = \"new_face_image_path\" # The path to the face image you want to add.\n", |
| 134 | + "existing_person_id = \"existing_person_id\" # The unique ID of the person to whom the face should be associated.\n", |
| 135 | + "\n", |
| 136 | + "# Convert the new face image to base64\n", |
| 137 | + "image_data = AzureContentUnderstandingFaceClient.read_file_to_base64(new_face_image_path)\n", |
| 138 | + "# Add the new face to the person directory and associate it with the existing person\n", |
| 139 | + "face_id = client.add_face(person_directory_id, image_data, person['personId'])\n", |
| 140 | + "if face_id:\n", |
| 141 | + " print(f\"Added face from {new_face_image_path} with face_id: {face_id} to person_id: {existing_person_id}\")\n", |
| 142 | + "else:\n", |
| 143 | + " print(f\"Failed to add face from {new_face_image_path} to person_id: {existing_person_id}\")" |
| 144 | + ] |
| 145 | + }, |
| 146 | + { |
| 147 | + "cell_type": "markdown", |
| 148 | + "id": "65b0cafa", |
| 149 | + "metadata": {}, |
| 150 | + "source": [ |
| 151 | + "### Associating a list of already enrolled faces\n", |
| 152 | + "\n", |
| 153 | + "You can associate a list of already enrolled faces in the Person Directory with their respective persons. This can be useful when you have existing face IDs and want to associate them to specific persons in the directory." |
| 154 | + ] |
| 155 | + }, |
| 156 | + { |
| 157 | + "cell_type": "code", |
| 158 | + "execution_count": null, |
| 159 | + "id": "af5de3d5", |
| 160 | + "metadata": {}, |
| 161 | + "outputs": [], |
| 162 | + "source": [ |
| 163 | + "existing_person_id = \"existing_person_id\" # The unique ID of the person to whom the face should be associated.\n", |
| 164 | + "existing_face_id_list = [\"existing_face_id_1\", \"existing_face_id_2\"] # The list of face IDs to be associated.\n", |
| 165 | + "\n", |
| 166 | + "# Associate the existing face IDs with the existing person\n", |
| 167 | + "client.update_person(person_directory_id, existing_person_id, face_ids=existing_face_id_list)" |
| 168 | + ] |
| 169 | + }, |
| 170 | + { |
| 171 | + "cell_type": "markdown", |
| 172 | + "id": "873574f7", |
| 173 | + "metadata": {}, |
| 174 | + "source": [ |
| 175 | + "### Associating and disassociating a face from a person\n", |
| 176 | + "You can associate or disassociate a face from a person in the Person Directory. Associating a face links it to a specific person, while disassociating removes this link." |
| 177 | + ] |
| 178 | + }, |
| 179 | + { |
| 180 | + "cell_type": "code", |
| 181 | + "execution_count": null, |
| 182 | + "id": "03e5f0eb", |
| 183 | + "metadata": {}, |
| 184 | + "outputs": [], |
| 185 | + "source": [ |
| 186 | + "existing_face_id = \"existing_face_id\" # The unique ID of the face.\n", |
| 187 | + "\n", |
| 188 | + "# Remove the association of the existing face ID from the person\n", |
| 189 | + "client.update_face(person_directory_id, existing_face_id, person_id=\"null\") # The person_id is set to \"null\" to remove the association\n", |
| 190 | + "\n", |
| 191 | + "# Associate the existing face ID with a person\n", |
| 192 | + "existing_person_id = \"existing_person_id\" # The unique ID of the person to be associated with the face.\n", |
| 193 | + "client.update_face(person_directory_id, existing_face_id, person_id=existing_person_id)" |
| 194 | + ] |
| 195 | + }, |
| 196 | + { |
| 197 | + "cell_type": "markdown", |
| 198 | + "id": "a04a7d26", |
| 199 | + "metadata": {}, |
| 200 | + "source": [ |
| 201 | + "### Deleting a face\n", |
| 202 | + "You can also delete a specific face. Once the face is deleted, the association between the face and its associated person is removed." |
| 203 | + ] |
| 204 | + }, |
| 205 | + { |
| 206 | + "cell_type": "code", |
| 207 | + "execution_count": null, |
| 208 | + "id": "da2bb1bd", |
| 209 | + "metadata": {}, |
| 210 | + "outputs": [], |
| 211 | + "source": [ |
| 212 | + "existing_face_id = \"existing_face_id\" # The unique ID of the face to delete.\n", |
| 213 | + "\n", |
| 214 | + "if client.delete_face(person_directory_id, existing_face_id):\n", |
| 215 | + " print(f\"Deleted face with face_id: {existing_face_id}\")\n", |
| 216 | + "else:\n", |
| 217 | + " print(f\"Failed to delete face with face_id: {existing_face_id}\")" |
| 218 | + ] |
| 219 | + }, |
| 220 | + { |
| 221 | + "cell_type": "markdown", |
| 222 | + "id": "2006b5f3", |
| 223 | + "metadata": {}, |
| 224 | + "source": [ |
| 225 | + "### Deleting a person\n", |
| 226 | + "\n", |
| 227 | + "When a person is deleted from the Person Directory, all the faces associated with that person remain in the Person Directory, but the association between the person and the faces is removed. This means the faces are no longer associated to any person in the Person Directory." |
| 228 | + ] |
| 229 | + }, |
| 230 | + { |
| 231 | + "cell_type": "code", |
| 232 | + "execution_count": null, |
| 233 | + "id": "5d52d34e", |
| 234 | + "metadata": {}, |
| 235 | + "outputs": [], |
| 236 | + "source": [ |
| 237 | + "existing_person_id = \"existing_person_id\" # The unique ID of the person to delete.\n", |
| 238 | + "if client.delete_person(person_directory_id, existing_person_id):\n", |
| 239 | + " print(f\"Deleted person with person_id: {existing_person_id}\")\n", |
| 240 | + "else:\n", |
| 241 | + " print(f\"Failed to delete person with person_id: {existing_person_id}\")" |
| 242 | + ] |
| 243 | + }, |
| 244 | + { |
| 245 | + "cell_type": "markdown", |
| 246 | + "id": "c007c6ab", |
| 247 | + "metadata": {}, |
| 248 | + "source": [ |
| 249 | + "### Deleting a person and their associated faces\n", |
| 250 | + "\n", |
| 251 | + "To completely remove a person and all their associated faces from the Person Directory, you can delete the person along with their face associations. This operation ensures that no residual data related to the person remains in the directory." |
| 252 | + ] |
| 253 | + }, |
| 254 | + { |
| 255 | + "cell_type": "code", |
| 256 | + "execution_count": null, |
| 257 | + "id": "3586f860", |
| 258 | + "metadata": {}, |
| 259 | + "outputs": [], |
| 260 | + "source": [ |
| 261 | + "existing_person_id = \"existing_person_id\" # The unique ID of the person to delete.\n", |
| 262 | + "\n", |
| 263 | + "# Get the list of face IDs associated with the person\n", |
| 264 | + "response = client.get_person(person_directory_id, existing_person_id)\n", |
| 265 | + "face_ids = response.get('faceIds', [])\n", |
| 266 | + "\n", |
| 267 | + "# Delete each face associated with the person\n", |
| 268 | + "for face_id in face_ids:\n", |
| 269 | + " if client.delete_face(person_directory_id, face_id):\n", |
| 270 | + " print(f\"Deleted face with face_id: {face_id}\")\n", |
| 271 | + " else:\n", |
| 272 | + " print(f\"Failed to delete face with face_id: {face_id}\")\n", |
| 273 | + "\n", |
| 274 | + "# Delete the person after deleting all associated faces\n", |
| 275 | + "if client.delete_person(person_directory_id, existing_person_id):\n", |
| 276 | + " print(f\"Deleted person with person_id: {existing_person_id}\")\n", |
| 277 | + "else:\n", |
| 278 | + " print(f\"Failed to delete person with person_id: {existing_person_id}\")" |
| 279 | + ] |
| 280 | + } |
| 281 | + ], |
| 282 | + "metadata": { |
| 283 | + "kernelspec": { |
| 284 | + "display_name": "openai-sample", |
| 285 | + "language": "python", |
| 286 | + "name": "python3" |
| 287 | + }, |
| 288 | + "language_info": { |
| 289 | + "codemirror_mode": { |
| 290 | + "name": "ipython", |
| 291 | + "version": 3 |
| 292 | + }, |
| 293 | + "file_extension": ".py", |
| 294 | + "mimetype": "text/x-python", |
| 295 | + "name": "python", |
| 296 | + "nbconvert_exporter": "python", |
| 297 | + "pygments_lexer": "ipython3", |
| 298 | + "version": "3.9.18" |
| 299 | + } |
| 300 | + }, |
| 301 | + "nbformat": 4, |
| 302 | + "nbformat_minor": 5 |
| 303 | +} |
0 commit comments