-
Notifications
You must be signed in to change notification settings - Fork 28
Review main-notebooks/build_person_directory.ipynb
#53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,7 +15,7 @@ | |
"source": [ | ||
"## Objective\n", | ||
"\n", | ||
" This notebook demonstrates how to identify faces in an image against a known set of persons. It begins by building a Person Directory, where each subfolder in a specified directory represents an individual. For each subfolder, a person is created and all face images within it are enrolled to that person.\n", | ||
"This notebook demonstrates how to identify faces in an image by matching them against a known set of persons. It begins by building a Person Directory, where each subfolder in a specified directory represents an individual. For each subfolder, a person entry is created, and all face images within that folder are enrolled to that person.\n", | ||
"\n", | ||
"| Enrollment | Searching |\n", | ||
"| :-: | :-: |\n", | ||
|
@@ -27,15 +27,19 @@ | |
"id": "80a375ca", | ||
"metadata": {}, | ||
"source": [ | ||
"## Create Azure content understanding face client\n", | ||
"> The [AzureContentUnderstandingFaceClient](../python/content_understanding_face_client.py) is a utility class for interacting with the Content Understanding Face service. Before the official SDK is released, this acts as a lightweight SDK. Set the constants **AZURE_AI_ENDPOINT**, **AZURE_AI_API_VERSION**, and **AZURE_AI_API_KEY** with your Azure AI Service information.\n", | ||
"## Create Azure Content Understanding Face Client\n", | ||
"\n", | ||
"> The [AzureContentUnderstandingFaceClient](../python/content_understanding_face_client.py) is a utility class designed for interacting with the Content Understanding Face service. Before the official SDK is released, this acts as a lightweight SDK.\n", | ||
"\n", | ||
"> Set the constants **AZURE_AI_ENDPOINT**, **AZURE_AI_API_VERSION**, and **AZURE_AI_API_KEY** with your Azure AI Service credentials.\n", | ||
"\n", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
"> ⚠️ Important:\n", | ||
"You must update the code below to match your Azure authentication method.\n", | ||
"Look for the `# IMPORTANT` comments and modify those sections accordingly.\n", | ||
"If you skip this step, the sample may not run correctly.\n", | ||
"Check for the `# IMPORTANT` comments and modify those sections accordingly.\n", | ||
"If you skip this step, the sample may not run as expected.\n", | ||
"\n", | ||
"> ⚠️ Note: Using a subscription key works, but using a token provider with Azure Active Directory (AAD) is much safer and is highly recommended for production environments." | ||
"> ⚠️ Note:\n", | ||
"Using a subscription key is supported, but using a token provider with Azure Active Directory (AAD) is more secure and strongly recommended for production environments." | ||
] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
}, | ||
{ | ||
|
@@ -52,7 +56,7 @@ | |
"from dotenv import find_dotenv, load_dotenv\n", | ||
"from azure.identity import DefaultAzureCredential, get_bearer_token_provider\n", | ||
"\n", | ||
"# import utility package from python samples root directory\n", | ||
"# Import utility package from Python samples root directory\n", | ||
"parent_dir = Path.cwd().parent\n", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
"sys.path.append(str(parent_dir))\n", | ||
"from python.content_understanding_face_client import AzureContentUnderstandingFaceClient\n", | ||
|
@@ -70,7 +74,7 @@ | |
" token_provider=token_provider,\n", | ||
" # IMPORTANT: Uncomment this if using subscription key\n", | ||
" # subscription_key=os.getenv(\"AZURE_AI_API_KEY\"),\n", | ||
" 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", | ||
" x_ms_useragent=\"azure-ai-content-understanding-python/build_person_directory\", # Used for sample usage telemetry; comment out to opt out.\n", | ||
")" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
] | ||
}, | ||
|
@@ -93,43 +97,43 @@ | |
"import uuid\n", | ||
"folder_path = \"../data/face/enrollment_data\" # Replace with the path to your folder containing subfolders of images\n", | ||
"\n", | ||
"# Create a person directory\n", | ||
"# Create a person directory with a unique ID\n", | ||
"person_directory_id = f\"person_directory_id_{uuid.uuid4().hex[:8]}\"\n", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
"client.create_person_directory(person_directory_id)\n", | ||
"logging.info(f\"Created person directory with ID: {person_directory_id}\")\n", | ||
"\n", | ||
"# Iterate through all subfolders in the folder_path\n", | ||
"# Iterate through all subfolders in the enrollment folder\n", | ||
"for subfolder_name in os.listdir(folder_path):\n", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
" subfolder_path = os.path.join(folder_path, subfolder_name)\n", | ||
" if os.path.isdir(subfolder_path):\n", | ||
" person_name = subfolder_name\n", | ||
" # Add a person for each subfolder\n", | ||
" # Add a person entry for each subfolder\n", | ||
" person = client.add_person(person_directory_id, tags={\"name\": person_name})\n", | ||
" logging.info(f\"Created person {person_name} with person_id: {person['personId']}\")\n", | ||
" logging.info(f\"Created person '{person_name}' with person_id: {person['personId']}\")\n", | ||
" if person:\n", | ||
" # Iterate through all images in the subfolder\n", | ||
" # Iterate through all image files in the subfolder\n", | ||
" for filename in os.listdir(subfolder_path):\n", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
" if filename.lower().endswith(('.png', '.jpg', '.jpeg')):\n", | ||
" image_path = os.path.join(subfolder_path, filename)\n", | ||
" # Convert image to base64\n", | ||
" # Convert image to base64 encoded string\n", | ||
" image_data = AzureContentUnderstandingFaceClient.read_file_to_base64(image_path)\n", | ||
" # Add a face to the Person Directory and associate it to the added person\n", | ||
" # Add the face to the Person Directory and associate it with the person\n", | ||
" face = client.add_face(person_directory_id, image_data, person['personId'])\n", | ||
" if face:\n", | ||
" logging.info(f\"Added face from {filename} with face_id: {face['faceId']} to person_id: {person['personId']}\")\n", | ||
" logging.info(f\"Added face from '{filename}' with face_id: {face['faceId']} to person_id: {person['personId']}\")\n", | ||
" else:\n", | ||
" logging.warning(f\"Failed to add face from {filename} to person_id: {person['personId']}\")\n", | ||
" logging.warning(f\"Failed to add face from '{filename}' to person_id: {person['personId']}\")\n", | ||
"\n", | ||
"logging.info(\"Done\")" | ||
"logging.info(\"Person directory creation complete.\")" | ||
] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
}, | ||
{ | ||
"cell_type": "markdown", | ||
"id": "6a5a058c", | ||
"metadata": {}, | ||
"source": [ | ||
"### Identifying person\n", | ||
"Detect multiple faces in an image and identify each one by matching it against enrolled persons in the Person Directory." | ||
"### Identifying persons\n", | ||
"Detect multiple faces in an image and identify each by matching against enrolled persons in the Person Directory." | ||
] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
}, | ||
{ | ||
|
@@ -144,14 +148,14 @@ | |
"# Detect faces in the test image\n", | ||
"image_data = AzureContentUnderstandingFaceClient.read_file_to_base64(test_image_path)\n", | ||
"detected_faces = client.detect_faces(data=image_data)\n", | ||
"for face in detected_faces['detectedFaces']:\n", | ||
"for face in detected_faces.get('detectedFaces', []):\n", | ||
" identified_persons = client.identify_person(person_directory_id, image_data, face['boundingBox'])\n", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
" if identified_persons.get(\"personCandidates\"):\n", | ||
" person = identified_persons[\"personCandidates\"][0]\n", | ||
" name = person.get(\"tags\", {}).get(\"name\", \"Unknown\")\n", | ||
" logging.info(f\"Detected person: {name} with confidence: {person.get('confidence', 0)} at bounding box: {face['boundingBox']}\")\n", | ||
" logging.info(f\"Detected person: {name} with confidence: {person.get('confidence', 0):.2f} at bounding box: {face['boundingBox']}\")\n", | ||
"\n", | ||
"logging.info(\"Done\")" | ||
"logging.info(\"Identification complete.\")" | ||
] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
}, | ||
{ | ||
|
@@ -160,7 +164,7 @@ | |
"metadata": {}, | ||
"source": [ | ||
"### Adding and associating a new face\n", | ||
"You can add a new face to the Person Directory and associate it with an existing person." | ||
"You can add a new face image to the Person Directory and associate it with an existing person." | ||
] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
}, | ||
{ | ||
|
@@ -170,17 +174,17 @@ | |
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"new_face_image_path = \"new_face_image_path\" # The path to the face image you want to add.\n", | ||
"existing_person_id = \"existing_person_id\" # The unique ID of the person to whom the face should be associated.\n", | ||
"new_face_image_path = \"new_face_image_path\" # Path to the new face image to be added.\n", | ||
"existing_person_id = \"existing_person_id\" # Unique ID of the person to associate the face with.\n", | ||
"\n", | ||
"# Convert the new face image to base64\n", | ||
"# Convert the new face image to a base64 encoded string\n", | ||
"image_data = AzureContentUnderstandingFaceClient.read_file_to_base64(new_face_image_path)\n", | ||
"# Add the new face to the person directory and associate it with the existing person\n", | ||
"# Add the new face to the Person Directory and associate it with the existing person\n", | ||
"face = client.add_face(person_directory_id, image_data, existing_person_id)\n", | ||
"if face:\n", | ||
" logging.info(f\"Added face from {new_face_image_path} with face_id: {face['faceId']} to person_id: {existing_person_id}\")\n", | ||
" logging.info(f\"Added face from '{new_face_image_path}' with face_id: {face['faceId']} to person_id: {existing_person_id}\")\n", | ||
"else:\n", | ||
" logging.warning(f\"Failed to add face from {new_face_image_path} to person_id: {existing_person_id}\")" | ||
" logging.warning(f\"Failed to add face from '{new_face_image_path}' to person_id: {existing_person_id}\")" | ||
] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
}, | ||
{ | ||
|
@@ -190,7 +194,7 @@ | |
"source": [ | ||
"### Associating a list of already enrolled faces\n", | ||
"\n", | ||
"You can associate a list of already enrolled faces in the Person Directory with their respective persons. This is useful if you have existing face IDs to link to specific persons." | ||
"You can associate a list of existing face IDs with their respective persons in the Person Directory. This is useful when linking pre-enrolled faces to specific persons." | ||
] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
}, | ||
{ | ||
|
@@ -200,10 +204,10 @@ | |
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"existing_person_id = \"existing_person_id\" # The unique ID of the person to whom the face should be associated.\n", | ||
"existing_face_id_list = [\"existing_face_id_1\", \"existing_face_id_2\"] # The list of face IDs to be associated.\n", | ||
"existing_person_id = \"existing_person_id\" # Unique ID of the person to associate faces with.\n", | ||
"existing_face_id_list = [\"existing_face_id_1\", \"existing_face_id_2\"] # List of face IDs to associate.\n", | ||
"\n", | ||
"# Associate the existing face IDs with the existing person\n", | ||
"# Associate the listed face IDs with the specified person\n", | ||
"client.update_person(person_directory_id, existing_person_id, face_ids=existing_face_id_list)" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
] | ||
}, | ||
|
@@ -213,7 +217,7 @@ | |
"metadata": {}, | ||
"source": [ | ||
"### Associating and disassociating a face from a person\n", | ||
"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." | ||
"You can link a face to a person or remove such a link in the Person Directory. Associating a face connects it to a specific person, while disassociating removes this connection." | ||
] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
}, | ||
{ | ||
|
@@ -223,18 +227,18 @@ | |
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"existing_face_id = \"existing_face_id\" # The unique ID of the face.\n", | ||
"existing_face_id = \"existing_face_id\" # Unique ID of the face.\n", | ||
"\n", | ||
"# Remove the association of the existing face ID from the person\n", | ||
"client.update_face(person_directory_id, existing_face_id, person_id=\"\") # The person_id is set to \"\" to remove the association\n", | ||
"logging.info(f\"Removed association of face_id: {existing_face_id} from the existing person_id\")\n", | ||
"logging.info(client.get_face(person_directory_id, existing_face_id)) # This will return the face information without the person association\n", | ||
"# Remove the association of the face from its person by setting person_id to an empty string\n", | ||
"client.update_face(person_directory_id, existing_face_id, person_id=\"\")\n", | ||
"logging.info(f\"Removed association of face_id: {existing_face_id} from its person.\")\n", | ||
"logging.info(client.get_face(person_directory_id, existing_face_id)) # Returns face information without person association\n", | ||
"\n", | ||
"# Associate the existing face ID with a person\n", | ||
"existing_person_id = \"existing_person_id\" # The unique ID of the person to be associated with the face.\n", | ||
"# Associate the face ID with a person\n", | ||
"existing_person_id = \"existing_person_id\" # Unique ID of the person to associate the face with.\n", | ||
"client.update_face(person_directory_id, existing_face_id, person_id=existing_person_id)\n", | ||
"logging.info(f\"Associated face_id: {existing_face_id} with person_id: {existing_person_id}\")\n", | ||
"logging.info(client.get_face(person_directory_id, existing_face_id)) # This will return the face information with the new person association" | ||
"logging.info(client.get_face(person_directory_id, existing_face_id)) # Returns face information with updated person association" | ||
] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
}, | ||
{ | ||
|
@@ -243,7 +247,7 @@ | |
"metadata": {}, | ||
"source": [ | ||
"### Updating metadata (tags and descriptions)\n", | ||
"You can add or update tags for individual persons, and both descriptions and tags for the Person Directory. These metadata fields help organize, filter, and manage your directory." | ||
"You can add or update tags for individual persons as well as update the description and tags for the entire Person Directory. These metadata fields help organize, filter, and manage your directory effectively." | ||
] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
}, | ||
{ | ||
|
@@ -263,19 +267,19 @@ | |
" tags=person_directory_tags\n", | ||
")\n", | ||
"logging.info(f\"Updated Person Directory with description: '{person_directory_description}' and tags: {person_directory_tags}\")\n", | ||
"logging.info(client.get_person_directory(person_directory_id)) # This will return the updated person directory information\n", | ||
"logging.info(client.get_person_directory(person_directory_id)) # Returns the updated Person Directory information\n", | ||
"\n", | ||
"# Update the tags for an individual person\n", | ||
"existing_person_id = \"existing_person_id\" # The unique ID of the person to update.\n", | ||
"person_tags = {\"role\": \"tester\", \"department\": \"engineering\", \"name\": \"\"} # This will remove the name tag from the person.\n", | ||
"existing_person_id = \"existing_person_id\" # Unique ID of the person to update\n", | ||
"person_tags = {\"role\": \"tester\", \"department\": \"engineering\", \"name\": \"\"} # This will remove the 'name' tag from the person\n", | ||
"\n", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
"client.update_person(\n", | ||
" person_directory_id,\n", | ||
" existing_person_id,\n", | ||
" tags=person_tags\n", | ||
")\n", | ||
"logging.info(f\"Updated person with person_id: {existing_person_id} with tags: {person_tags}\")\n", | ||
"logging.info(client.get_person(person_directory_id, existing_person_id)) # This will return the updated person information" | ||
"logging.info(client.get_person(person_directory_id, existing_person_id)) # Returns the updated person information" | ||
] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
}, | ||
{ | ||
|
@@ -284,7 +288,7 @@ | |
"metadata": {}, | ||
"source": [ | ||
"### Deleting a face\n", | ||
"You can also delete a specific face. Once the face is deleted, the association between the face and its associated person is removed." | ||
"You can delete a specific face from the Person Directory. Once deleted, the association between the face and the person is removed." | ||
] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
}, | ||
{ | ||
|
@@ -294,7 +298,7 @@ | |
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"existing_face_id = \"existing_face_id\" # The unique ID of the face to delete.\n", | ||
"existing_face_id = \"existing_face_id\" # Unique ID of the face to delete\n", | ||
"\n", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
"client.delete_face(person_directory_id, existing_face_id)\n", | ||
"logging.info(f\"Deleted face with face_id: {existing_face_id}\")" | ||
|
@@ -307,7 +311,7 @@ | |
"source": [ | ||
"### Deleting a person\n", | ||
"\n", | ||
"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." | ||
"When a person is deleted from the Person Directory, all faces associated with that person remain in the directory but their association with the person is removed. This means the faces are no longer linked to any person." | ||
] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
}, | ||
{ | ||
|
@@ -317,7 +321,7 @@ | |
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"existing_person_id = \"existing_person_id\" # The unique ID of the person to delete.\n", | ||
"existing_person_id = \"existing_person_id\" # Unique ID of the person to delete\n", | ||
"\n", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
"client.delete_person(person_directory_id, existing_person_id)\n", | ||
"logging.info(f\"Deleted person with person_id: {existing_person_id}\")" | ||
|
@@ -330,7 +334,7 @@ | |
"source": [ | ||
"### Deleting a person and their associated faces\n", | ||
"\n", | ||
"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." | ||
"To completely remove a person and all their associated faces from the Person Directory, delete the faces first, then delete the person. This ensures no residual data remains linked to that person." | ||
] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
}, | ||
{ | ||
|
@@ -340,15 +344,15 @@ | |
"metadata": {}, | ||
"outputs": [], | ||
"source": [ | ||
"existing_person_id = \"existing_person_id\" # The unique ID of the person to delete.\n", | ||
"existing_person_id = \"existing_person_id\" # Unique ID of the person to delete\n", | ||
"\n", | ||
"# Get the list of face IDs associated with the person\n", | ||
"# Retrieve the list of face IDs associated with the person\n", | ||
"response = client.get_person(person_directory_id, existing_person_id)\n", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
"face_ids = response.get('faceIds', [])\n", | ||
"\n", | ||
"# Delete each face associated with the person\n", | ||
"for face_id in face_ids:\n", | ||
" logging.info(f\"Deleting face with face_id: {face_id} from person_id: {existing_person_id}\")\n", | ||
" logging.info(f\"Deleting face with face_id: {face_id} associated with person_id: {existing_person_id}\")\n", | ||
" client.delete_face(person_directory_id, face_id)\n", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
"\n", | ||
"# Delete the person after deleting all associated faces\n", | ||
|
@@ -378,4 +382,4 @@ | |
}, | ||
"nbformat": 4, | ||
"nbformat_minor": 5 | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.