skills/cv/mask-to-polygon-contour-hierarchy/SKILL.md
Convert binary segmentation masks to Shapely MultiPolygons using cv2 contour hierarchy to correctly handle interior holes, with Douglas-Peucker simplification
npx skillsauth add wenmin-wu/ds-skills cv-mask-to-polygon-contour-hierarchyInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Converting binary masks to vector polygons is needed for GIS submissions, vectorized post-processing, or spatial queries. Use cv2.findContours with RETR_CCOMP to get a two-level contour hierarchy: outer contours become polygon shells, their children become holes. Apply Douglas-Peucker simplification and minimum-area filtering to clean up jagged edges.
import cv2
import numpy as np
from collections import defaultdict
from shapely.geometry import Polygon, MultiPolygon
def mask_to_polygons(mask, epsilon=1.0, min_area=10.0):
mask_uint8 = ((mask > 0) * 255).astype(np.uint8)
contours, hierarchy = cv2.findContours(
mask_uint8, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_TC89_KCOS)
if not contours or hierarchy is None:
return MultiPolygon()
approx = [cv2.approxPolyDP(c, epsilon, True) for c in contours]
children = defaultdict(list)
child_set = set()
for idx, (_, _, _, parent) in enumerate(hierarchy[0]):
if parent != -1:
child_set.add(idx)
children[parent].append(approx[idx])
polys = []
for idx, cnt in enumerate(approx):
if idx not in child_set and cv2.contourArea(cnt) >= min_area:
shell = cnt[:, 0, :]
holes = [c[:, 0, :] for c in children.get(idx, [])
if cv2.contourArea(c) >= min_area]
p = Polygon(shell, holes)
if not p.is_valid:
p = p.buffer(0)
polys.append(p)
return MultiPolygon(polys)
findContours with RETR_CCOMP for two-level hierarchyapproxPolyDP to simplify contour vertices.buffer(0)data-ai
Scaled Pinball Loss (SPL) metric for evaluating quantile forecasts, normalized by mean absolute successive differences of training data
data-ai
Walk backward through a time series and multiplicatively rescale segments when jumps exceed a fraction of the running mean to correct data collection anomalies
testing
Transform forecasting target to next/current ratio minus one so that optimizing MAE or squared error implicitly minimizes SMAPE
tools
Convert point forecasts to prediction intervals by scaling with logit-transformed quantile ratios passed through a Normal CDF