File size: 2,889 Bytes
cd922fb
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
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