Image_Compressor / utils /advanced.py
DILSHAD737's picture
Upload 3 files
cd922fb verified
Raw
History Blame Contribute Delete
2.89 kB
import hashlib
import numpy as np
from PIL import Image
import imagehash
from skimage.metrics import structural_similarity as ssim
import cv2
class AdvancedFeatures:
@staticmethod
def perceptual_hash(image_path):
"""Generate perceptual hash for deduplication"""
img = Image.open(image_path)
return imagehash.phash(img, hash_size=16)
@staticmethod
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
@staticmethod
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
@staticmethod
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