Metadata-Version: 2.4
Name: microdefectcv
Version: 0.2.1
Summary: Adaptive OpenCV-based defect enhancement and segmentation for SEM and microstructure images
Author-email: Sahil Soni <Sahilsonii369@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/Sahilsonii/microdefectcv
Project-URL: Documentation, https://sahilsonii.github.io/microdefectcv/
Project-URL: Changelog, https://github.com/Sahilsonii/microdefectcv/blob/main/CHANGELOG.md
Project-URL: Issues, https://github.com/Sahilsonii/microdefectcv/issues
Project-URL: Source, https://github.com/Sahilsonii/microdefectcv
Keywords: opencv,computer-vision,image-processing,defect-detection,defect-segmentation,sem,scanning-electron-microscopy,microstructure,materials-science,perovskite,perovskite-solar-cells,thin-films,pinhole-detection,pbi2,clahe,image-segmentation,grain-boundary-detection,morphological-operations,quality-control,scientific-computing
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Education
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Scientific/Engineering :: Image Processing
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Topic :: Multimedia :: Graphics
Classifier: Topic :: Multimedia :: Graphics :: Graphics Conversion
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: opencv-python>=4.5
Requires-Dist: numpy>=1.21
Provides-Extra: viz
Requires-Dist: matplotlib>=3.4; extra == "viz"
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: matplotlib>=3.4; extra == "dev"
Dynamic: license-file

# MicroDefectCV

**Adaptive OpenCV-based defect enhancement and segmentation for SEM and microstructure images.**

[![PyPI version](https://img.shields.io/pypi/v/microdefectcv)](https://pypi.org/project/microdefectcv/)
[![PyPI Downloads](https://img.shields.io/pypi/dm/microdefectcv)](https://pypi.org/project/microdefectcv/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Python 3.8+](https://img.shields.io/badge/python-3.8+-blue.svg)](https://www.python.org/)

A domain-specific computer vision toolkit for defect detection in perovskite solar cell SEM images. MicroDefectCV provides a reusable, mode-aware pipeline for pinhole and PbI₂ bright-particle detection that generalises to a wide range of microstructure images — no deep learning or labelled data required.

> This package provides a lightweight classical computer vision **baseline** for defect enhancement and segmentation. It does not claim to replace deep learning methods on large annotated datasets.

> **0.2.0 is a correctness release.** If you are on 0.1.x, upgrade: returned
> masks were at the wrong resolution, YOLO exports were systematically
> displaced, `sensitivity` did nothing, and 16-bit images crashed. See
> [CHANGELOG.md](CHANGELOG.md).

---

## Features

- 🔬 **Six detection modes** covering different perovskite morphologies and defect types
- 🧠 **Auto mode** that classifies image morphology from statistics alone
- 🧩 **Grain boundary suppression** for 3D and mixed-morphology images
- 📐 **Needle crystal detection** for elongated PbI₂ excess structures
- 📊 **Defect statistics** (count, area, area ratio) in one call
- 🖼️ **Intermediate stage images** for debugging and research
- ✅ **Zero deep learning** — pure OpenCV + NumPy, runs on CPU
- 📦 **Pip-installable** clean package structure
- 💻 **CLI entry point** — run `microdefectcv` directly from any terminal after install

---

# MicroDefectCV

MicroDefectCV is a computer vision toolkit for defect detection in perovskite solar cell SEM images.

## PyPI
https://pypi.org/project/microdefectcv/

## Installation

```bash
pip install microdefectcv            # core: opencv + numpy
pip install 'microdefectcv[viz]'     # + matplotlib, for save_result_grid
```

matplotlib is an optional extra as of 0.2.0. It is used by exactly one function,
so a core install no longer pulls a plotting stack you may never call.

Or install from source:

```bash
git clone https://github.com/Sahilsonii/microdefectcv.git
cd microdefectcv
pip install -e .
```

---

## Quick Start

```python
import cv2
from microdefectcv import detect_defects

image = cv2.imread("sample_images/sem_image.png")

result = detect_defects(
    image,
    mode="auto",       # auto-selects morphology from image statistics
    min_area=20,
    return_intermediate=True
)

print(f"Defects found  : {result['defect_count']}")
print(f"Area ratio     : {result['defect_area_ratio']:.4f}")

mask     = result["mask"]         # binary defect mask
enhanced = result["enhanced"]     # CLAHE-enhanced image
contours = result["contours"]     # list of OpenCV contours
```

---

## Detection Modes

| Mode | Target Defects | Image Morphology |
|---|---|---|
| `auto` | All | Auto-detected from statistics |
| `pbi2` | PbI₂ bright particles + needles | Any |
| `pinhole` | Dark pinholes (small + large) | Any |
| `2d` | Both | 2D perovskite (flat morphology) |
| `3d` | Both + needles | 3D perovskite (grain suppression active) |
| `3d_2d` | Both + needles | Mixed 2D-3D morphology |

---

## Method Pipeline

```
Input Image
    │
    ├─ Grayscale conversion + dtype normalisation (uint16 / float / BGRA)
    ├─ SEM metadata bar detection  ──► excluded from analysis, NOT from output
    ├─ Mode selection (auto or user-specified)
    ├─ sensitivity + profile_overrides applied to the mode profile
    ├─ Gaussian denoising + CLAHE
    │
    ├─ [3D / 3D-2D only] Grain boundary suppression mask
    │
    ├─ Bright particle detection (max-of-Top-Hats + absolute residual threshold)
    ├─ Dark pit detection        (Percentile threshold + micro-threshold)
    ├─ Needle crystal detection  (Rectangular Top-Hat + aspect ratio filter)
    │
    ├─ Shape feature filtering (area, circularity, solidity, contrast)
    ├─ Non-maximum suppression (IoU-based, across classes)
    │
    └─ Output at INPUT resolution: mask, enhanced, contours, detections,
       defect_count, defect_area_ratio, crop_row
```

> The bright path thresholds the top-hat residual at an absolute value
> (`bright_tophat_thresh`, default 6) because top-hat has already removed the
> local background. Earlier documentation described a "dual percentile
> threshold"; the two percentile fields existed but were never read, and were
> removed in 0.2.0.

See [`docs/method_overview.md`](docs/method_overview.md) for full technical details.

---

## Parameters

| Parameter | Type | Default | Description |
|---|---|---|---|
| `image` | `np.ndarray` | — | Grayscale, BGR or BGRA. `uint8`, `uint16`, `int32` and float are all accepted and normalised |
| `mode` | `str` | `"auto"` | Detection mode (see table above) |
| `sensitivity` | `float` | `1.5` | Higher admits more candidates, lower fewer, by scaling the area/contrast/confidence gates. `1.5` is the neutral value and reproduces the profile exactly |
| `min_area` | `float` | `20` | Minimum defect area in pixels. Applied **on top of** the mode profile's own floor, so the effective minimum is the larger of the two |
| `return_intermediate` | `bool` | `False` | Include per-stage pipeline images (at analysis resolution) |
| `crop_sem_bar` | `bool` | `True` | Exclude a detected bottom metadata bar from analysis. Set `False` for already-cropped images |
| `profile_overrides` | `dict` | `None` | Override any mode-profile field, e.g. `{"tophat_kernels": [3, 5, 7, 11, 15]}`. Keys are validated |

### Return value

| Key | Description |
|---|---|
| `mask` | Binary defect mask, **at input resolution** |
| `enhanced` | CLAHE-enhanced image, at input resolution |
| `defect_count` | Number of detections |
| `defect_area_ratio` | Defect pixels / **analysed** pixels |
| `contours` | Filtered contours, in the input coordinate frame |
| `detections` | Dicts of `contour`, `class_id`, `defect_type`, `bbox=(x, y, w, h)` |
| `mode` | Mode actually used (resolved, if `"auto"` was passed) |
| `crop_row` | First row excluded as metadata bar; `== height` when nothing was cropped |

Everything is in the coordinate frame of the image you passed in, so both of
these are correct with no adjustment:

```python
overlay = overlay_mask(image, result["mask"])
save_yolo_annotations(result["detections"], image.shape, "labels.txt")
```

> In 0.1.x they were not: `mask` came back cropped to the analysed region, so the
> first call raised and the second silently displaced every box by the crop
> ratio. See [CHANGELOG.md](CHANGELOG.md).

---

## Quick Start Guide

### Method 1: Command Line (Single Image)
After `pip install microdefectcv`, the `microdefectcv` command is available from any terminal — no need to navigate to a script folder.
```bash
# Auto-detect mode
microdefectcv "C:\Users\asus\Desktop\SEM annotation\3D perovskite with PbI2 excess\08-10.tif" --mode auto --min-area 20

# PbI2 bright particle + needle detection
microdefectcv "C:\Users\asus\Desktop\SEM annotation\3D perovskite with PbI2 excess\08-10.tif" --mode pbi2 --min-area 30

# Pinhole / dark void detection
microdefectcv "C:\Users\asus\Desktop\SEM annotation\3D perovskite with PbI2 excess\08-10.tif" --mode pinhole --min-area 20

# 2D perovskite (flat morphology)
microdefectcv "C:\Users\asus\Desktop\SEM annotation\3D perovskite with PbI2 excess\08-10.tif" --mode 2d --min-area 20

# 3D perovskite with grain boundary suppression
microdefectcv "C:\Users\asus\Desktop\SEM annotation\3D perovskite with PbI2 excess\08-10.tif" --mode 3d --min-area 20

# Mixed 2D-3D morphology
microdefectcv "C:\Users\asus\Desktop\SEM annotation\3D perovskite with PbI2 excess\08-10.tif" --mode 3d_2d --min-area 20
```

### Method 2: Batch Processing (PowerShell)
Process an entire folder of images automatically:
```powershell
Get-ChildItem -Path "path\to\folder" -Filter *.jpg | ForEach-Object {
    microdefectcv $_.FullName --mode auto
}
```

### Method 3: Python API
Import and use directly in your own scripts:
```python
import cv2
from microdefectcv import detect_defects
from microdefectcv.visualization import save_yolo_annotations

image = cv2.imread("path/to/image.jpg")
result = detect_defects(image, mode="auto", min_area=20)

print(f"Found {result['defect_count']} defects!")
save_yolo_annotations(result["detections"], image.shape, "outputs/labels.txt")
```

---

## Results

![Defect Detection Output](images/output.png)

---

## Comparison

| Method | Suitability | Notes |
|---|---|---|
| Global Threshold | Low | Fails under uneven SEM lighting |
| Otsu | Low–Medium | No domain adaptation |
| CLAHE + Otsu | Medium | Better contrast, still single-class |
| Canny | Edge-only | Not suitable for void/particle detection |
| **MicroDefectCV** | **High** | Adaptive, mode-aware, domain-specific |

---

## Benchmark

Earlier versions of this README noted that no quantitative benchmark shipped
with the package. Here it is, measured on **62 annotated real perovskite FESEM
frames carrying 3,236 expert boxes**. A defect counts as found when a detection
centre falls inside its expert box — deliberately generous, because the question
is whether the detector responds at all, not how tightly it localises.

| path | mode | expert boxes | recall | median side, found | median side, missed |
|---|---|---|---|---|---|
| dark pits | `pinhole` | 2,797 | **0.792** | 15.6 px | 10.4 px |
| bright particles | `pbi2` | 439 | **0.492** | 18.2 px | 11.7 px |

Runtime, 705×1024, single CPU core:

| mode | 0.1.1 | 0.2.0 |
|---|---|---|
| `pinhole` | 1.30 s | **0.12 s** |
| `3d` | 0.08 s | 0.06 s |

---

## Limitations

Stated plainly, because a classical baseline is only useful if you know where it
stops working.

**Both paths are size-limited.** Missed defects are consistently ~1.5× smaller
than found ones. On a low-noise synthetic canvas the dark path reaches recall
1.00 at ≥10 px diameter and falls to **0.25 at 2 px**. If your defects are a few
pixels across, this is not the right tool.

**`pbi2` cannot see large particles.** A top-hat responds only to structures
*smaller* than its kernel, and the `pbi2` bank is `[3, 5, 7]`, so particles
wider than ~7 px produce almost no response — even though the profile's
`max_area_bright` nominally admits ~62 px.

The default is left as-is on purpose. Widening the bank restores large-blob
recall on smooth synthetic canvases (0.00 → 1.00) but **reduces** it on real SEM
texture (0.492 → 0.041), because a wider top-hat starts responding to grain
structure. If your images are large isolated particles on a smooth background:

```python
detect_defects(img, mode="pbi2",
               profile_overrides={"tophat_kernels": [3, 5, 7, 11, 15, 21]})
```

**`min_area` interacts with the mode profile.** The default of 20 sits above
every profile's own floor, so it is what actually governs small defects. At
`min_area=120` the dark path's matched recall on a synthetic canvas is 0.00.

**No nanometre calibration.** Every size reported is in pixels. Physical scale
depends on your instrument's pixel size, which the package does not read.

---

## Running Tests

```bash
pip install 'microdefectcv[dev]'
pytest                    # 70 tests
```

`tests/test_regressions.py` holds one test per defect fixed in 0.2.0. All of
them failed silently before the fix, which is why they survived to a release.

---

## Use Cases

- **Perovskite solar-cell SEM** — pinhole and PbI₂ crystal detection
- **Thin-film defect inspection** — dark voids and bright particle segmentation
- **Microstructure void detection** — general SEM / optical microscopy
- **Coating and surface QC** — surface dark defect segmentation
- **Classical CV baseline** — compare against DL models on annotated datasets

---

## Citation

If you use MicroDefectCV in academic work, please cite:

```
@software{microdefectcv2025,
  title  = {MicroDefectCV: Adaptive OpenCV-based Defect Segmentation for SEM Images},
  author = {Sahil Soni},
  year   = {2025},
  url    = {https://github.com/Sahilsonii/microdefectcv}
}
```

---

## Roadmap

- [x] Annotated SEM benchmark — see [Benchmark](#benchmark), 3,236 expert boxes
- [x] Working `sensitivity` control
- [ ] Publish the benchmark corpus and evaluation script
- [ ] Scale-adaptive top-hat bank, so `pbi2` covers its own `max_area_bright`
      without losing recall on textured frames (see [Limitations](#limitations))
- [ ] Sub-5 px detection path — the measured floor is the main capability gap
- [ ] Optional integration with OpenCV-contrib

---

## License

MIT — see [LICENSE](LICENSE).
