Spaces:
Running
Running
made thin border
Browse files- .gitignore +4 -1
- comic_panel_extractor/cli.py +0 -2
- comic_panel_extractor/image_processor.py +32 -1
- comic_panel_extractor/main.py +6 -4
- comic_panel_extractor/panel_extractor.py +2 -2
- requirements.txt +2 -1
.gitignore
CHANGED
|
@@ -205,4 +205,7 @@ cython_debug/
|
|
| 205 |
marimo/_static/
|
| 206 |
marimo/_lsp/
|
| 207 |
__marimo__/
|
| 208 |
-
temp_dir
|
|
|
|
|
|
|
|
|
|
|
|
| 205 |
marimo/_static/
|
| 206 |
marimo/_lsp/
|
| 207 |
__marimo__/
|
| 208 |
+
temp_dir
|
| 209 |
+
input.jpg
|
| 210 |
+
comic_panel_extractor/api_outputs/
|
| 211 |
+
temp.py
|
comic_panel_extractor/cli.py
CHANGED
|
@@ -68,8 +68,6 @@ Examples:
|
|
| 68 |
for key, value in config_data.items():
|
| 69 |
if hasattr(config, key):
|
| 70 |
setattr(config, key, value)
|
| 71 |
-
if args.verbose:
|
| 72 |
-
print(f"📄 Loaded configuration from: {args.config}")
|
| 73 |
except Exception as e:
|
| 74 |
print(f"⚠️ Warning: Could not load config file: {e}", file=sys.stderr)
|
| 75 |
|
|
|
|
| 68 |
for key, value in config_data.items():
|
| 69 |
if hasattr(config, key):
|
| 70 |
setattr(config, key, value)
|
|
|
|
|
|
|
| 71 |
except Exception as e:
|
| 72 |
print(f"⚠️ Warning: Could not load config file: {e}", file=sys.stderr)
|
| 73 |
|
comic_panel_extractor/image_processor.py
CHANGED
|
@@ -50,9 +50,40 @@ class ImageProcessor:
|
|
| 50 |
cv2.imwrite(str(dilated_path), dilated)
|
| 51 |
|
| 52 |
return str(gray_path), str(binary_path), str(dilated_path)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 53 |
|
| 54 |
def clean_dilated_image(self, dilated_path: str,
|
| 55 |
-
output_filename: str = "
|
| 56 |
max_neighbors: int = 2) -> str:
|
| 57 |
"""Clean dilated image by thinning thick borders."""
|
| 58 |
dilated = cv2.imread(dilated_path, cv2.IMREAD_GRAYSCALE)
|
|
|
|
| 50 |
cv2.imwrite(str(dilated_path), dilated)
|
| 51 |
|
| 52 |
return str(gray_path), str(binary_path), str(dilated_path)
|
| 53 |
+
|
| 54 |
+
def thin_image_borders(self, processed_image_path: str, output_filename: str = "5_thin_border.jpg") -> str:
|
| 55 |
+
"""
|
| 56 |
+
Clean dilated image by thinning thick borders and removing hanging clusters.
|
| 57 |
+
"""
|
| 58 |
+
from skimage.morphology import skeletonize, remove_small_objects
|
| 59 |
+
from skimage.measure import label
|
| 60 |
+
|
| 61 |
+
# Load image
|
| 62 |
+
img = cv2.imread(processed_image_path, cv2.IMREAD_GRAYSCALE)
|
| 63 |
+
_, binary = cv2.threshold(img, 128, 1, cv2.THRESH_BINARY_INV) # invert, binary mask (0,1)
|
| 64 |
+
|
| 65 |
+
# Skeletonize
|
| 66 |
+
skeleton = skeletonize(binary).astype(np.uint8)
|
| 67 |
+
|
| 68 |
+
# Remove small hanging clusters
|
| 69 |
+
labeled = label(skeleton, connectivity=2)
|
| 70 |
+
cleaned = remove_small_objects(labeled, min_size=150) # Adjust min_size for more/less pruning
|
| 71 |
+
|
| 72 |
+
# Convert back to 0–255 uint8 image
|
| 73 |
+
final = (cleaned > 0).astype(np.uint8) * 255
|
| 74 |
+
|
| 75 |
+
# Invert back if needed
|
| 76 |
+
result = 255 - final
|
| 77 |
+
|
| 78 |
+
# Save
|
| 79 |
+
output_path = f'{self.config.output_folder}/{output_filename}'
|
| 80 |
+
cv2.imwrite(output_path, result)
|
| 81 |
+
print(f"✅ Cleaned and thinned image saved to: {output_path}")
|
| 82 |
+
return str(output_path)
|
| 83 |
+
|
| 84 |
|
| 85 |
def clean_dilated_image(self, dilated_path: str,
|
| 86 |
+
output_filename: str = "6_dilated_cleaned.jpg",
|
| 87 |
max_neighbors: int = 2) -> str:
|
| 88 |
"""Clean dilated image by thinning thick borders."""
|
| 89 |
dilated = cv2.imread(dilated_path, cv2.IMREAD_GRAYSCALE)
|
comic_panel_extractor/main.py
CHANGED
|
@@ -32,14 +32,16 @@ class ComicPanelExtractor:
|
|
| 32 |
masked_image_path = self.image_processor.mask_text_regions([bubble["bbox"] for bubble in text_bubbles])
|
| 33 |
|
| 34 |
# Step 2: Preprocess image
|
| 35 |
-
_, _,
|
| 36 |
-
|
|
|
|
|
|
|
| 37 |
# Step 3: Clean dilated image
|
| 38 |
-
|
| 39 |
|
| 40 |
# Step 4: Extract panels
|
| 41 |
panel_images, panel_data, all_panel_path = self.panel_extractor.extract_panels(
|
| 42 |
-
|
| 43 |
)
|
| 44 |
|
| 45 |
return panel_images, panel_data, all_panel_path
|
|
|
|
| 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 = self.image_processor.preprocess_image(masked_image_path)
|
| 36 |
+
|
| 37 |
+
# Step 3: Thin border line
|
| 38 |
+
processed_image_path = self.image_processor.thin_image_borders(processed_image_path)
|
| 39 |
# Step 3: Clean dilated image
|
| 40 |
+
# processed_image_path = self.image_processor.clean_dilated_image(processed_image_path)
|
| 41 |
|
| 42 |
# Step 4: Extract panels
|
| 43 |
panel_images, panel_data, all_panel_path = self.panel_extractor.extract_panels(
|
| 44 |
+
processed_image_path, min_width_ratio=0.1
|
| 45 |
)
|
| 46 |
|
| 47 |
return panel_images, panel_data, all_panel_path
|
comic_panel_extractor/panel_extractor.py
CHANGED
|
@@ -102,7 +102,7 @@ class PanelExtractor:
|
|
| 102 |
width = dilated.shape[1]
|
| 103 |
row_slice = dilated[y1:y2, :]
|
| 104 |
col_black_percentage = np.sum(row_slice == 0, axis=0) / (y2 - y1) * 100
|
| 105 |
-
|
| 106 |
# Find column gutters
|
| 107 |
col_gutters = []
|
| 108 |
in_gutter = False
|
|
@@ -169,7 +169,7 @@ class PanelExtractor:
|
|
| 169 |
panel_data.append(panel_info)
|
| 170 |
|
| 171 |
# Save panel image
|
| 172 |
-
panel_path = f'{self.config.output_folder}/panel_{idx}.jpg'
|
| 173 |
cv2.imwrite(str(panel_path), panel_img)
|
| 174 |
all_panel_path.append(panel_path)
|
| 175 |
|
|
|
|
| 102 |
width = dilated.shape[1]
|
| 103 |
row_slice = dilated[y1:y2, :]
|
| 104 |
col_black_percentage = np.sum(row_slice == 0, axis=0) / (y2 - y1) * 100
|
| 105 |
+
|
| 106 |
# Find column gutters
|
| 107 |
col_gutters = []
|
| 108 |
in_gutter = False
|
|
|
|
| 169 |
panel_data.append(panel_info)
|
| 170 |
|
| 171 |
# Save panel image
|
| 172 |
+
panel_path = f'{self.config.output_folder}/panel_{idx}_{(x1, y1, x2, y2)}.jpg'
|
| 173 |
cv2.imwrite(str(panel_path), panel_img)
|
| 174 |
all_panel_path.append(panel_path)
|
| 175 |
|
requirements.txt
CHANGED
|
@@ -5,4 +5,5 @@ easyocr
|
|
| 5 |
fastapi
|
| 6 |
uvicorn
|
| 7 |
python-multipart
|
| 8 |
-
jinja2
|
|
|
|
|
|
| 5 |
fastapi
|
| 6 |
uvicorn
|
| 7 |
python-multipart
|
| 8 |
+
jinja2
|
| 9 |
+
scikit-image
|