avans06 commited on
Commit
5f31bcd
·
1 Parent(s): 93497a7

refactor: Replace local remove_border with image-panel-border-cleaner package.

Browse files
Files changed (3) hide show
  1. app.py +2 -1
  2. image_processing/panel.py +0 -160
  3. requirements.txt +3 -1
app.py CHANGED
@@ -14,7 +14,8 @@ import tempfile
14
  import shutil
15
  from tqdm import tqdm
16
 
17
- from image_processing.panel import generate_panel_blocks, generate_panel_blocks_by_ai, remove_border
 
18
 
19
  # --- UI Description ---
20
  DESCRIPTION = """
 
14
  import shutil
15
  from tqdm import tqdm
16
 
17
+ from image_processing.panel import generate_panel_blocks, generate_panel_blocks_by_ai
18
+ from image_panel_border_cleaner import remove_border
19
 
20
  # --- UI Description ---
21
  DESCRIPTION = """
image_processing/panel.py CHANGED
@@ -547,163 +547,3 @@ def extract_panels_for_images_in_folder_by_ai(
547
  cv2.imwrite(out_path, panel)
548
  num_panels += len(panel_blocks)
549
  return (num_files, num_panels)
550
-
551
-
552
- # Ensure the thinning function is available
553
- try:
554
- # Attempt to import the thinning function from the contrib module
555
- from cv2.ximgproc import thinning
556
- except ImportError:
557
- # If opencv-contrib-python is not installed, print a warning and provide a dummy function
558
- print("Warning: cv2.ximgproc.thinning not found. Border removal might be less effective.")
559
- print("Please install 'opencv-contrib-python' via 'pip install opencv-contrib-python'")
560
- def thinning(src, thinningType=None): # Dummy function to prevent crashes
561
- return src
562
-
563
-
564
- def _find_best_border_line(roi_mask: np.ndarray, axis: int, scan_range: range) -> int:
565
- """
566
- A helper function to find the best border line along a single axis.
567
- It scans from the inside-out and returns the index of the line with the highest score.
568
-
569
- Parameters:
570
- - roi_mask: The skeletonized mask of the panel's border area.
571
- - axis: The axis to scan along (0 for vertical, 1 for horizontal).
572
- - scan_range: The range of indices to scan (defines direction and search zone).
573
-
574
- Returns:
575
- - The index of the most likely border line.
576
- """
577
- best_index, max_score = scan_range.start, -1
578
-
579
- # The total span of the search, used for normalizing the position weight.
580
- total_span = abs(scan_range.stop - scan_range.start)
581
- if total_span == 0:
582
- return best_index
583
-
584
- for i in scan_range:
585
- # Calculate continuity score based on the scan axis
586
- if axis == 1: # Horizontal scan (for top/bottom borders)
587
- continuity_score = np.count_nonzero(roi_mask[i, :])
588
- else: # Vertical scan (for left/right borders)
589
- continuity_score = np.count_nonzero(roi_mask[:, i])
590
-
591
- # Position weight increases as we move from the start (inner) to the end (outer) of the range.
592
- # This prioritizes lines closer to the physical edge of the panel.
593
- progress = abs(i - scan_range.start)
594
- position_weight = progress / total_span
595
-
596
- # Combine scores
597
- score = continuity_score * (1 + position_weight)
598
-
599
- # Update if we found a better candidate
600
- if score >= max_score:
601
- max_score, best_index = score, i
602
-
603
- return best_index
604
-
605
-
606
- def remove_border(panel_image: np.ndarray,
607
- search_zone_ratio: float = 0.25,
608
- padding: int = 5) -> np.ndarray:
609
- """
610
- Removes borders using skeletonization and weighted projection analysis.
611
- This definitive version accurately finds the innermost border line by reducing
612
- all contour lines to a single-pixel width, eliminating thickness bias from
613
- speech bubble intersections.
614
-
615
- Parameters:
616
- - panel_image: The input panel image.
617
- - search_zone_ratio: The percentage of the panel's width/height from the edge
618
- to define the search area for a border (e.g., 0.25 = 25%).
619
- - padding: Pixels to add inside the final detected border to avoid clipping art.
620
-
621
- Returns:
622
- - The cropped panel image, or the original if processing fails.
623
- """
624
- # Return original image if it's invalid or too small to process
625
- if panel_image is None or panel_image.shape[0] < 30 or panel_image.shape[1] < 30:
626
- return panel_image
627
-
628
- # --- 1. Preparation ---
629
- # Add a safe, white border to separate the panel's border from the image edge
630
- pad_size = 15
631
- padded_image = cv2.copyMakeBorder(
632
- panel_image, pad_size, pad_size, pad_size, pad_size,
633
- cv2.BORDER_CONSTANT, value=[255, 255, 255]
634
- )
635
-
636
- # Convert to grayscale and binarize to highlight non-white areas
637
- gray = cv2.cvtColor(padded_image, cv2.COLOR_BGR2GRAY)
638
- _, thresh = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY_INV)
639
-
640
- # Find the outermost contour, which should now be the panel itself
641
- contours, _ = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
642
-
643
- # If no contours are found, there's nothing to process
644
- if not contours:
645
- return panel_image
646
-
647
- # The largest contour is almost always the panel we want
648
- largest_contour = max(contours, key=cv2.contourArea)
649
- x, y, w, h = cv2.boundingRect(largest_contour)
650
-
651
- # --- 2. Create Skeletonized Mask ---
652
- # Create a mask by filling the largest contour
653
- filled_mask = np.zeros_like(gray)
654
- cv2.drawContours(filled_mask, [largest_contour], -1, 255, cv2.FILLED)
655
-
656
- # Create a hollow version of the contour to provide a clean input for skeletonization.
657
- # Use a fixed number of erosion iterations to define the thickness of the hollow ring.
658
- erosion_iterations = 5
659
- hollow_contour = cv2.subtract(filled_mask, cv2.erode(filled_mask, np.ones((3,3), np.uint8), iterations=erosion_iterations))
660
-
661
- # Perform skeletonization to reduce varied-thickness lines to a single-pixel-wide skeleton
662
- skeleton = thinning(hollow_contour)
663
-
664
- # Crop the skeleton mask to the Region of Interest (ROI) for analysis
665
- roi_mask = skeleton[y:y+h, x:x+w]
666
-
667
- # --- 3. Find Borders using the Helper Function ---
668
- # Define search zones and scan ranges for each border
669
- top_search_end = int(h * search_zone_ratio)
670
- bottom_search_start = h - top_search_end
671
- left_search_end = int(w * search_zone_ratio)
672
- right_search_start = w - left_search_end
673
-
674
- # The scan_range determines the direction (inside-out)
675
- top_range = range(top_search_end, -1, -1)
676
- bottom_range = range(bottom_search_start, h)
677
- left_range = range(left_search_end, -1, -1)
678
- right_range = range(right_search_start, w)
679
-
680
- # Call the common function for each border
681
-
682
- # --- Find Top Border ---
683
- best_top_y = _find_best_border_line(roi_mask, axis=1, scan_range=top_range)
684
- # --- Find Bottom Border ---
685
- best_bottom_y = _find_best_border_line(roi_mask, axis=1, scan_range=bottom_range)
686
- # --- Find Left Border ---
687
- best_left_x = _find_best_border_line(roi_mask, axis=0, scan_range=left_range)
688
- # --- Find Right Border ---
689
- best_right_x = _find_best_border_line(roi_mask, axis=0, scan_range=right_range)
690
-
691
- # --- 4. Final Cropping ---
692
- # Convert relative ROI coordinates back to the global coordinates of the padded image and apply padding
693
- final_x1 = x + best_left_x + padding
694
- final_y1 = y + best_top_y + padding
695
- final_x2 = x + best_right_x - padding
696
- final_y2 = y + best_bottom_y - padding
697
-
698
- # If the calculated coordinates are invalid, return the original image
699
- if final_x1 >= final_x2 or final_y1 >= final_y2:
700
- return panel_image
701
-
702
- # Crop the final result from the padded image
703
- cropped = padded_image[final_y1:final_y2, final_x1:final_x2]
704
-
705
- # Perform a final check to ensure the cropped image is not too small
706
- if cropped.shape[0] < 10 or cropped.shape[1] < 10:
707
- return panel_image
708
-
709
- return cropped
 
547
  cv2.imwrite(out_path, panel)
548
  num_panels += len(panel_blocks)
549
  return (num_files, num_panels)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
requirements.txt CHANGED
@@ -5,4 +5,6 @@ numpy
5
  opencv-contrib-python
6
  tqdm
7
  torch
8
- yolov5
 
 
 
5
  opencv-contrib-python
6
  tqdm
7
  torch
8
+ yolov5
9
+
10
+ git+https://github.com/avan06/image-panel-border-cleaner.git