Nail Anemia Detector
A machine learning model for detecting anemia from fingernail images using handcrafted color features.
Model Description
This model analyzes fingernail images to predict anemia risk. It extracts medically-relevant color features (pallor indices, redness measures, hemoglobin proxies) and uses an MLP classifier for prediction.
Key Features:
- 100% recall mode available (catches all anemic patients)
- Lightweight and fast inference
- Suitable for screening applications
Performance
| Metric | Value |
|---|---|
| AUC | 0.75 |
| Accuracy | 73% |
| Recall (Sensitivity) | 90% |
| Specificity | 46% |
| F1 Score | 0.81 |
High Sensitivity Mode
For 100% recall (no missed anemic patients):
- Set threshold to 0.255
- Specificity: 17.1%
- Use for screening followed by confirmatory blood test
Model Files
| File | Description |
|---|---|
mlp_model.joblib |
Trained sklearn MLP classifier |
feature_scaler.joblib |
StandardScaler for feature normalization |
best_model.pt |
PyTorch model (alternative) |
model_metadata.json |
Model configuration and metrics |
inference.py |
Inference script |
Usage
Installation
pip install joblib numpy pandas pillow scikit-learn scipy
Quick Inference
import joblib
import numpy as np
from PIL import Image
from scipy.ndimage import uniform_filter
# Load model
model = joblib.load('mlp_model.joblib')
scaler = joblib.load('feature_scaler.joblib')
# Threshold: 0.10 for balanced, 0.255 for 100% recall
threshold = 0.10
def extract_features(img):
img = img.convert('RGB').resize((224, 224))
arr = np.array(img).astype(float)
r, g, b = arr[:,:,0], arr[:,:,1], arr[:,:,2]
brightness = 0.299*r + 0.587*g + 0.114*b
features = []
# Brightness features
features.extend([brightness.mean(), brightness.std()])
features.extend([np.percentile(brightness, p) for p in [10, 25, 50, 75, 90]])
# Redness features
redness = r / (r + g + b + 1e-10)
features.extend([redness.mean(), redness.std()])
# Pallor features
white_ratio = (brightness > 180).sum() / brightness.size
pink_ratio = ((r > 150) & (g < 150) & (b < 150)).sum() / brightness.size
features.extend([white_ratio, pink_ratio])
# Channel statistics
for ch in [r, g, b]:
features.extend([ch.mean(), ch.std()])
# Color ratios
features.extend([
(r.mean() + 1) / (g.mean() + 1),
(r.mean() + 1) / (b.mean() + 1),
(r.mean() - b.mean()) / 255,
])
# Hemoglobin proxy
hb = r / (g + b + 1)
features.extend([hb.mean(), hb.std()])
# Spatial features
h, w = arr.shape[:2]
top = brightness[:h//3, :].mean()
bottom = brightness[2*h//3:, :].mean()
features.append(top - bottom)
center = brightness[h//4:3*h//4, w//4:3*w//4].mean()
features.append(center - brightness.mean())
# Gradient features
gx = np.abs(np.diff(brightness, axis=1, prepend=brightness[:, :1]))
gy = np.abs(np.diff(brightness, axis=0, prepend=brightness[:1, :]))
gradient = np.sqrt(gx**2 + gy**2)
features.extend([gradient.mean(), gradient.std()])
# Local variance
local_mean = uniform_filter(brightness, size=7)
local_var = uniform_filter((brightness - local_mean)**2, size=7)
local_var = np.maximum(local_var, 0)
features.extend([np.sqrt(local_var).mean(), np.sqrt(local_var).std()])
return np.array(features, dtype=np.float32)
# Predict
img = Image.open('nail_image.jpg')
features = extract_features(img)
features_scaled = scaler.transform(features.reshape(1, -1))
probability = model.predict_proba(features_scaled)[0, 1]
prediction = "anemia" if probability >= threshold else "healthy"
print(f"Prediction: {prediction}")
print(f"Probability: {probability:.4f}")
Training Details
Dataset
This model was trained on the Detection of Anemia using Colour of the Fingernails Image Datasets from Ghana:
Asare, Justice Williams; APPIAHENE, PETER; DONKOH, EMMANUEL (2022), "Detection of Anemia using Colour of the Fingernails Image Datasets from Ghana", Mendeley Data, V1, doi: 10.17632/2xx4j3kjg2.1
Dataset available at: https://data.mendeley.com/datasets/2xx4j3kjg2/1
Training Data
- 3,406 images from 443 patients
- Patient-level splits to prevent data leakage
- Features: 27 handcrafted color features
Feature Engineering
Features extracted based on medical knowledge:
- Pallor indicators: Brightness metrics, white/pink ratios
- Redness measures: R channel statistics, redness index
- Color ratios: R/G, R/B, hemoglobin proxies
- Saturation: Color intensity measures
- Spatial patterns: Gradients, center vs edge differences
Model Architecture
- MLP with hidden layers: [128, 64]
- Optimizer: Adam
- Loss: Cross-entropy with class weights
Limitations
- Not a diagnostic tool: Use only for screening, confirm with blood tests
- Limited dataset: ~550 patients
- Specificity trade-off: High sensitivity comes with more false positives
- Single imaging site: Only fingernail images tested
Intended Use
This model is designed as a pre-screening tool for anemia in:
- Primary care settings
- Resource-limited areas
- Telemedicine applications
Workflow:
Image Analysis (this model) โ If positive โ Blood test confirmation
Ethical Considerations
- Results should be confirmed by healthcare professionals
- Not intended to replace standard diagnostic procedures
- Consider population demographics when interpreting results
Citation
If you use this model, please cite both the model and the dataset:
Model:
@model{nail_anemia_detector,
title={Nail Anemia Detector},
author={JetX-GT},
year={2026},
publisher={Hugging Face},
url={https://huggingface.co/JetX-GT/nail-anemia-detector}
}
Dataset:
@dataset{asare2022anemia,
title={Detection of Anemia using Colour of the Fingernails Image Datasets from Ghana},
author={Asare, Justice Williams and Appiahene, Peter and Donkoh, Emmanuel},
year={2022},
publisher={Mendeley Data},
version={V1},
doi={10.17632/2xx4j3kjg2.1}
}
License
MIT License
- Downloads last month
- -