File size: 4,773 Bytes
9754b95
 
 
 
 
 
 
 
 
babdf76
 
9754b95
 
 
 
 
4de751c
9754b95
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
import os
import time
from PIL import Image
from retinaface import RetinaFace
from concurrent.futures import ProcessPoolExecutor

Image.MAX_IMAGE_PIXELS = 200000000  # Allow images up to 200 million pixels

DATA = [
    ((768, 768), r"/kaggle/input/samikk"),
    ((1024, 1024), r"/kaggle/input/samikk"),
]



NUM_THREADS = 1  # Modify this for the desired number of threads
OUTPUT_ROOT = r"/kaggle/working/outputs"  # Root folder to save resized images
Save_PNG = False  # Options are True and False
LOG_FILE = "face_detection_failures.txt"  # File to log images where faces can't be detected

def resize_image(args):
    start_time = time.time()  # Start timing

    try:
        input_path, resolution, output_root, save_as_png = args
    except ValueError as e:
        print(f"Error unpacking arguments: {e}")
        return None

    try:
        # Load the image
        image = Image.open(input_path)
    except Exception as e:
        print(f"Error loading image: {e}")
        return None

    face_detected = True
    face_locations = None

    try:
        # Get face locations using RetinaFace
        faces = RetinaFace.detect_faces(input_path)

        if not faces or 'face_1' not in faces:
            face_detected = False
            with open(LOG_FILE, 'a') as log:
                log.write(f"Face not detected: {input_path}\n")
        else:
            face = faces['face_1']
            x, y, x2, y2 = face['facial_area']
            face_locations = [(y, x2, y2, x)]  # Adjust format to match face_recognition
    except Exception as e:
        print(f"Error detecting faces: {e}")
        face_detected = False

    # Proceed with cropping and resizing
    try:
        desired_aspect_ratio = resolution[0] / resolution[1]
        image_aspect_ratio = image.width / image.height

        # Calculate crop dimensions
        if image_aspect_ratio > desired_aspect_ratio:
            new_width = int(image.height * desired_aspect_ratio)
            new_height = image.height
        else:
            new_width = image.width
            new_height = int(image.width / desired_aspect_ratio)

        # Default centering
        left = (image.width - new_width) / 2
        top = (image.height - new_height) / 2
        right = (image.width + new_width) / 2
        bottom = (image.height + new_height) / 2

        # Adjust for face center if a face is detected
        if face_detected and face_locations:
            face_top, face_right, face_bottom, face_left = face_locations[0]
            face_center_x = (face_left + face_right) // 2
            face_center_y = (face_top + face_bottom) // 2

            left = min(max(0, face_center_x - new_width // 2), image.width - new_width)
            top = min(max(0, face_center_y - new_height // 2), image.height - new_height)
            right = left + new_width
            bottom = top + new_height

        image = image.crop((left, top, right, bottom))

        # Resize image with best resampling filter (LANCZOS)
        image = image.resize(resolution, Image.LANCZOS)

        output_folder = os.path.join(output_root, f"{resolution[0]}x{resolution[1]}")
        if not os.path.exists(output_folder):
            os.makedirs(output_folder)

        output_path = os.path.join(output_folder, os.path.basename(input_path))
        if save_as_png:
            output_path = os.path.splitext(output_path)[0] + '.png'
            image.save(output_path, format='PNG')
        else:
            image.save(output_path, quality=100)

    except Exception as e:
        print(f"Error processing or saving image: {e}")
        return None

    end_time = time.time()  # End timing
    return end_time - start_time  # Return processing time

def process_folder(input_folder, resolution, save_as_png):
    image_paths = [os.path.join(input_folder, fname) for fname in os.listdir(input_folder) if fname.lower().endswith(('png', 'jpg', 'jpeg'))]

    total_images = len(image_paths)
    processed_count = 0
    total_time = 0  # Total time for processing images

    with ProcessPoolExecutor(max_workers=NUM_THREADS) as executor:
        for processing_time in executor.map(resize_image, [(path, resolution, OUTPUT_ROOT, save_as_png) for path in image_paths]):
            processed_count += 1
            if processing_time is not None:
                total_time += processing_time
            average_time = total_time / processed_count * 1000  # Convert to milliseconds
            print(f"Processed {processed_count}/{total_images} images for resolution {resolution[0]}x{resolution[1]}... Average processing time per image: {average_time:.2f} ms")

if __name__ == "__main__":
    for resolution, folder in DATA:
        process_folder(folder, resolution, Save_PNG)
    print("Processing complete!")