#!/usr/bin/env python3 import argparse from pathlib import Path import cv2 import numpy as np def odd_block_size(value: str) -> int: block_size = int(value) if block_size < 3 or block_size % 2 == 0: raise argparse.ArgumentTypeError("block size must be an odd integer greater than or equal to 3") return block_size parser = argparse.ArgumentParser(description="Create a binary mask from a grayscale OpenCV threshold.") parser.add_argument("input_image", type=Path) parser.add_argument("output_mask", type=Path) parser.add_argument("--method", choices=("global", "adaptive"), default="global") parser.add_argument("--threshold", type=int, default=127) parser.add_argument("--invert", action="store_true") parser.add_argument("--block-size", type=odd_block_size, default=31) parser.add_argument("--c", type=int, default=5) args = parser.parse_args() gray = cv2.imread(str(args.input_image), cv2.IMREAD_GRAYSCALE) if gray is None: raise SystemExit(f"could not read image: {args.input_image}") threshold_type = cv2.THRESH_BINARY_INV if args.invert else cv2.THRESH_BINARY if args.method == "global": used_threshold, mask = cv2.threshold(gray, args.threshold, 255, threshold_type) method_label = "global binary inverse" if args.invert else "global binary" parameter_line = f"threshold: {used_threshold:.1f}" else: mask = cv2.adaptiveThreshold( gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C, threshold_type, args.block_size, args.c, ) method_label = "adaptive gaussian inverse" if args.invert else "adaptive gaussian" parameter_line = f"block size: {args.block_size}, C: {args.c}" args.output_mask.parent.mkdir(parents=True, exist_ok=True) if not cv2.imwrite(str(args.output_mask), mask): raise SystemExit(f"could not write mask: {args.output_mask}") foreground_pixels = int(np.count_nonzero(mask == 255)) total_pixels = int(mask.size) foreground_percent = foreground_pixels / total_pixels * 100 unique_values = " ".join(str(int(value)) for value in np.unique(mask)) print(f"input: {args.input_image}") print(f"method: {method_label}") print(parameter_line) print(f"foreground pixels: {foreground_pixels} / {total_pixels} ({foreground_percent:.2f}%)") print(f"unique values: {unique_values}") print(f"output: {args.output_mask}")