--- license: mit tags: - medical - anemia-detection - healthcare - sklearn - pytorch library_name: sklearn pipeline_tag: image-classification --- # 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 ```bash pip install joblib numpy pandas pillow scikit-learn scipy ``` ### Quick Inference ```python 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 1. **Not a diagnostic tool**: Use only for screening, confirm with blood tests 2. **Limited dataset**: ~550 patients 3. **Specificity trade-off**: High sensitivity comes with more false positives 4. **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:** ```bibtex @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:** ```bibtex @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