Skip to content
Back to skills

Mask To Polygon Contour Hierarchy

ASecurity

Convert binary segmentation masks to Shapely MultiPolygons using cv2 contour hierarchy to correctly handle interior holes, with Douglas-Peucker simplification

  • 61 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 12, 2026
documentationpythongoshell

Security analysis

A100/100

Scanned September 12, 2026

npx -y skills add wenmin-wu/ds-skills --skill mask-to-polygon-contour-hierarchy --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Mask To Polygon Contour Hierarchy?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Mask To Polygon Contour Hierarchy
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/wenmin-wu-mask-to-polygon-contour-hierarchy/badge)](https://www.skillsdirectory.com/skills/wenmin-wu-mask-to-polygon-contour-hierarchy)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: cv-mask-to-polygon-contour-hierarchy
description: Convert binary segmentation masks to Shapely MultiPolygons using cv2 contour hierarchy to correctly handle interior holes, with Douglas-Peucker simplification
---

# Mask to Polygon via Contour Hierarchy

## Overview

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.

## Quick Start

```python
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)
```

## Workflow

1. Threshold mask to binary uint8
2. `findContours` with `RETR_CCOMP` for two-level hierarchy
3. `approxPolyDP` to simplify contour vertices
4. Map parent-child hierarchy to shell-hole polygon pairs
5. Filter by minimum area, fix invalid geometries with `.buffer(0)`

## Key Decisions

- **RETR_CCOMP vs RETR_TREE**: CCOMP gives exactly two levels (shell + holes); TREE is for nested structures
- **epsilon**: controls simplification — higher = fewer vertices, smoother boundaries
- **min_area**: removes tiny noise polygons; tune to match annotation resolution
- **.buffer(0)**: fixes self-intersections from approximation

## References

- [Full pipeline demo: poly -> pixels -> ML -> poly](https://www.kaggle.com/code/lopuhin/full-pipeline-demo-poly-pixels-ml-poly)

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.