File size: 5,279 Bytes
cdb0658
10a7d83
f49ae1e
 
 
 
cdb0658
 
10a7d83
cdb0658
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10a7d83
cdb0658
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f49ae1e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10a7d83
 
 
f49ae1e
 
 
 
 
 
 
 
10a7d83
f49ae1e
 
 
10a7d83
f49ae1e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10a7d83
f49ae1e
10a7d83
f49ae1e
 
10a7d83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
import os
from datetime import datetime

import cv2
import matplotlib.image as mpimg
import matplotlib.pyplot as plt
import numpy as np
from PIL import Image, ImageOps
from zoneinfo import ZoneInfo


def crop_and_pad_image(image_path, threshold=20, target_size=(512, 512)):
    """
    Crop and pad an image to a square with the specified target size.

    Args:
        image_path (str): Path to the input image file.
        threshold (int): Threshold value for binarizing the image.
        target_size (tuple): Target size of the output image (width, height).

    Returns:
        PIL.Image.Image: Cropped and padded image.
    """
    try:
        # Load the image
        image = Image.open(image_path).convert("RGB")
    except Exception as e:
        raise ValueError(f"Error loading image: {str(e)}")

    # Convert the image to a NumPy array
    image_array = np.array(image)

    # Binarize the image
    binary_image_array = np.where(image_array > threshold, 1, 0).astype(np.uint8)

    # Find non-zero elements (non-black pixels)
    non_zero_indices = np.argwhere(binary_image_array)

    # Check if non-zero elements exist
    if non_zero_indices.size == 0:
        raise ValueError(f"No non-zero elements found for the image: {image_path}")

    # Get the bounding box of non-zero elements
    (y1, x1, _), (y2, x2, _) = non_zero_indices.min(0), non_zero_indices.max(0)

    # Crop the Region of Interest (ROI)
    cropped_img = image.crop((x1, y1, x2, y2))

    # Pad the image to make it a square
    squared_img = ImageOps.pad(cropped_img, target_size)

    return squared_img


def track_files(folder_path, extensions=(".jpg", ".jpeg", ".png")):
    """
    Track all the files in a folder and its subfolders.

    Args:
        folder_path (str): The path of the folder to track files in.
        extensions (tuple, optional): Tuple of file extensions to track. Default is ('.jpg', '.jpeg', '.png').

    Returns:
        list: A list containing the paths of all files in the folder and its subfolders.
    """
    # Validate folder_path
    if not os.path.isdir(folder_path):
        raise ValueError("Invalid folder path provided.")

    # Convert extensions to lowercase for case-insensitive comparison
    extensions = tuple(ext.lower() for ext in extensions)

    # Initialize file_list
    file_list = []

    # Walk through the folder and its subfolders
    for root, dirs, files in os.walk(folder_path):
        for filename in files:
            file_path = os.path.join(root, filename)
            _, extension = os.path.splitext(file_path)
            # Check if the file extension is in the list of extensions
            if extension.lower() in extensions:
                file_list.append(file_path)

    return file_list


def crop_circle_roi(image_path):
    """
    Crop the circular Region of Interest (ROI) from a fundus image.

    Args:
    - image_path (str): Path to the fundus image.

    Returns:
    - cropped_roi (numpy.ndarray): The cropped circular Region of Interest.
    """
    # Read the image
    image = cv2.imread(image_path, cv2.IMREAD_COLOR)

    # Convert the image to grayscale
    gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    # Apply thresholding to binarize the image
    _, thresholded_image = cv2.threshold(gray_image, 50, 255, cv2.THRESH_BINARY)

    # Find contours in the binary image
    contours, _ = cv2.findContours(
        thresholded_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE
    )

    # Assuming the largest contour corresponds to the ROI
    contour = max(contours, key=cv2.contourArea)

    # Get the bounding rectangle of the contour
    x, y, w, h = cv2.boundingRect(contour)

    # Crop the circular ROI using the bounding rectangle
    cropped_roi = image[y : y + h, x : x + w]

    return cropped_roi


def plot_image_grid(image_paths, roi_crop=False):
    """
    Create a grid plot with a maximum of 16 images.

    Args:
    - image_paths (list): A list of image paths to be plotted.

    Returns:
    - None
    """
    num_images = min(len(image_paths), 16)
    num_rows = (num_images - 1) // 4 + 1
    fig, axes = plt.subplots(num_rows, 4, figsize=(12, 3 * num_rows))

    for i, ax in enumerate(axes.flat):
        if i < num_images:
            if roi_crop:
                img = crop_and_pad_image(image_paths[i])
            else:
                img = mpimg.imread(image_paths[i])
            ax.imshow(img)
            ax.axis("off")
        else:
            ax.axis("off")

    plt.tight_layout()
    plt.show()


def generate_run_id(zone: ZoneInfo = ZoneInfo("Asia/Kathmandu")) -> str:
    """Generate a unique run ID using current UTC date and time.

    Args:
        zone (ZoneInfo, optional): Timezone information. Defaults to Indian Standard Time.

    Returns:
        str: A unique run ID in the format 'run-YYYY-MM-DD-HH-MM-SS'.
    """
    try:
        current_utc_time = datetime.utcnow().astimezone(zone)
        formatted_time = current_utc_time.strftime("%Y-%m-%d-%H-%M-%S")
        return f"run-{formatted_time}"
    except Exception as e:
        # Handle exceptions gracefully
        print(f"Error generating run ID: {e}")
        return None  # Or raise an exception if appropriate


if __name__ == "__main__":
    print(generate_run_id())