yum-archive/2ner
A toon shader for Unity's BIRP.
git clone https://git.yummers.dev/yum-archive/2ner
91f89f5
master
1#!/usr/bin/env python3 2 3import numpy as np 4import cv2 5import argparse 6import os 7 8def compute_sdf(img, n_px, bit_depth=8): 9 # Convert to binary image if not already 10 _, binary = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY) 11 12 # Compute distance transform for both foreground and background 13 dist_transform_fg = cv2.distanceTransform(binary, cv2.DIST_L2, 5) 14 dist_transform_bg = cv2.distanceTransform(255 - binary, cv2.DIST_L2, 5) 15 16 # Combine to get signed distance field (positive outside, negative inside) 17 sdf = dist_transform_fg - dist_transform_bg 18 19 # Clip to ±n_px range 20 sdf = np.clip(sdf, -n_px, n_px) 21 22 # Map from [-n_px, +n_px] to [0, 1] 23 sdf_normalized = (sdf + n_px) / (2 * n_px) 24 25 # Quantize to requested bit depth 26 if bit_depth == 8: 27 max_value = 255 28 dtype = np.uint8 29 elif bit_depth == 16: 30 max_value = 65535 31 dtype = np.uint16 32 else: 33 raise ValueError(f"Unsupported bit depth: {bit_depth}") 34 35 sdf_quantized = np.round(sdf_normalized * max_value).astype(dtype) 36 37 return sdf_quantized 38 39def main(): 40 parser = argparse.ArgumentParser(description='Generate SDF from black and white image with fixed range encoding') 41 parser.add_argument('input_images', nargs='+', help='Path to input image(s)') 42 parser.add_argument('--n_px', type=float, default=64.0, 43 help='Maximum distance to encode in pixels (default: 64)') 44 parser.add_argument('--bit_depth', type=int, default=8, choices=[8, 16], 45 help='Output bit depth (default: 8)') 46 args = parser.parse_args() 47 48 # Process each input image 49 for input_path in args.input_images: 50 # Get input and output paths 51 filename, ext = os.path.splitext(input_path) 52 output_path = f"{filename}-sdf{ext}" 53 54 # Read input image 55 img = cv2.imread(input_path, cv2.IMREAD_GRAYSCALE) 56 if img is None: 57 print(f"Error: Could not read image {input_path}") 58 continue 59 60 # Compute SDF with fixed range 61 sdf = compute_sdf(img, args.n_px, args.bit_depth) 62 63 # Save result 64 if args.bit_depth == 16: 65 # For 16-bit images, ensure proper saving 66 cv2.imwrite(output_path, sdf) 67 else: 68 cv2.imwrite(output_path, sdf) 69 70 print(f"SDF generated and saved to {output_path} (±{args.n_px}px range, {args.bit_depth}-bit)") 71 print(f" Decoding: 0.5 = contour, 0.0 = -{args.n_px}px (inside), 1.0 = +{args.n_px}px (outside)") 72 73if __name__ == "__main__": 74 main()