jebin2 commited on
Commit
f0c23ec
Β·
1 Parent(s): d00f531

easy panel ext added

Browse files
comic_panel_extractor/config.py CHANGED
@@ -4,6 +4,7 @@ from dataclasses import dataclass
4
  class Config:
5
  """Configuration settings for the comic-to-video pipeline."""
6
  input_path: str = ""
 
7
  output_folder: str = "temp_dir"
8
  distance_threshold: int = 70
9
  vertical_threshold: int = 30
 
4
  class Config:
5
  """Configuration settings for the comic-to-video pipeline."""
6
  input_path: str = ""
7
+ black_overlay_input_path: str = ""
8
  output_folder: str = "temp_dir"
9
  distance_threshold: int = 70
10
  vertical_threshold: int = 30
comic_panel_extractor/image_processor.py CHANGED
@@ -11,11 +11,11 @@ class ImageProcessor:
11
  def __init__(self, config: Config):
12
  self.config = config
13
 
14
- def mask_text_regions(self, bboxes: List[List[int]], output_filename: str = "1_text_removed.jpg", color: Tuple[int, int, int] = (0, 0, 0)) -> str:
15
  """Mask text regions in the image to reduce panel extraction noise."""
16
- image = cv2.imread(self.config.input_path)
17
  if image is None:
18
- raise FileNotFoundError(f"Could not load image: {self.config.input_path}")
19
 
20
  for bbox in bboxes:
21
  x1, y1, x2, y2 = bbox
@@ -26,16 +26,17 @@ class ImageProcessor:
26
  print(f"βœ… Text-masked image saved to: {output_path}")
27
  return str(output_path)
28
 
29
- def preprocess_image(self, masked_image_path) -> Tuple[str, str, str]:
30
  """Preprocess image for panel extraction."""
31
- image = cv2.imread(masked_image_path)
32
  if image is None:
33
- raise FileNotFoundError(f"Could not load image: {masked_image_path}")
34
 
35
  # Convert to grayscale and binary
36
  gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
37
  _, binary = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY_INV)
38
- binary, is_inverted = self.invert_if_black_dominates(binary)
 
39
 
40
  if not is_inverted:
41
  # Dilate to strengthen borders
 
11
  def __init__(self, config: Config):
12
  self.config = config
13
 
14
+ def mask_text_regions(self, input_path, bboxes: List[List[int]], output_filename: str = "1_text_removed.jpg", color: Tuple[int, int, int] = (0, 0, 0)) -> str:
15
  """Mask text regions in the image to reduce panel extraction noise."""
16
+ image = cv2.imread(input_path)
17
  if image is None:
18
+ raise FileNotFoundError(f"Could not load image: {input_path}")
19
 
20
  for bbox in bboxes:
21
  x1, y1, x2, y2 = bbox
 
26
  print(f"βœ… Text-masked image saved to: {output_path}")
27
  return str(output_path)
28
 
29
+ def preprocess_image(self, processed_image_path) -> Tuple[str, str, str]:
30
  """Preprocess image for panel extraction."""
31
+ image = cv2.imread(processed_image_path)
32
  if image is None:
33
+ raise FileNotFoundError(f"Could not load image: {processed_image_path}")
34
 
35
  # Convert to grayscale and binary
36
  gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
37
  _, binary = cv2.threshold(gray, 200, 255, cv2.THRESH_BINARY_INV)
38
+ is_inverted = False
39
+ # binary, is_inverted = self.invert_if_black_dominates(binary)
40
 
41
  if not is_inverted:
42
  # Dilate to strengthen borders
comic_panel_extractor/main.py CHANGED
@@ -3,6 +3,7 @@ from .config import Config
3
  from .image_processor import ImageProcessor
4
  from .panel_extractor import PanelData
5
  from .panel_extractor import PanelExtractor
 
6
 
7
  from typing import List, Tuple
8
  from pathlib import Path
@@ -26,13 +27,16 @@ class ComicPanelExtractor:
26
  def extract_panels_from_comic(self) -> Tuple[List[np.ndarray], List[PanelData]]:
27
  """Complete pipeline to extract panels from a comic image."""
28
  print(f"Starting panel extraction for: {self.config.input_path}")
29
-
 
 
 
30
  # Step 1: Detect and mask text regions
31
  text_bubbles = self._detect_text_bubbles()
32
- masked_image_path = self.image_processor.mask_text_regions([bubble["bbox"] for bubble in text_bubbles])
33
-
34
  # Step 2: Preprocess image
35
- _, _, processed_image_path, is_inverted = self.image_processor.preprocess_image(masked_image_path)
36
 
37
  if is_inverted:
38
  # Step 3: Remove Inner Sketch
 
3
  from .image_processor import ImageProcessor
4
  from .panel_extractor import PanelData
5
  from .panel_extractor import PanelExtractor
6
+ from .panel_segmentation import main as main_panel_segmentation
7
 
8
  from typing import List, Tuple
9
  from pathlib import Path
 
27
  def extract_panels_from_comic(self) -> Tuple[List[np.ndarray], List[PanelData]]:
28
  """Complete pipeline to extract panels from a comic image."""
29
  print(f"Starting panel extraction for: {self.config.input_path}")
30
+
31
+ processed_image_path = main_panel_segmentation(self.config.output_folder, self.config.input_path, self.config.input_path)
32
+ self.config.black_overlay_input_path = processed_image_path
33
+
34
  # Step 1: Detect and mask text regions
35
  text_bubbles = self._detect_text_bubbles()
36
+ processed_image_path = self.image_processor.mask_text_regions(processed_image_path, [bubble["bbox"] for bubble in text_bubbles])
37
+
38
  # Step 2: Preprocess image
39
+ _, _, processed_image_path, is_inverted = self.image_processor.preprocess_image(processed_image_path)
40
 
41
  if is_inverted:
42
  # Step 3: Remove Inner Sketch
comic_panel_extractor/panel_extractor.py CHANGED
@@ -4,6 +4,7 @@ from .config import Config
4
  import numpy as np
5
  import cv2
6
  from dataclasses import dataclass
 
7
 
8
  @dataclass
9
  class PanelData:
@@ -218,49 +219,98 @@ class PanelExtractor:
218
 
219
  return [(x1, y1, x2, y2) for x1, y1, x2, y2 in panels
220
  if (x2 - x1) >= min_allowed_width and (y2 - y1) >= min_allowed_height]
221
-
222
- def _save_panels(self, panels: List[Tuple[int, int, int, int]],
223
- original: np.ndarray, width: int, height: int) -> Tuple[List[np.ndarray], List[PanelData]]:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  """Save panel images and return panel data."""
225
  visual_output = original.copy()
226
  panel_images = []
227
  panel_data = []
228
  all_panel_path = []
229
-
 
 
 
 
 
 
230
  for idx, (x1, y1, x2, y2) in enumerate(panels, 1):
231
- # Extract panel image
232
- panel_img = original[y1:y2, x1:x2]
233
 
234
- # Check if more than 90% pixels are black
235
  gray = cv2.cvtColor(panel_img, cv2.COLOR_BGR2GRAY)
236
- black_pixels = np.sum(gray < 30) # pixel intensity <30 considered black
237
  total_pixels = gray.size
238
  black_ratio = black_pixels / total_pixels
239
 
240
- if black_ratio > 0.9:
241
  print(f"⚠️ Skipping panel #{idx} β€” {round(black_ratio * 100, 2)}% black")
242
  continue
 
 
243
 
244
- # Add to results
 
 
 
 
 
 
 
 
245
  panel_images.append(panel_img)
246
-
247
- # Create panel data
248
  panel_info = PanelData.from_coordinates(x1, y1, x2, y2)
249
  panel_data.append(panel_info)
250
-
251
- # Save panel image
252
- panel_path = f'{self.config.output_folder}/panel_{idx}_{(x1, y1, x2, y2)}.jpg'
253
  cv2.imwrite(str(panel_path), panel_img)
254
  all_panel_path.append(panel_path)
255
-
256
- # Draw visualization
257
  cv2.rectangle(visual_output, (x1, y1), (x2, y2), (0, 255, 0), 2)
258
  cv2.putText(visual_output, f"#{idx}", (x1+5, y1+25),
259
- cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
260
-
261
- # Save visualization
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
262
  visual_path = f'{self.config.output_folder}/panels_visualization.jpg'
263
  cv2.imwrite(str(visual_path), visual_output)
264
-
265
  print(f"βœ… Extracted {len(panel_images)} panels after filtering.")
266
- return panel_images, panel_data, all_panel_path
 
4
  import numpy as np
5
  import cv2
6
  from dataclasses import dataclass
7
+ import os
8
 
9
  @dataclass
10
  class PanelData:
 
219
 
220
  return [(x1, y1, x2, y2) for x1, y1, x2, y2 in panels
221
  if (x2 - x1) >= min_allowed_width and (y2 - y1) >= min_allowed_height]
222
+
223
+ def count_panel_files(self, folder_path: str) -> int:
224
+ """
225
+ Count the number of files in a folder that start with 'panel_'.
226
+
227
+ Args:
228
+ folder_path: Path to the folder to search.
229
+
230
+ Returns:
231
+ Number of files starting with 'panel_'.
232
+ """
233
+ if not os.path.exists(folder_path):
234
+ print(f"Folder does not exist: {folder_path}")
235
+ return 0
236
+
237
+ return len([
238
+ fname for fname in os.listdir(folder_path)
239
+ if fname.startswith("panel_") and os.path.isfile(os.path.join(folder_path, fname))
240
+ ])
241
+
242
+ def _save_panels(self, panels: List[Tuple[int, int, int, int]], original: np.ndarray, width: int, height: int) -> Tuple[List[np.ndarray], List[PanelData], List[str]]:
243
  """Save panel images and return panel data."""
244
  visual_output = original.copy()
245
  panel_images = []
246
  panel_data = []
247
  all_panel_path = []
248
+
249
+ panel_idx = self.count_panel_files(self.config.output_folder)
250
+ black_overlay_input = cv2.imread(self.config.black_overlay_input_path)
251
+
252
+ image_area = width * height
253
+ maybe_full_page_panel = None # Store panel that is β‰₯90% of the page
254
+
255
  for idx, (x1, y1, x2, y2) in enumerate(panels, 1):
256
+ # Extract panel image from black_overlay_input
257
+ panel_img = black_overlay_input[y1:y2, x1:x2]
258
 
259
+ # Check for mostly black content
260
  gray = cv2.cvtColor(panel_img, cv2.COLOR_BGR2GRAY)
261
+ black_pixels = np.sum(gray < 30)
262
  total_pixels = gray.size
263
  black_ratio = black_pixels / total_pixels
264
 
265
+ if black_ratio > 0.8:
266
  print(f"⚠️ Skipping panel #{idx} β€” {round(black_ratio * 100, 2)}% black")
267
  continue
268
+ else:
269
+ print(f"βœ… Black ratio panel #{idx} β€” {round(black_ratio * 100, 2)}% black")
270
 
271
+ # Check if this panel is β‰₯90% of the full image
272
+ panel_area = (x2 - x1) * (y2 - y1)
273
+ if panel_area >= 0.9 * image_area:
274
+ print(f"⚠️ Panel #{idx} covers β‰₯90% of the image β€” marked for potential use only")
275
+ maybe_full_page_panel = (idx, (x1, y1, x2, y2))
276
+ continue # Skip for now
277
+
278
+ # Save valid smaller panel
279
+ panel_img = visual_output[y1:y2, x1:x2]
280
  panel_images.append(panel_img)
 
 
281
  panel_info = PanelData.from_coordinates(x1, y1, x2, y2)
282
  panel_data.append(panel_info)
283
+
284
+ panel_idx += 1
285
+ panel_path = f'{self.config.output_folder}/panel_{panel_idx}_{(x1, y1, x2, y2)}.jpg'
286
  cv2.imwrite(str(panel_path), panel_img)
287
  all_panel_path.append(panel_path)
288
+
 
289
  cv2.rectangle(visual_output, (x1, y1), (x2, y2), (0, 255, 0), 2)
290
  cv2.putText(visual_output, f"#{idx}", (x1+5, y1+25),
291
+ cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
292
+
293
+ # If no valid panels were saved, and we had a full-page one, save it
294
+ if not panel_images and maybe_full_page_panel and panel_idx == 0:
295
+ idx, (x1, y1, x2, y2) = maybe_full_page_panel
296
+ panel_img = visual_output[y1:y2, x1:x2]
297
+ panel_images.append(panel_img)
298
+ panel_info = PanelData.from_coordinates(x1, y1, x2, y2)
299
+ panel_data.append(panel_info)
300
+
301
+ panel_idx += 1
302
+ panel_path = f'{self.config.output_folder}/panel_{panel_idx}_{(x1, y1, x2, y2)}.jpg'
303
+ cv2.imwrite(str(panel_path), panel_img)
304
+ all_panel_path.append(panel_path)
305
+
306
+ cv2.rectangle(visual_output, (x1, y1), (x2, y2), (255, 0, 0), 2)
307
+ cv2.putText(visual_output, f"#full", (x1+5, y1+25),
308
+ cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 0, 0), 2)
309
+ print(f"βœ… Saved full-page panel as fallback")
310
+
311
+ # Save final visualization
312
  visual_path = f'{self.config.output_folder}/panels_visualization.jpg'
313
  cv2.imwrite(str(visual_path), visual_output)
314
+
315
  print(f"βœ… Extracted {len(panel_images)} panels after filtering.")
316
+ return panel_images, panel_data, all_panel_path
comic_panel_extractor/panel_segmentation.py ADDED
@@ -0,0 +1,240 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import numpy as np
3
+ from PIL import Image, ImageDraw
4
+ import imageio.v2 as imageio # Fix for imageio warning
5
+ from skimage.color import rgb2gray
6
+ from skimage.feature import canny
7
+ from skimage import measure
8
+ from scipy import ndimage as ndi
9
+ import re
10
+ from skimage.morphology import remove_small_holes
11
+
12
+
13
+ def extract_fully_white_panels(
14
+ original_image: np.ndarray,
15
+ segmentation_mask: np.ndarray,
16
+ output_dir: str = "panel_output",
17
+ debug_region_dir: str = "panel_debug_regions",
18
+ min_area_ratio: float = 0.05,
19
+ min_width_ratio: float = 0.05,
20
+ min_height_ratio: float = 0.05,
21
+ save_debug: bool = True
22
+ ):
23
+ """
24
+ Extract fully white panels from a segmented image.
25
+
26
+ Args:
27
+ original_image: Original RGB image as numpy array
28
+ segmentation_mask: Binary segmentation mask
29
+ output_dir: Directory to save extracted panels
30
+ debug_region_dir: Directory to save debug images
31
+ min_area_ratio: Minimum area ratio threshold
32
+ min_width_ratio: Minimum width ratio threshold
33
+ min_height_ratio: Minimum height ratio threshold
34
+ save_debug: Whether to save debug images
35
+
36
+ Returns:
37
+ List of saved panel file paths
38
+ """
39
+ os.makedirs(output_dir, exist_ok=True)
40
+ if save_debug:
41
+ os.makedirs(debug_region_dir, exist_ok=True)
42
+
43
+ img_h, img_w = segmentation_mask.shape
44
+ image_area = img_h * img_w
45
+
46
+ orig_pil = Image.fromarray(original_image)
47
+ labeled_mask = measure.label(segmentation_mask)
48
+ regions = measure.regionprops(labeled_mask)
49
+
50
+ saved_panels = []
51
+ accepted_boxes = []
52
+ panel_idx = 0
53
+
54
+ for idx, region in enumerate(regions):
55
+ minr, minc, maxr, maxc = region.bbox
56
+ w = maxc - minc
57
+ h = maxr - minr
58
+ area = w * h
59
+ crop_box = (minc, minr, maxc, maxr)
60
+ crop_name_prefix = f"region_{idx+1}"
61
+
62
+ # Crops
63
+ cropped_img = orig_pil.crop(crop_box)
64
+ cropped_mask = segmentation_mask[minr:maxr, minc:maxc]
65
+ # Fix for Pillow warning: Remove mode parameter
66
+ mask_pil = Image.fromarray((cropped_mask * 255).astype('uint8'))
67
+
68
+ # 1. Threshold check
69
+ if (
70
+ area < min_area_ratio * image_area or
71
+ w < min_width_ratio * img_w or
72
+ h < min_height_ratio * img_h
73
+ ):
74
+ if save_debug:
75
+ cropped_img.save(os.path.join(debug_region_dir, f"{crop_name_prefix}_too_small_orig.jpg"))
76
+ mask_pil.save(os.path.join(debug_region_dir, f"{crop_name_prefix}_too_small_mask.jpg"))
77
+ continue
78
+
79
+ # 2. Check if region is mostly white (allow small % of black)
80
+ black_pixel_count = np.count_nonzero(region.image == 0)
81
+ total_pixels = region.image.size
82
+ black_ratio = black_pixel_count / total_pixels
83
+
84
+ if black_ratio > 0.02: # Allow up to 1% black pixels
85
+ print(f"❌ Black ratio panel #{idx} β€” {round(black_ratio * 100, 2)}% black")
86
+ # Save debug info if desired
87
+ if save_debug:
88
+ debug_region_dir_specific = os.path.join(output_dir, f"region_{idx}_skipped_black_inside")
89
+ os.makedirs(debug_region_dir_specific, exist_ok=True)
90
+
91
+ # Save cropped mask
92
+ cropped_mask = segmentation_mask[minr:maxr, minc:maxc]
93
+ # Fix for Pillow warning: Remove mode parameter
94
+ mask_pil = Image.fromarray((cropped_mask * 255).astype("uint8"))
95
+ mask_pil.save(os.path.join(debug_region_dir_specific, f"region_{idx}_mask.jpg"))
96
+
97
+ # Highlight black pixels in red and zoom
98
+ highlighted = np.stack([cropped_mask]*3, axis=-1) * 255
99
+ highlighted[cropped_mask == 0] = [255, 0, 0]
100
+ highlighted_zoom = Image.fromarray(highlighted.astype('uint8')).resize(
101
+ (highlighted.shape[1]*4, highlighted.shape[0]*4), resample=Image.NEAREST
102
+ )
103
+ highlighted_zoom.save(os.path.join(debug_region_dir_specific, f"region_{idx}_highlight_black_zoomed.jpg"))
104
+
105
+ continue
106
+
107
+ # 3. Save valid panel with bbox coordinates in filename
108
+ bbox_str = f"({minc}, {minr}, {maxc}, {maxr})"
109
+ panel_idx = panel_idx + 1
110
+ panel_path = os.path.join(output_dir, f"panel_{panel_idx}_{bbox_str}.jpg")
111
+ cropped_img.save(panel_path)
112
+ saved_panels.append(panel_path)
113
+ accepted_boxes.append((minc, minr, maxc, maxr))
114
+
115
+ if save_debug:
116
+ cropped_img.save(os.path.join(debug_region_dir, f"{crop_name_prefix}_saved_orig.jpg"))
117
+ mask_pil.save(os.path.join(debug_region_dir, f"{crop_name_prefix}_saved_mask.jpg"))
118
+
119
+ # 4. Debug image with accepted boxes
120
+ if save_debug:
121
+ debug_img = orig_pil.copy()
122
+ draw = ImageDraw.Draw(debug_img)
123
+ for (x1, y1, x2, y2) in accepted_boxes:
124
+ draw.rectangle([x1, y1, x2, y2], outline="red", width=3)
125
+ debug_img.save(os.path.join(output_dir, "debug_all_saved_panels.jpg"))
126
+
127
+ return saved_panels
128
+
129
+
130
+ def create_segmentation_mask(image: np.ndarray, save_debug: bool = True) -> np.ndarray:
131
+ """
132
+ Create segmentation mask from image using edge detection and hole filling.
133
+
134
+ Args:
135
+ image: Input RGB image as numpy array
136
+ save_debug: Whether to save intermediate processing steps
137
+
138
+ Returns:
139
+ Binary segmentation mask
140
+ """
141
+ if save_debug:
142
+ os.makedirs("panel_debug_steps", exist_ok=True)
143
+ Image.fromarray(image).save("panel_debug_steps/step1_original.jpg")
144
+
145
+ # Convert to grayscale
146
+ grayscale = rgb2gray(image)
147
+ if save_debug:
148
+ gray_uint8 = (grayscale * 255).astype('uint8')
149
+ # Fix for Pillow warning: Remove mode parameter
150
+ Image.fromarray(gray_uint8).save("panel_debug_steps/step2_grayscale.jpg")
151
+
152
+ # Edge detection
153
+ edges = canny(grayscale)
154
+ if save_debug:
155
+ edges_uint8 = (edges * 255).astype('uint8')
156
+ # Fix for Pillow warning: Remove mode parameter
157
+ Image.fromarray(edges_uint8).save("panel_debug_steps/step3_edges.jpg")
158
+
159
+ # Fill holes in edges
160
+ segmentation = ndi.binary_fill_holes(edges)
161
+
162
+ # βœ… Remove small black clusters (holes in white regions)
163
+ segmentation_cleaned = remove_small_holes(segmentation, area_threshold=500) # adjust threshold as needed
164
+
165
+ if save_debug:
166
+ segmentation_uint8 = (segmentation_cleaned * 255).astype('uint8')
167
+ Image.fromarray(segmentation_uint8).save("panel_debug_steps/step4_segmentation_filled.jpg")
168
+
169
+ return segmentation_cleaned
170
+
171
+
172
+ def create_image_with_panels_removed(
173
+ original_image: np.ndarray,
174
+ segmentation_mask: np.ndarray,
175
+ output_folder: str,
176
+ output_path: str,
177
+ save_debug: True
178
+ ) -> None:
179
+ """
180
+ Create a version of the original image with detected panels blacked out.
181
+
182
+ Args:
183
+ original_image: Original RGB image as numpy array
184
+ segmentation_mask: Binary segmentation mask
185
+ output_path: Path to save the modified image
186
+ """
187
+ # Get panel information
188
+ saved_panels = extract_fully_white_panels(
189
+ original_image=original_image,
190
+ segmentation_mask=segmentation_mask,
191
+ output_dir=output_folder,
192
+ debug_region_dir="panel_debug_regions",
193
+ save_debug=save_debug
194
+ )
195
+
196
+ # Create modified image
197
+ im_no_panels = Image.fromarray(original_image.copy())
198
+ draw = ImageDraw.Draw(im_no_panels)
199
+
200
+ # Get regions and black them out
201
+ labeled_mask = measure.label(segmentation_mask)
202
+ regions = measure.regionprops(labeled_mask)
203
+ pattern = re.compile(r"panel_\d+_\((\d+), (\d+), (\d+), (\d+)\)\.jpg")
204
+
205
+ for panel_path in saved_panels:
206
+ # Extract panel index from filename with bbox format
207
+ panel_name = os.path.basename(panel_path)
208
+ match = pattern.match(panel_name)
209
+ minc, minr, maxc, maxr = map(int, match.groups())
210
+
211
+ draw.rectangle([minc, minr, maxc, maxr], fill=(0, 0, 0))
212
+
213
+ # Save the result
214
+ im_no_panels.save(output_path)
215
+
216
+
217
+ def main(output_folder, input_image_path, original_image_path):
218
+ """Main execution function."""
219
+ # Load the input image
220
+ image = imageio.imread(input_image_path)
221
+ original_image = imageio.imread(original_image_path)
222
+ save_debug = True
223
+ # Create segmentation mask
224
+ segmentation_mask = create_segmentation_mask(image, save_debug=save_debug)
225
+
226
+ pre_process_path = f"{output_folder}/original_with_panels_removed.jpg"
227
+ # Create image with panels removed
228
+ create_image_with_panels_removed(
229
+ original_image=original_image,
230
+ segmentation_mask=segmentation_mask,
231
+ output_folder=output_folder,
232
+ output_path=pre_process_path,
233
+ save_debug=save_debug
234
+ )
235
+
236
+ return pre_process_path
237
+
238
+
239
+ if __name__ == "__main__":
240
+ main('panel_output', 'test7.jpg', 'test7.jpg')