Spaces:
Sleeping
Sleeping
| import hashlib | |
| import numpy as np | |
| from PIL import Image | |
| import imagehash | |
| from skimage.metrics import structural_similarity as ssim | |
| import cv2 | |
| class AdvancedFeatures: | |
| def perceptual_hash(image_path): | |
| """Generate perceptual hash for deduplication""" | |
| img = Image.open(image_path) | |
| return imagehash.phash(img, hash_size=16) | |
| def find_similar_images(image_paths, threshold=5): | |
| """Group similar images by perceptual hash""" | |
| hashes = {} | |
| for path in image_paths: | |
| try: | |
| hashes[path] = AdvancedFeatures.perceptual_hash(path) | |
| except: | |
| pass | |
| # Group images | |
| groups = [] | |
| processed = set() | |
| for path1, hash1 in hashes.items(): | |
| if path1 in processed: | |
| continue | |
| group = [path1] | |
| for path2, hash2 in hashes.items(): | |
| if path2 != path1 and path2 not in processed: | |
| if hash1 - hash2 <= threshold: | |
| group.append(path2) | |
| processed.add(path2) | |
| groups.append(group) | |
| processed.add(path1) | |
| return groups | |
| def calculate_ssim(original_path, compressed_path): | |
| """Calculate structural similarity index""" | |
| img1 = cv2.imread(str(original_path)) | |
| img2 = cv2.imread(str(compressed_path)) | |
| # Resize to same dimensions | |
| if img1.shape != img2.shape: | |
| img2 = cv2.resize(img2, (img1.shape[1], img1.shape[0])) | |
| # Convert to grayscale for SSIM | |
| gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) | |
| gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) | |
| score = ssim(gray1, gray2) | |
| return score | |
| def recursive_optimize(compressor, img, target_size_kb, max_iterations=10): | |
| """Find optimal quality to hit target file size""" | |
| low, high = 30, 100 | |
| best_result = None | |
| best_size_diff = float('inf') | |
| for _ in range(max_iterations): | |
| mid = (low + high) // 2 | |
| # Test at quality 'mid' | |
| test_output = io.BytesIO() | |
| img.save(test_output, format='WEBP', quality=mid) | |
| size_kb = len(test_output.getvalue()) / 1024 | |
| diff = abs(size_kb - target_size_kb) | |
| if diff < best_size_diff: | |
| best_size_diff = diff | |
| best_result = (mid, test_output.getvalue()) | |
| if size_kb > target_size_kb: | |
| high = mid - 1 | |
| else: | |
| low = mid + 1 | |
| if diff < target_size_kb * 0.05: # Within 5% | |
| break | |
| return best_result |