Metadata-Version: 2.4
Name: acdentnet
Version: 0.1.0
Summary: Tooth discrepancy analysis from maxilla and mandible dental images using HeatmapNet (ResNet50)
Project-URL: Homepage, https://github.com/Sandeep-4469/acdentnet
Project-URL: Repository, https://github.com/Sandeep-4469/acdentnet
Project-URL: Bug Tracker, https://github.com/Sandeep-4469/acdentnet/issues
Author-email: Sandeep Vissa <sandeepvissa2002@gmail.com>
License: MIT
License-File: LICENSE
Keywords: computer-vision,dental,dental-imaging,heatmap,keypoint-detection,mandible,maxilla,moyers,resnet,space-analysis,tanaka-johnston,teeth,tooth-discrepancy
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Healthcare Industry
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
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: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Scientific/Engineering :: Image Recognition
Classifier: Topic :: Scientific/Engineering :: Medical Science Apps.
Requires-Python: >=3.8
Requires-Dist: huggingface-hub>=0.20.0
Requires-Dist: numpy>=1.21.0
Requires-Dist: opencv-python>=4.5.0
Requires-Dist: pillow>=9.0.0
Requires-Dist: torch>=1.13.0
Requires-Dist: torchvision>=0.14.0
Provides-Extra: dev
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: ruff>=0.1.0; extra == 'dev'
Description-Content-Type: text/markdown

# acdentnet

[![PyPI version](https://img.shields.io/pypi/v/acdentnet.svg)](https://pypi.org/project/acdentnet/)
[![Python](https://img.shields.io/pypi/pyversions/acdentnet.svg)](https://pypi.org/project/acdentnet/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Model on HF](https://img.shields.io/badge/Model-HuggingFace-orange)](https://huggingface.co/sandy4469/acdentnet)

**Tooth discrepancy analysis from maxilla and mandible dental images.**

`acdentnet` uses a HeatmapNet model (ResNet50 backbone) to localise measurement keypoints on dental X-ray or photograph images and computes tooth space discrepancy using the **Tanaka-Johnston** and **Moyers** formulas.

> The model weights (~131 MB) are hosted on Hugging Face and **download automatically** on first use.

---

## Installation

```bash
pip install acdentnet
```

The model downloads automatically the first time you import the package.

---

## Quick start

```python
from acdentnet import DiscrepancyPredictor

# No model path needed — downloads automatically from HuggingFace
predictor = DiscrepancyPredictor()

# Step 1: mandible (provides incisor measurements)
result = predictor.predict("mandible.jpg", arch="mandible", gender="male")

print(f"Lower incisor sum : {result.lower_incisor_sum_mm:.2f} mm")
print(f"Left available    : {result.left_available_mm:.2f} mm")
print(f"Right available   : {result.right_available_mm:.2f} mm")
print()
print(f"Tanaka-Johnston : {result.tanaka.mean_discrepancy_mm:+.2f} mm → {result.tanaka.interpretation()}")
print(f"Moyers          : {result.moyers.mean_discrepancy_mm:+.2f} mm → {result.moyers.interpretation()}")

# Step 2: maxilla (requires incisor sum from mandible)
maxilla = predictor.predict(
    "maxilla.jpg",
    arch="maxilla",
    gender="male",
    lower_incisor_sum_mm=result.lower_incisor_sum_mm,
)
```

### No scale reference in image?

```python
result = predictor.predict("xray.jpg", arch="mandible", has_scale=False)
# Returns pixel measurements only; Tanaka/Moyers are skipped
print(result.left_available_px, result.right_available_px)
```

### Save annotated image

```python
predictor.annotate_and_save("mandible.jpg", "output.jpg", arch="mandible")
```

### Export as JSON

```python
print(predictor.predict_to_json("mandible.jpg", arch="mandible"))
```

---

## Command-line interface

```bash
# Interactive scale prompt
acdentnet mandible.jpg --arch mandible --gender male

# Explicit flags
acdentnet mandible.jpg --arch mandible --scale
acdentnet mandible.jpg --arch mandible --no-scale   # pixel measurements only

# Maxilla (provide incisor sum from mandible result)
acdentnet maxilla.jpg --arch maxilla --incisor-sum 22.5

# Save annotated image
acdentnet mandible.jpg --arch mandible --scale --output out.jpg

# JSON output
acdentnet mandible.jpg --arch mandible --scale --json

# Use a local weights file instead of auto-download
acdentnet mandible.jpg --model /path/to/heatmap_best.pth --arch mandible --scale
```

---

## How it works

```
Input image (mandible or maxilla)
        │
        ▼
  HeatmapNet (ResNet50 + 3 deconv layers)
        │  14 heatmaps → 14 keypoints
        ▼
  build_lines()
        │  7 lines (mandible) or 3 lines (maxilla)
        │  scale → px_to_mm calibration (if scale present)
        ▼
  compute_discrepancy()
        │
        ├── Tanaka-Johnston formula
        └── Moyers formula (gender-specific lookup table)
```

### Keypoint layout

| Arch | Lines |
|------|-------|
| **Maxilla** | scale (5mm ref) · left arc · right arc |
| **Mandible** | scale · incisor 1–4 · left arc · right arc |

### Discrepancy formulas

| Formula | Mandible | Maxilla |
|---------|----------|---------|
| **Tanaka-Johnston** | predicted = (incisor_sum / 2) + 10.5 | predicted = (incisor_sum / 2) + 11.0 |
| **Moyers** | gender-specific lookup table | gender-specific lookup table |

Discrepancy = available arch space − predicted required space  
→ **positive** = spacing · **negative** = crowding

---

## API reference

### `DiscrepancyPredictor`

```python
DiscrepancyPredictor(model_path=None, device=None)
```

| Method | Returns | Description |
|--------|---------|-------------|
| `predict(image, arch, gender, has_scale, lower_incisor_sum_mm)` | `DiscrepancyResult` | Full analysis |
| `annotate(image, ...)` | `PIL.Image` | Predict + draw lines |
| `annotate_and_save(image, path, ...)` | `Path` | Predict, draw, save |
| `predict_to_json(image, ...)` | `str` | Result as JSON string |

### `DiscrepancyResult`

| Field | Type | Description |
|-------|------|-------------|
| `arch` | `str` | `"mandible"` or `"maxilla"` |
| `has_scale` | `bool` | Whether mm calibration was applied |
| `lower_incisor_sum_mm` | `float` | Sum of 4 lower incisor widths |
| `left_available_mm` | `float` | Available space, left side |
| `right_available_mm` | `float` | Available space, right side |
| `tanaka` | `FormulaResult` | Tanaka-Johnston result |
| `moyers` | `FormulaResult` | Moyers result |

### `FormulaResult`

| Field | Description |
|-------|-------------|
| `predicted_per_side_mm` | Required space per side |
| `left_discrepancy_mm` | left available − predicted |
| `right_discrepancy_mm` | right available − predicted |
| `mean_discrepancy_mm` | mean of left + right |
| `interpretation()` | `"spacing (+x.xx mm)"` or `"crowding (-x.xx mm)"` |

---

## Model

- **Architecture:** ResNet50 backbone + 3 transposed convolution layers → 14-channel heatmap output
- **Input:** 512 × 512 RGB image
- **Output:** 14 keypoint heatmaps (128 × 128 each)
- **Weights:** [sandy4469/acdentnet](https://huggingface.co/sandy4469/acdentnet) on Hugging Face (~131 MB)
- **Cache:** `~/.cache/acdentnet/heatmap_best.pth`

---

## License

MIT — see [LICENSE](LICENSE).
