ApyHTML19 commited on
Commit
38d0309
·
verified ·
1 Parent(s): 0537115

Update README.md

Browse files
Files changed (1) hide show
  1. README.md +118 -29
README.md CHANGED
@@ -8,7 +8,9 @@ tags:
8
  - resnet50
9
  - fpn
10
  - medical
 
11
  - pytorch
 
12
  pipeline_tag: image-segmentation
13
  ---
14
 
@@ -18,41 +20,62 @@ pipeline_tag: image-segmentation
18
 
19
  # MediSeG — Mask R-CNN for Medicine Box Instance Segmentation
20
 
21
- Custom **Mask R-CNN** (ResNet-50 + FPN + RPN + ROI Align, implemented from scratch in PyTorch) that detects and segments medicine boxes (`Med-Box`) in images.
22
 
23
- ## Model description
 
 
 
 
 
 
24
 
25
- - **Backbone**: ResNet-50 (ImageNet-pretrained), feature maps C2–C5.
26
- - **Neck**: Feature Pyramid Network (FPN), levels P2–P5, 256 channels.
27
- - **Region proposal**: RPN with 3 anchor ratios per level (0.5, 1.0, 2.0), one fixed anchor scale per level (32/64/128/256).
28
- - **ROI heads**: shared two-layer MLP trunk → classification head + box regression head (7×7 ROI Align) and a 4-conv + deconv mask head (14×14 → 28×28 ROI Align).
29
- - **Classes**: 2 (`background`, `Med-Box`).
30
- - **Input size**: 640×640 RGB.
31
 
32
- Full architecture diagram: see `ARCHITECTURE.md` in the source repository.
 
 
 
 
 
 
33
 
34
  ## Intended use
35
 
36
- Detect and segment medicine boxes in photos (e.g. pharmacy / assistive applications). Not validated for clinical or safety-critical use.
 
 
37
 
38
  ## Training data
39
 
40
- - 389 training images, 84 validation images, 84 test images.
41
- - Annotations: YOLO-seg polygons (4-point quadrilaterals per instance), converted to bounding boxes + rasterized binary masks.
42
- - Single object class: `Med-Box`.
 
 
 
 
 
 
 
 
43
 
44
  ## Training procedure
45
 
46
- - Optimizer: SGD, `lr=0.005`, `momentum=0.9`, `weight_decay=0.0005`, `StepLR` (step=8, gamma=0.1).
47
- - Losses: RPN objectness (BCE) + RPN box regression (smooth-L1), ROI classification (cross-entropy) + ROI box regression (smooth-L1, class-specific), mask (BCE on 28×28 predictions cropped/resized from ground-truth masks).
48
- - Positive/negative sampling: IoU ≥ 0.7 / < 0.3 for RPN anchors, IoU ≥ 0.5 for ROI proposals (see `app/config.py` for exact sampling ratios and batch sizes).
 
 
 
 
49
 
50
  ## Evaluation
51
 
52
- Evaluated with **Dice** and **IoU** on the held-out test split (combined instance masks vs. combined ground-truth masks per image). Fill in scores after running:
53
 
54
  ```bash
55
- python -m app.evaluate
56
  ```
57
 
58
  | Metric | Value |
@@ -62,34 +85,100 @@ python -m app.evaluate
62
 
63
  ## How to use
64
 
 
 
65
  ```python
66
  import torch
67
- from app.model_arch.mask_rcnn_full import MaskRCNN
 
 
 
 
 
 
68
 
 
69
  model = MaskRCNN(num_classes=2, pretrained_backbone=False)
70
- checkpoint = torch.load("best_model.pth", map_location="cpu")
71
- model.load_state_dict(checkpoint["model_state_dict"])
72
  model.eval()
73
 
74
- image = torch.rand(1, 3, 640, 640) # replace with a real preprocessed image
75
  with torch.no_grad():
76
- detections = model(image) # list of {boxes, labels, scores, masks} per image
 
 
 
77
  ```
78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  ## Limitations
80
 
81
- - Single class (`Med-Box`); not a general-purpose detector.
82
- - Fixed 640×640 input resize (no letterboxing) — non-square source images are stretched.
83
- - Small dataset (389 training images) — expect limited generalization outside the training distribution.
 
 
84
 
85
  ## Citation
86
 
87
- If you use this model, please cite the repository:
88
-
89
  ```
90
  @misc{mediseg2026,
91
  title = {MediSeG: Mask R-CNN for Medicine Box Instance Segmentation},
92
  year = {2026},
93
- url = {<repo-url>}
94
  }
95
  ```
 
8
  - resnet50
9
  - fpn
10
  - medical
11
+ - ocr
12
  - pytorch
13
+ - safetensors
14
  pipeline_tag: image-segmentation
15
  ---
16
 
 
20
 
21
  # MediSeG — Mask R-CNN for Medicine Box Instance Segmentation
22
 
23
+ Custom **Mask R-CNN** (ResNet-50 + FPN + RPN + ROI Align, implemented from scratch in PyTorch — no `torchvision.models.detection`) that detects and segments medicine packages (`medicine_box`) in photos.
24
 
25
+ The model is the first stage of the MediSeG pipeline: **detection + mask → masked crop → OCR (French + Arabic) → LLM identification → web search → annotated summary**.
26
+
27
+ <p align="center">
28
+ <img src="assets/examples/01_multi_box_detections.jpg" alt="Mask R-CNN detections on three medicine boxes" width="49%">
29
+ <img src="assets/examples/01_multi_box_annotated.jpg" alt="Full pipeline output: each box identified with name, dosage, form and active ingredient" width="49%">
30
+ </p>
31
+ <p align="center"><em>Left: Mask R-CNN output (boxes + masks + scores). Right: full pipeline output (OCR + LLM + web search).</em></p>
32
 
33
+ ## Model description
 
 
 
 
 
34
 
35
+ - **Backbone**: ResNet-50 (ImageNet-pretrained), feature maps C2–C5; the top 3 ResNet stages are fine-tuned, BatchNorm stays frozen.
36
+ - **Neck**: Feature Pyramid Network (FPN), 5 levels, 256 channels.
37
+ - **Region proposal**: RPN, one anchor size per level (32 / 64 / 128 / 256 / 512) × 3 aspect ratios (0.5, 1.0, 2.0); NMS 0.7, 300 proposals kept at test time.
38
+ - **ROI heads**: two-layer MLP trunk → classification head + class-specific box regression head (7×7 ROI Align); 4-conv + deconv mask head (14×14 ROI Align → 28×28 masks).
39
+ - **Classes**: 2 (`0 = background`, `1 = medicine_box`).
40
+ - **Input**: RGB, letterboxed to 640×640 (aspect ratio preserved, black padding, top-left aligned).
41
+ - **Weights**: `checkpoints/best_model.safetensors` in this repository.
42
 
43
  ## Intended use
44
 
45
+ Locate and segment medicine packages (boxes, tubes, sachets) in photos, typically to crop them for OCR — e.g. pharmacy tooling or assistive apps that read a medicine's label.
46
+
47
+ **Not** validated for clinical or safety-critical use. The downstream LLM identification can be wrong (see [Limitations](#limitations)); never rely on it to decide what medicine to take.
48
 
49
  ## Training data
50
 
51
+ Built from two public sources merged into one COCO instance-segmentation dataset (full report: `data/report.md` in the source repository):
52
+
53
+ | Split | Images | Instances |
54
+ |---|---:|---:|
55
+ | train | 540 | 806 |
56
+ | val | 68 | 121 |
57
+ | test | 68 | 100 |
58
+
59
+ - Sources: `main_ar_fr` (French/Arabic packages, 4-point polygons) and `medicine_packv2` (polygons). A third source with bounding boxes only was excluded.
60
+ - Split 80/10/10 with seed 42, **grouped by source photo** (near-duplicates merged by perceptual hash) to avoid train/test leakage — the original splits leaked 128 images.
61
+ - Single class: `medicine_box`.
62
 
63
  ## Training procedure
64
 
65
+ - SGD, `lr=0.01`, `momentum=0.9`, `weight_decay=1e-4`, batch size 8, 30 epochs.
66
+ - Linear warmup over 200 iterations, LR ×0.1 at epochs 20 and 26, gradient clipping at 10, mixed precision on GPU.
67
+ - Losses (equal weights): RPN objectness (BCE) + RPN box (smooth-L1), ROI classification (cross-entropy) + ROI box (smooth-L1), mask (BCE on 28×28).
68
+ - Sampling: RPN anchors positive at IoU ≥ 0.7 / negative < 0.3 (256 per image, 50 % positive); ROI proposals positive at IoU ≥ 0.5 (512 per image, 25 % positive).
69
+ - Augmentation: random horizontal flip (p = 0.5).
70
+
71
+ All hyperparameters live in `model_rcnn_scratch/config.py`.
72
 
73
  ## Evaluation
74
 
75
+ Dice and IoU on the held-out test split (union of predicted masks with score ≥ 0.5 vs. union of ground-truth masks, per image):
76
 
77
  ```bash
78
+ python -m model_rcnn_scratch.evaluate
79
  ```
80
 
81
  | Metric | Value |
 
85
 
86
  ## How to use
87
 
88
+ ### Weights only
89
+
90
  ```python
91
  import torch
92
+ import torchvision.transforms.functional as TF
93
+ from huggingface_hub import hf_hub_download
94
+ from PIL import Image
95
+ from safetensors.torch import load_file
96
+
97
+ from model_rcnn_scratch.dataset import letterbox
98
+ from model_rcnn_scratch.model_architecture.mask_rcnn_full import MaskRCNN
99
 
100
+ weights = hf_hub_download("ApyHTML19/MediSeg-Mask-RCNN", "checkpoints/best_model.safetensors")
101
  model = MaskRCNN(num_classes=2, pretrained_backbone=False)
102
+ model.load_state_dict(load_file(weights, device="cpu"))
 
103
  model.eval()
104
 
105
+ image, scale = letterbox(Image.open("photo.jpg").convert("RGB")) # 640x640, aspect ratio kept
106
  with torch.no_grad():
107
+ detections = model(TF.to_tensor(image).unsqueeze(0))[0] # {boxes, labels, scores, masks}
108
+
109
+ keep = detections["scores"] >= 0.5
110
+ boxes = detections["boxes"][keep] / scale # back to original image coordinates
111
  ```
112
 
113
+ The model code lives in the source repository (`model_rcnn_scratch/`); `model_rcnn_scratch.hub.load_model()` does the download + loading above in one call.
114
+
115
+ ### Command line
116
+
117
+ ```bash
118
+ python -m model_rcnn_scratch.predict path/to/photo.jpg # detection only -> outputs_results/<name>_pred.png
119
+ python -m harness.pipeline path/to/photo.jpg # detection + masked crop + OCR, no API key needed
120
+ python -m operation.run path/to/photo.jpg # full pipeline (needs OPENAI_API_KEY + TAVILY_API_KEY)
121
+ ```
122
+
123
+ Full pipeline outputs, in `outputs_results/pipeline/`: `<name>_detections.jpg`, `<name>_box<i>.png` (masked crop), `<name>_analysis.json`, `<name>_annotated.jpg`.
124
+
125
+ ## Examples
126
+
127
+ All images below are real outputs of the model and pipeline, stored in [`assets/examples/`](assets/examples/).
128
+
129
+ ### Several boxes, French labels
130
+
131
+ <p align="center">
132
+ <img src="assets/examples/01_multi_box_crop0.png" alt="Masked crop of the Doliprane box" width="35%">
133
+ </p>
134
+
135
+ Masked crop (`<name>_box0.png`) sent to OCR. The three boxes are detected with score ≈ 1.00; the pipeline identifies **Doliprane 1000 mg**, **Ibuprofène Mylan 200 mg** and **Efferalgan 500 mg**, each with its active ingredient (paracetamol / ibuprofen).
136
+
137
+ ### Bilingual French / Arabic tube and box
138
+
139
+ <p align="center">
140
+ <img src="assets/examples/02_bilingual_tube_annotated.jpg" alt="Aureomycine tube and box, French and Arabic labels" width="80%">
141
+ </p>
142
+
143
+ The French tube (#0) and the Arabic box (#1) are both identified as **Auréomycine 1 %** (chlortetracycline, ophthalmic ointment). Box #2 is a duplicate partial detection of the tube's label.
144
+
145
+ ### Arabic-only label
146
+
147
+ <p align="center">
148
+ <img src="assets/examples/03_arabic_box_annotated.jpg" alt="Vermox box with an Arabic label" width="60%">
149
+ </p>
150
+
151
+ Arabic OCR reads **فيرموكسمجم** ("Vermox mg", words merged), Latin OCR reads **500** and **janssen**, and the LLM resolves it to **Vermox 500 mg** (mebendazole).
152
+
153
+ ### Failure cases
154
+
155
+ <p align="center">
156
+ <img src="assets/examples/04_failure_false_positives_annotated.jpg" alt="False positives on a glass and a text block" width="60%">
157
+ </p>
158
+
159
+ Advertising image: the Propalgina Plus box (#0) is correct, but the model also fires on a **block of text** (#1, score 0.78) and a **glass** (#2, score 0.50). The LLM then "identifies" the text block as paracetamol 500 mg from the words it contains.
160
+
161
+ <p align="center">
162
+ <img src="assets/examples/05_failure_llm_misid_detections.jpg" alt="Two overlapping Colocalm boxes, correctly segmented" width="49%">
163
+ <img src="assets/examples/05_failure_llm_misid_annotated.jpg" alt="LLM misidentification of one box as Lokelma" width="49%">
164
+ </p>
165
+
166
+ Segmentation of the two overlapping boxes is correct and the OCR reads the Arabic brand name correctly (كولوكالم, Colocalm — mebeverine), but the LLM maps it to **Lokelma**, a different medicine. Box #1 gets the right active ingredient without a name.
167
+
168
  ## Limitations
169
 
170
+ - Single class (`medicine_box`); not a general-purpose detector. Any rectangular, label-like region (text panels, product packaging, glasses) can trigger a detection — see the failure cases above. Raise the score threshold (default 0.5) to trade recall for precision.
171
+ - Small dataset (540 training images), mostly French/Arabic packages photographed on plain backgrounds — expect weaker results on cluttered scenes, blisters, bottles or other scripts.
172
+ - Overlapping boxes may produce duplicate or partial detections.
173
+ - The identification stage depends on OCR quality and on an external LLM + web search; it can return a wrong medicine with high confidence. Treat it as a hint, not a diagnosis.
174
+ - `Backbone_RES` downloads ImageNet ResNet-50 weights when training from scratch (not needed for inference with `pretrained_backbone=False`).
175
 
176
  ## Citation
177
 
 
 
178
  ```
179
  @misc{mediseg2026,
180
  title = {MediSeG: Mask R-CNN for Medicine Box Instance Segmentation},
181
  year = {2026},
182
+ url = {https://huggingface.co/ApyHTML19/MediSeg-Mask-RCNN}
183
  }
184
  ```