Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Opening vs Closing decision guide, structuring element selection, Top-Hat/Bottom-Hat contrast filters, and grayscale morphology
.claude/skills/aeren23-morphology-toolkit/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-04 | ✗→✓ | ▲ Improved | -12% | 0% |
| case-02 | ✗→✓ | ▲ Improved | -13% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 9% | 0% |
| case-01 | ✓→✓ | = Same ✓ | -8% | 0% |
| case-05 | ✓→✓ | = Same ✓ | 21% | 0% |
What do you need to clean up?
├── Small white noise specks on black background (external noise)
│ └── ✅ Opening (Erosion → Dilation)
│
├── Small black holes inside white objects (internal gaps)
│ └── ✅ Closing (Dilation → Erosion)
│
├── Objects touching each other (need separation)
│ └── ✅ Erosion (shrinks objects apart)
│
└── Broken lines or gaps in object boundaries
└── ✅ Dilation (expands and connects)| Operation | Formula | Removes | Keeps | Memory Aid | |-----------|---------|---------|-------|------------| | Opening | Erode → Dilate | External noise | Object integrity | "Opens" gaps between noise and object | | Closing | Dilate → Erode | Internal holes | Object shape | "Closes" holes inside object |
> Golden rule: Opening cleans the outside, Closing fills the inside.
Real-world example — Fingerprint processing:
| Shape | OpenCV Constant | Best For | |-------|----------------|----------| | Rectangle/Square | cv2.MORPH_RECT | Angular objects, text characters | | Ellipse/Disk | cv2.MORPH_ELLIPSE | Round objects, cells, coins | | Cross (+) | cv2.MORPH_CROSS | Thin lines, intersections |
Size selection rule: The structuring element must be:
pythonkernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
| Filter | Formula | Reveals | Use Case | |--------|---------|---------|----------| | Top-Hat | Original - Opening | Bright details on dark background | Bright spots, text on dark surface | | Bottom-Hat | Closing - Original | Dark details on bright background | Dark spots, stains on light surface |
pythontophat = cv2.morphologyEx(gray, cv2.MORPH_TOPHAT, kernel) blackhat = cv2.morphologyEx(gray, cv2.MORPH_BLACKHAT, kernel)
Swapping the order of erosion and dilation produces opposite results:
In binary images, erosion/dilation work with set theory. In grayscale:
| Operation | Grayscale Behavior | Visual Effect | |-----------|-------------------|---------------| | Dilation | Maximum filter (picks brightest neighbor) | Image brightens, bright regions expand | | Erosion | Minimum filter (picks darkest neighbor) | Image darkens, dark regions expand |
python# Single pass eroded = cv2.erode(binary, kernel, iterations=1) # Multiple passes = stronger effect (equivalent to larger kernel) eroded = cv2.erode(binary, kernel, iterations=3)
python# Dilation - Erosion = object boundary gradient = cv2.morphologyEx(binary, cv2.MORPH_GRADIENT, kernel)
pythonkernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) eroded = cv2.erode(binary, kernel, iterations=1) dilated = cv2.dilate(binary, kernel, iterations=1) opened = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel) closed = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)
pythongradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel) # Boundary tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel) # Bright details blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel) # Dark details
python# Typical binary cleanup pipeline kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3, 3)) cleaned = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel) # Remove noise cleaned = cv2.morphologyEx(cleaned, cv2.MORPH_CLOSE, kernel) # Fill holes
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-04 | fail→pass | 14,258 | 6,589 | -54% | 1 | 1 | 0% | 2,946 | 2,594 | -12% | 0 | 0 | — |
case-01 | pass→pass | 15,282 | 7,093 | -54% | 1 | 1 | 0% | 3,050 | 2,799 | -8% | 0 | 0 | — |
case-02 | fail→pass | 16,645 | 8,407 | -49% | 1 | 1 | 0% | 3,418 | 2,976 | -13% | 0 | 0 | — |
case-03 | fail→pass | 11,352 | 5,217 | -54% | 1 | 1 | 0% | 2,140 | 2,336 | +9% | 0 | 0 | — |
case-05 | pass→pass | 9,007 | 5,143 | -43% | 1 | 1 | 0% | 1,869 | 2,256 | +21% | 0 | 0 | — |
case-06 | pass→pass | 2,968 | 3,505 | +18% | 1 | 1 | 0% | 540 | 1,700 | +215% | 0 | 0 | — |
case-07 | pass→pass | 3,179 | 3,411 | +7% | 1 | 1 | 0% | 584 | 1,786 | +206% | 0 | 0 | — |
case-08 | pass→pass | 8,128 | 4,163 | -49% | 1 | 1 | 0% | 1,664 | 1,962 | +18% | 0 | 0 | — |
case-09 | pass→pass | 10,302 | 7,382 | -28% | 1 | 1 | 0% | 2,085 | 2,635 | +26% | 0 | 0 | — |
case-10 | pass→pass | 8,200 | 4,788 | -42% | 1 | 1 | 0% | 1,637 | 2,093 | +28% | 0 | 0 | — |
case-11 | pass→pass | 6,830 | 4,485 | -34% | 1 | 1 | 0% | 1,367 | 2,044 | +50% | 0 | 0 | — |
case-12 | pass→pass | 10,502 | 6,442 | -39% | 1 | 1 | 0% | 1,740 | 2,422 | +39% | 0 | 0 | — |
case-13 | pass→pass | 10,132 | 7,157 | -29% | 1 | 1 | 0% | 1,959 | 2,433 | +24% | 0 | 0 | — |
case-14 | pass→pass | 3,994 | 2,371 | -41% | 1 | 1 | 0% | 691 | 1,586 | +130% | 0 | 0 | — |
case-15 | pass→pass | 2,326 | 2,060 | -11% | 1 | 1 | 0% | 456 | 1,543 | +238% | 0 | 0 | — |
case-16 | pass→pass | 3,823 | 3,232 | -15% | 1 | 1 | 0% | 809 | 1,689 | +109% | 0 | 0 | — |
case-17 | pass→pass | 3,907 | 2,310 | -41% | 1 | 1 | 0% | 741 | 1,603 | +116% | 0 | 0 | — |
case-18 | pass→pass | 6,297 | 4,527 | -28% | 1 | 1 | 0% | 1,389 | 2,142 | +54% | 0 | 0 | — |
case-19 | pass→pass | 5,306 | 3,448 | -35% | 1 | 1 | 0% | 1,069 | 1,863 | +74% | 0 | 0 | — |
case-20 | pass→pass | 9,585 | 8,361 | -13% | 1 | 1 | 0% | 2,144 | 2,965 | +38% | 0 | 0 | — |
case-21 | pass→pass | 11,061 | 5,844 | -47% | 1 | 1 | 0% | 2,384 | 2,479 | +4% | 0 | 0 | — |
case-22 | pass→pass | 5,441 | 4,137 | -24% | 1 | 1 | 0% | 1,303 | 2,008 | +54% | 0 | 0 | — |
case-23 | pass→pass | 7,253 | 4,784 | -34% | 1 | 1 | 0% | 1,642 | 2,244 | +37% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 23 cases were attempted. The headline lift of +13 percentage points is the difference between those two pass rates over the 23 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.