feat: Enhance face processing with EXIF orientation handling and database updates

This commit introduces a comprehensive EXIF orientation handling system to improve face processing accuracy. Key changes include the addition of an `exif_orientation` field in the database schema, updates to the `FaceProcessor` class for applying orientation corrections before face detection, and the implementation of a new `EXIFOrientationHandler` utility for managing image orientation. The README has been updated to document these enhancements, including recent fixes for face orientation issues and improved face extraction logic. Additionally, tests for EXIF orientation handling have been added to ensure functionality and reliability.
This commit is contained in:
tanyar09
2025-10-17 13:50:47 -04:00
parent 2828b9966b
commit 5db41b63ef
5 changed files with 484 additions and 83 deletions
+136
View File
@@ -0,0 +1,136 @@
#!/usr/bin/env python3
"""
Test script for EXIF orientation handling
"""
import sys
import os
sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
from src.utils.exif_utils import EXIFOrientationHandler
from PIL import Image
import tempfile
def test_exif_orientation_detection():
"""Test EXIF orientation detection"""
print("🧪 Testing EXIF orientation detection...")
# Test with any available images in the project
test_dirs = [
"/home/ladmin/Code/punimtag/demo_photos",
"/home/ladmin/Code/punimtag/data"
]
test_images = []
for test_dir in test_dirs:
if os.path.exists(test_dir):
for file in os.listdir(test_dir):
if file.lower().endswith(('.jpg', '.jpeg', '.png')):
test_images.append(os.path.join(test_dir, file))
if len(test_images) >= 2: # Limit to 2 images for testing
break
if not test_images:
print(" ️ No test images found - testing with coordinate transformation only")
return
for image_path in test_images:
print(f"\n📸 Testing: {os.path.basename(image_path)}")
# Get orientation info
orientation = EXIFOrientationHandler.get_exif_orientation(image_path)
orientation_info = EXIFOrientationHandler.get_orientation_info(image_path)
print(f" Orientation: {orientation}")
print(f" Description: {orientation_info['description']}")
print(f" Needs correction: {orientation_info['needs_correction']}")
if orientation and orientation != 1:
print(f" ✅ EXIF orientation detected: {orientation}")
else:
print(f" ️ No orientation correction needed")
def test_coordinate_transformation():
"""Test face coordinate transformation"""
print("\n🧪 Testing coordinate transformation...")
# Test coordinates in DeepFace format
test_coords = {'x': 100, 'y': 150, 'w': 200, 'h': 200}
original_width, original_height = 800, 600
print(f" Original coordinates: {test_coords}")
print(f" Image dimensions: {original_width}x{original_height}")
# Test different orientations
test_orientations = [1, 3, 6, 8] # Normal, 180°, 90° CW, 90° CCW
for orientation in test_orientations:
transformed = EXIFOrientationHandler.transform_face_coordinates(
test_coords, original_width, original_height, orientation
)
print(f" Orientation {orientation}: {transformed}")
def test_image_correction():
"""Test image orientation correction"""
print("\n🧪 Testing image orientation correction...")
# Test with any available images
test_dirs = [
"/home/ladmin/Code/punimtag/demo_photos",
"/home/ladmin/Code/punimtag/data"
]
test_images = []
for test_dir in test_dirs:
if os.path.exists(test_dir):
for file in os.listdir(test_dir):
if file.lower().endswith(('.jpg', '.jpeg', '.png')):
test_images.append(os.path.join(test_dir, file))
if len(test_images) >= 1: # Limit to 1 image for testing
break
if not test_images:
print(" ️ No test images found - skipping image correction test")
return
for image_path in test_images:
print(f"\n📸 Testing correction for: {os.path.basename(image_path)}")
try:
# Load and correct image
corrected_image, orientation = EXIFOrientationHandler.correct_image_orientation_from_path(image_path)
if corrected_image:
print(f" ✅ Image loaded and corrected")
print(f" Original orientation: {orientation}")
print(f" Corrected dimensions: {corrected_image.size}")
# Save corrected image to temp file for inspection
with tempfile.NamedTemporaryFile(suffix='_corrected.jpg', delete=False) as tmp_file:
corrected_image.save(tmp_file.name, quality=95)
print(f" Corrected image saved to: {tmp_file.name}")
else:
print(f" ❌ Failed to load/correct image")
except Exception as e:
print(f" ❌ Error: {e}")
break # Only test first image found
def main():
"""Run all tests"""
print("🔍 EXIF Orientation Handling Tests")
print("=" * 50)
test_exif_orientation_detection()
test_coordinate_transformation()
test_image_correction()
print("\n✅ All tests completed!")
if __name__ == "__main__":
main()