Skip to content

Instantly share code, notes, and snippets.

@simias
Created October 6, 2024 18:11
Show Gist options
  • Save simias/bd362b87b6d80802658ca7f24a79df72 to your computer and use it in GitHub Desktop.
Save simias/bd362b87b6d80802658ca7f24a79df72 to your computer and use it in GitHub Desktop.
Naive script to detect the cell edges in manga
#!/usr/bin/env python
import sys
import random
from PIL import Image, ImageDraw
def detect(source, target):
manga = Image.open(source)
manga = manga.convert("RGB")
w, h = manga.size;
detect = Image.new("RGB", (w, h), color=(0, 0, 0))
manga_px = manga.load()
detect_px = detect.load()
# Flood-fill border
candidates = [ (0, 0) ]
while candidates:
x, y = candidates.pop()
dr, dg, db = detect_px[x, y]
if dr != 0:
# Already processed
continue
l = to_greyscale(*manga_px[x, y])
if l < 250:
# Too dark, consider it an edge
detect_px[x, y] = (255, 1, 1)
continue
# Fill
detect_px[x, y] = (1, 1, 255)
if x > 0:
candidates.append((x - 1, y))
if x < w - 1:
candidates.append((x + 1, y))
if y > 0:
candidates.append((x, y - 1))
if y < h - 1:
candidates.append((x, y + 1))
areas = count_areas((w, h), detect_px)
for (n, (center, npix)) in enumerate(areas):
pc = round((npix * 100) / (w * h))
draw_text(detect, center, (200, 200, 200), f"#{n + 1}: {npix}px ({pc}%)")
detect.save(target)
def draw_text(image, center, color, text):
draw = ImageDraw.Draw(image)
bbox = draw.textbbox((0, 0), text)
text_width = bbox[2] - bbox[0]
text_height = bbox[3] - bbox[1]
x, y = center
centered_x = x - text_width // 2
centered_y = y - text_height // 2
draw.text((centered_x, centered_y), text, fill=color)
def count_areas(dim, detect_px):
w, h = dim
narea = 0
area_thshold = (w * h) * 0.05;
areas = []
for y in range(h):
for x in range(w):
r, g, b = detect_px[x, y]
if r != 0:
# Already processed
continue
r = random.randint(1, 200)
g = random.randint(1, 200)
b = random.randint(1, 200)
npix, min_x, max_x, min_y, max_y = flood_fill((w, h),
detect_px,
(x, y),
(r, g, b))
if npix > area_thshold:
center = (int((min_x + max_x) / 2), int((min_y + max_y) / 2))
areas.append((center, npix))
return areas
def flood_fill(dim, detect_px, start, col):
w, h = dim
min_x, min_y = start
max_x, max_y = start
npix = 0
candidates = [ start ]
while candidates:
x, y = candidates.pop()
dr, dg, db = detect_px[x, y]
if dr != 0:
# Already processed
continue
if x < min_x:
min_x = x
if y < min_y:
min_y = y
if x > max_x:
max_x = x
if y > max_y:
max_y = y
npix += 1
detect_px[x, y] = col
if x > 0:
candidates.append((x - 1, y))
if x < w - 1:
candidates.append((x + 1, y))
if y > 0:
candidates.append((x, y - 1))
if y < h - 1:
candidates.append((x, y + 1))
return npix, min_x, max_x, min_y, max_y
def to_greyscale(r, g, b):
return int(0.299 * r + 0.587 * g + 0.114 * b)
if __name__ == "__main__":
if len(sys.argv) != 3:
print(f"Usage: {sys.argv[0]} <source_image> <output_image>")
sys.exit(1)
detect(sys.argv[1], sys.argv[2])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment