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

  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:

@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
-
Inference Providers NEW
This model isn't deployed by any Inference Provider. ๐Ÿ™‹ Ask for provider support