Medical imaging case study
Classifying colon tissue images as benign or adenocarcinoma with OpenCV contrast enhancement and a fine-tuned ResNet-18, packaged as a web demo anyone can try.
Colorectal cancer is diagnosed by pathologists who examine stained tissue slides under a microscope. The work is slow, and different experts sometimes disagree on borderline cases. A model that flags likely cancer can help a pathologist prioritise which slides to review first.
The goal of this project is a binary classifier for colon tissue patches: benign or adenocarcinoma, the most common type of colon cancer.
I used the colon part of the public LC25000 dataset: 10,000 H&E stained images at 768 × 768 pixels, 5,000 per class. The split is 70% training, 15% validation and 15% test, stratified so each split keeps the 50/50 balance.
One detail shaped how I read the results: the 10,000 images were created by augmenting 500 original images (250 per class). Augmented copies of the same original can land in both the training and test sets, which makes test scores optimistic. The dataset does not say which images share an original, so this cannot be fully fixed. I report it openly instead of hiding it.
In cancer screening, missing a cancer is worse than a false alarm. Accuracy hides that difference, so the evaluation reports sensitivity (how many cancers are caught) and specificity (how many benign samples are correctly cleared) separately, plus the ROC curve for choosing a different threshold.
H&E slides look different depending on the lab, the scanner and the staining batch. Enhancing contrast only on the lightness channel, together with mild brightness jitter during training, helps the model focus on tissue structure instead of colour shifts. The training script has a --no-clahe switch to measure what CLAHE contributes.
Free hosting means running on a CPU. ResNet-18 is accurate enough for this task and small enough (about 45 MB) to load and predict in about a second without a GPU, which keeps the live demo responsive.
Trained for 8 epochs on a free Colab T4 GPU, then evaluated once on the 1,500 test images the model never saw during training (750 per class).
| Metric | Score |
|---|---|
| Accuracy | 100.0% |
| Sensitivity (cancers caught) | 100.0% |
| Specificity (benign correctly cleared) | 100.0% |
| Precision | 100.0% |
| F1 | 1.000 |
| ROC-AUC | 1.000 |
Validation accuracy hit 100% after the very first epoch. On a real-world medical task that would be a red flag, and here the cause is the dataset itself: the 10,000 colon images were made by rotating and flipping 500 originals, so copies of the same tissue sample sit in both the training and test sets. The test partly measures recognition of tissue the model has already seen. Published results on LC25000 commonly report 99 to 100% for the same reason.
A fair estimate needs a split that keeps near-duplicates together, or a test on slides from a different source. Both are on the list below.
The trained model, its metrics and sample images are published on Hugging Face, and the demo loads it from there.