Files
uniface/examples/face_parsing.ipynb

388 lines
2.0 MiB
Plaintext
Raw Normal View History

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Face Parsing with UniFace\n",
"\n",
"This notebook demonstrates face parsing (semantic segmentation) using the **UniFace** library.\n",
"\n",
"Face parsing segments a face image into different facial components such as skin, eyes, nose, mouth, hair, etc.\n",
"\n",
"## 1. Install UniFace"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Note: you may need to restart the kernel to use updated packages.\n"
]
}
],
"source": [
"%pip install -q uniface"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 2. Import Libraries"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"UniFace version: 1.6.0\n"
]
}
],
"source": [
"import cv2\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"from pathlib import Path\n",
"\n",
"import uniface\n",
"from uniface.parsing import BiSeNet\n",
"from uniface.constants import ParsingWeights\n",
"from uniface.visualization import vis_parsing_maps\n",
"\n",
"print(f\"UniFace version: {uniface.__version__}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 3. Initialize BiSeNet Model"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"✓ Model loaded (CoreML (Apple Silicon))\n"
]
}
],
"source": [
"# Initialize face parser (uses ResNet18 by default)\n",
"parser = BiSeNet(model_name=ParsingWeights.RESNET34) # use resnet34 for better accuracy"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 4. Face Parsing Classes\n",
"\n",
"The BiSeNet model segments faces into **19 different classes**:\n",
"\n",
"| Class ID | Component | Class ID | Component |\n",
"|----------|-----------|----------|----------|\n",
"| 0 | Background | 10 | Nose |\n",
"| 1 | Skin | 11 | Mouth |\n",
"| 2 | Left Eyebrow | 12 | Upper Lip |\n",
"| 3 | Right Eyebrow | 13 | Lower Lip |\n",
"| 4 | Left Eye | 14 | Neck |\n",
"| 5 | Right Eye | 15 | Neck Lace |\n",
"| 6 | Eye Glasses | 16 | Cloth |\n",
"| 7 | Left Ear | 17 | Hair |\n",
"| 8 | Right Ear | 18 | Hat |\n",
"| 9 | Ear Ring | | |"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 5. Process Test Images\n",
"\n",
"The test images are already cropped face images, so we can directly parse them without face detection."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Processing: image0.jpg\n",
" Parsed with 13 unique classes\n",
"Processing: image1.jpg\n",
" Parsed with 12 unique classes\n",
"Processing: image2.jpg\n",
" Parsed with 11 unique classes\n",
"Processing: image3.jpg\n",
" Parsed with 12 unique classes\n",
"Processing: image4.jpg\n",
" Parsed with 10 unique classes\n",
"\n",
"Processed 5 images\n"
]
}
],
"source": [
"# Get all test images\n",
"test_images_dir = Path('../assets/test_images')\n",
"test_images = sorted(test_images_dir.glob('*.jpg'))\n",
"\n",
"# Store original and processed images\n",
"original_images = []\n",
"parsed_images = []\n",
"\n",
"for image_path in test_images:\n",
" print(f\"Processing: {image_path.name}\")\n",
"\n",
" # Load image (already a face crop)\n",
" image = cv2.imread(str(image_path))\n",
"\n",
" # Parse the face directly\n",
" mask = parser.parse(image)\n",
" unique_classes = len(set(mask.flatten()))\n",
" print(f' Parsed with {unique_classes} unique classes')\n",
"\n",
" # Visualize the parsing result\n",
" image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n",
" vis_result = vis_parsing_maps(image_rgb, mask, save_image=False)\n",
"\n",
" original_images.append(image_rgb)\n",
" parsed_images.append(vis_result)\n",
"\n",
"print(f\"\\nProcessed {len(test_images)} images\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 6. Visualize Results\n",
"\n",
"Display original images in the first row and parsed images in the second row."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 2000x800 with 10 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"num_images = len(original_images)\n",
"fig, axes = plt.subplots(2, num_images, figsize=(4 * num_images, 8))\n",
"\n",
"if num_images == 1:\n",
" axes = axes.reshape(-1, 1)\n",
"\n",
"for i in range(num_images):\n",
" # Original image\n",
" axes[0, i].imshow(original_images[i])\n",
" axes[0, i].set_title(f'Original {i+1}', fontsize=12)\n",
" axes[0, i].axis('off')\n",
"\n",
" # Parsed image\n",
" axes[1, i].imshow(parsed_images[i])\n",
" axes[1, i].set_title(f'Parsed {i+1}', fontsize=12)\n",
" axes[1, i].axis('off')\n",
"\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 7. Parse a Single Face (Detailed)\n",
"\n",
"Let's parse a single face and display the segmentation mask in detail."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABcYAAAH/CAYAAAB9zg7OAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzsvQncLdlVFV73e/PU7/U8ZOwOSSADJGEKk2ESCIoMCggoCIogisigQoB/ZEYEHAABRRFnAREUkEkiEAwICRDRJITMczqd9Phev+5+7/5/u+5ddVetWvvUqfsNr9Ndu/u++92qM+yzzz77nL3OrlOL5XK5bGaaaaaZZppppplmmmmmmWaaaaaZZppppplmmulRQjtXmoGZZppppplmmmmmmWaaaaaZZppppplmmmmmmWY6SJqB8ZlmmmmmmWaaaaaZZppppplmmmmmmWaaaaaZHlU0A+MzzTTTTDPNNNNMM80000wzzTTTTDPNNNNMMz2qaAbGZ5pppplmmmmmmWaaaaaZZppppplmmmmmmWZ6VNEMjM8000wzzTTTTDPNNNNMM80000wzzTTTTDPN9KiiGRifaaaZZppppplmmmmmmWaaaaaZZppppplmmulRRTMwPtNMM80000wzzTTTTDPNNNNMM80000wzzTTTo4pmYHymmWaaaaaZZppppplmmmmmmWaaaaaZZppppkcVzcD4TDPNNNNMM80000wzzTTTTDPNNNNMM80000yPKpqB8Zlm2oL+0l/6S81isWhe//rX76qcj/7oj27LOUgKnqPOaMNMM80000wzzfTeRfM8Xk9/7+/9vVZW//N//s8rzcpMM80006OOHgnzVfAfPvvDkWJuC/5irrvSGENG/+pf/auWl/ieaaaHK83A+EyPeHrRi17UfPZnf3bzuMc9rjl27FhzzTXXNB/5kR/Z/MN/+A+b+++//0qz97AnTGbZ51nPetaVZnGmmWaaaaY9oPvuu6/59m//9uY5z3lOc/r06XbOfOxjH9t81Ed9VPN1X/d1zWte85orzeLDlvba8XviE5/Yft6bgI/43HTTTc1DDz1k073iFa/o0r23tG2mmWaa6eFEs1+7Hb3gBS9o557v+I7vKKa7fPly8/jHP745dOhQ86Y3venA+HtvpkfC5sdMMx2+0gzMNNN+UThmf/2v//Xmn/2zf9acOnWqef7z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
"text/plain": [
"<Figure size 1500x500 with 3 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Mask shape: (208, 208)\n",
"Unique classes: [ 0 1 2 3 4 5 10 12 13 14 16 17]\n",
"Number of classes: 12\n"
]
}
],
"source": [
"# Load a test image\n",
"image_path = '../assets/test_images/image1.jpg'\n",
"image = cv2.imread(image_path)\n",
"\n",
"# Parse the face\n",
"mask = parser.parse(image)\n",
"\n",
"# Visualize\n",
"image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n",
"vis_result = vis_parsing_maps(image_rgb, mask, save_image=False)\n",
"\n",
"# Display\n",
"fig, axes = plt.subplots(1, 3, figsize=(15, 5))\n",
"\n",
"axes[0].imshow(image_rgb)\n",
"axes[0].set_title('Original Face', fontsize=14)\n",
"axes[0].axis('off')\n",
"\n",
"axes[1].imshow(mask, cmap='tab20')\n",
"axes[1].set_title('Segmentation Mask', fontsize=14)\n",
"axes[1].axis('off')\n",
"\n",
"axes[2].imshow(vis_result)\n",
"axes[2].set_title('Overlay Visualization', fontsize=14)\n",
"axes[2].axis('off')\n",
"\n",
"plt.tight_layout()\n",
"plt.show()\n",
"\n",
"print(f\"Mask shape: {mask.shape}\")\n",
"print(f\"Unique classes: {np.unique(mask)}\")\n",
"print(f\"Number of classes: {len(np.unique(mask))}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 8. Extract Specific Facial Components\n",
"\n",
"You can extract specific facial components using the mask."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 2000x400 with 5 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Load image\n",
"image_path = '../assets/test_images/image0.jpg'\n",
"image = cv2.imread(image_path)\n",
"image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n",
"\n",
"# Parse the face\n",
"mask = parser.parse(image)\n",
"\n",
"# Extract specific components\n",
"# 1 = skin, 17 = hair, 10 = nose, 12 = upper lip, 13 = lower lip\n",
"components_to_extract = {\n",
" 'Skin': 1,\n",
" 'Hair': 17,\n",
" 'Nose': 10,\n",
" 'Lips': [12, 13] # Upper and lower lips combined\n",
"}\n",
"\n",
"fig, axes = plt.subplots(1, len(components_to_extract) + 1, figsize=(20, 4))\n",
"\n",
"# Show original\n",
"axes[0].imshow(image_rgb)\n",
"axes[0].set_title('Original', fontsize=12)\n",
"axes[0].axis('off')\n",
"\n",
"# Extract and show each component\n",
"for idx, (name, class_ids) in enumerate(components_to_extract.items(), 1):\n",
" # Handle both single class and multiple classes\n",
" if isinstance(class_ids, list):\n",
" component_mask = np.zeros_like(mask, dtype=np.uint8)\n",
" for class_id in class_ids:\n",
" component_mask |= (mask == class_id).astype(np.uint8)\n",
" else:\n",
" component_mask = (mask == class_ids).astype(np.uint8)\n",
"\n",
" # Apply mask to image\n",
" extracted = image_rgb.copy()\n",
" extracted[component_mask == 0] = 0\n",
"\n",
" axes[idx].imshow(extracted)\n",
" axes[idx].set_title(name, fontsize=12)\n",
" axes[idx].axis('off')\n",
"\n",
"plt.tight_layout()\n",
"plt.show()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "base",
"language": "python",
"name": "python3"
},
"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.13.5"
}
},
"nbformat": 4,
"nbformat_minor": 4
}