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:
@@ -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()
|
||||
Reference in New Issue
Block a user