initial commit

This commit is contained in:
Jiao77
2025-11-24 20:34:50 +08:00
commit 633749886e
15 changed files with 2665 additions and 0 deletions

View File

@@ -0,0 +1,79 @@
#!/usr/bin/env python3
"""
skeleton_extract.py
Extract Manhattan-style skeleton from binary layout images.
Supports optional color inversion and basic denoising.
Outputs skeleton PNG and a JSON summary with connected-component counts.
"""
import argparse
from pathlib import Path
import numpy as np
from PIL import Image
import cv2
from skimage.morphology import skeletonize
from skimage import img_as_ubyte
import json
def load_image(path, invert=False):
im = Image.open(path).convert('L')
a = np.array(im)
# auto threshold by Otsu
_, th = cv2.threshold(a, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
if invert:
th = 255 - th
return th // 255
def denoise(bin_img, kernel=3):
# simple opening/closing
k = cv2.getStructuringElement(cv2.MORPH_RECT, (kernel, kernel))
img = cv2.morphologyEx((bin_img * 255).astype('uint8'), cv2.MORPH_OPEN, k)
img = cv2.morphologyEx(img, cv2.MORPH_CLOSE, k)
return img // 255
def extract_skeleton(bin_img):
# skimage expects bool image
sk = skeletonize(bin_img > 0)
return sk.astype('uint8')
def save_png(arr, path):
im = Image.fromarray((arr * 255).astype('uint8'))
im.save(path)
def main():
p = argparse.ArgumentParser()
p.add_argument('input')
p.add_argument('outdir')
p.add_argument('--invert', action='store_true', help='Invert black/white before processing')
p.add_argument('--denoise', type=int, default=3, help='Denoise kernel size')
args = p.parse_args()
inp = Path(args.input)
out = Path(args.outdir)
out.mkdir(parents=True, exist_ok=True)
bin_img = load_image(inp, invert=args.invert)
if args.denoise and args.denoise > 0:
bin_img = denoise(bin_img, kernel=args.denoise)
sk = extract_skeleton(bin_img)
save_png(bin_img, out / (inp.stem + '_bin.png'))
save_png(sk, out / (inp.stem + '_sk.png'))
# summary
num_pixels = int(sk.sum())
components = cv2.connectedComponents((sk * 255).astype('uint8'))[0] - 1
info = {'input': str(inp), 'pixels_in_skeleton': int(num_pixels), 'components': int(components)}
with open(out / (inp.stem + '_sk.json'), 'w') as f:
json.dump(info, f, indent=2)
print('Saved:', out / (inp.stem + '_sk.png'))
if __name__ == '__main__':
main()