YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
- Lung Cancer Classification API with Grad-CAM
- Example output: ```
- π©Ί LUNG CANCER CLASSIFICATION - DenseNet121
- ============================================================ π CLASSIFICATION RESULTS
- ============================================================ π₯ FINAL DIAGNOSIS
- Classification: Small Cell (Class B) Confidence: 72.15%
Lung Cancer Classification API with Grad-CAM
A production-ready Flask REST API for classifying lung cancer types using DenseNet121 with Grad-CAM visualization. Validates medical images, provides explainable AI predictions, and returns base64-encoded visualizations.
Features
- β DenseNet121 Classification: 4-class lung cancer type prediction (Adenocarcinoma, Small Cell, Large Cell, Squamous Cell)
- β Grad-CAM Visualization: Visual explanation of model predictions via heatmap overlays
- β CT Scan Validation: Automatic rejection of non-medical (color) images
- β Dual Preprocessing: Attempts both normalized and non-normalized preprocessing for robust predictions
- β REST API: Flask with Swagger UI documentation
- β CORS Support: Mobile and cross-origin requests enabled
- β Production Ready: Gunicorn WSGI server, environment variables, Docker-compatible
- β JSON Responses: Base64-encoded images for mobile integration
Installation
Local Development
# Clone the repository
git clone <repo-url>
cd Grad-Cam-Backend
# Create virtual environment
python3.11 -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Install dependencies
pip install -r requirements.txt
Docker (Optional)
docker build -t lung-cancer-api .
docker run -p 5001:5001 lung-cancer-api
Usage
Running Locally
# Development (debug mode enabled)
DEBUG=true python app.py
# Production (debug mode disabled)
python app.py
# Or use Gunicorn
gunicorn app:app --bind 0.0.0.0:5001
Running Tests
Classify a single image using the command-line tool:
source .venv/bin/activate
python test.py /path/to/ct_scan.jpg
Example output: ```
π©Ί LUNG CANCER CLASSIFICATION - DenseNet121
π Image: ct_scan.jpg π Size: (512, 512, 3)
π Running classification...
============================================================ π CLASSIFICATION RESULTS
Adenocarcinoma (Class A) ββββββββββββββββββββ 45.23% Small Cell (Class B) ββββββββββββββββββββ 72.15% Large Cell (Class E) ββββββββββββββββββββ 12.50% Squamous Cell (Class G) ββββββββββββββββββββ 8.12%
============================================================ π₯ FINAL DIAGNOSIS
Classification: Small Cell (Class B) Confidence: 72.15%
β Result saved to 'classification_result.png'
### REST API
**Base URL**: `http://localhost:5001`
#### 1. Health Check
```bash
GET /health
Response: {"status": "healthy", "model_loaded": true}
2. CT Scan Validation (No Classification)
POST /validate-ct
Content-Type: multipart/form-data
file: <image_file>
Response:
{
"is_ct_scan": true,
"color_score": 4.5,
"message": "Valid CT scan - grayscale image detected"
}
3. Full Analysis with Grad-CAM
POST /analyze
Content-Type: multipart/form-data
file: <image_file>
Response (on success):
{
"success": true,
"prediction": "Small Cell (Class B)",
"confidence": 72.15,
"all_confidences": {
"Adenocarcinoma (Class A)": 45.23,
"Small Cell (Class B)": 72.15,
"Large Cell (Class E)": 12.50,
"Squamous Cell (Class G)": 8.12
},
"original_image": "base64_encoded_jpeg_string",
"heatmap_image": "base64_encoded_gradcam_heatmap"
}
Swagger UI
Interactive API documentation available at: http://localhost:5001/docs
Deployment
Railway.app Deployment
Create a Railway account at https://railway.app
Connect your GitHub repository
- Go to Railway dashboard
- Click "New Project" β "Deploy from GitHub repo"
- Select this repository
Configure environment variables in Railway dashboard:
DEBUG=False PORT=5001Deploy
- Railway automatically detects
Procfileand deploys the app - Your API will be available at
https://<your-project>.up.railway.app
- Railway automatically detects
Heroku Deployment (Legacy)
heroku create <app-name>
heroku config:set DEBUG=False
git push heroku main
API Validation
CT Scan Validation Threshold
- Valid CT scans: Color score < 6.0 (grayscale images)
- Rejected: Color score β₯ 6.0 (color photos, non-medical images)
Color score measures RGB channel variance:
- Pure grayscale: 0-2
- Real CT scans: 2-6
- Color photos: 7-100
Confidence Threshold
- Accepted: Confidence β₯ 50%
- Rejected: Confidence < 50% (uncertain predictions)
Configuration
Environment Variables
Create a .env file (or set via environment):
# Flask settings
DEBUG=False # Set to True for development
PORT=5001 # Server port (defaults to 5001)
# Optional overrides
# MODEL_PATH=models/densenet_final_classification.pth
Model Architecture
DenseNet121 (Feature Extractor)
β
[2176 channels]
β
Classifier:
- ReLU Activation
- Linear(2176 β 4) [outputs class logits]
β
Softmax Probabilities
β
4-Class Output:
[Adenocarcinoma, Small Cell, Large Cell, Squamous Cell]
Preprocessing Pipeline
The API uses dual preprocessing for robustness:
- Normalized: ImageNet normalization (mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
- Non-normalized: Raw tensor scaling
Algorithm selects whichever produces higher max confidence, adapting to different training conditions.
Grad-CAM Explanation
Grad-CAM (Gradient-weighted Class Activation Mapping) highlights regions the model focuses on:
- Red/Hot regions: Model focuses heavily (high confidence)
- Blue/Cool regions: Model has low attention (less relevant)
- Alpha blending: 0.4 transparency for visualization
Extracted from: model.features.norm5 (last fully-connected layer before classifier)
Error Handling
| Status | Error | Solution |
|---|---|---|
| 400 | "No file uploaded" | Ensure multipart/form-data with 'file' field |
| 400 | "Invalid input: image does not appear to be a CT scan" | Use actual CT scan (grayscale medical image) |
| 400 | "Confidence too low" | Model uncertain; try another image |
| 500 | "Error processing image" | Check server logs; verify model file exists |
File Structure
Grad-Cam-Backend/
βββ app.py # Main Flask application
βββ test.py # Command-line classification tool
βββ models/
β βββ densenet_final_classification.pth # DenseNet weights
βββ requirements.txt # Python dependencies
βββ Procfile # Railway deployment config
βββ runtime.txt # Python version (3.11.14)
βββ .env.example # Example environment variables
βββ .gitignore # Git ignore patterns
βββ README.md # This file
Class Labels
| Index | Class | Description |
|---|---|---|
| 0 | Adenocarcinoma (Class A) | Most common; develops in glandular cells |
| 1 | Small Cell (Class B) | Aggressive; fast-growing variant |
| 2 | Large Cell (Class E) | Rare; large undifferentiated cells |
| 3 | Squamous Cell (Class G) | Develops in flat cells lining airways |
Performance Tuning
Increase Sensitivity
CONFIDENCE_THRESHOLD = 0.3 # Lower from 0.5 to accept more predictions
# In app.py line ~180
Adjust CT Validation
is_valid = color_score < 8.0 # Raise from 6.0 if rejecting true CTs with color compression
# In app.py line ~157
Troubleshooting
Model fails to load
RuntimeError: Error(s) in loading state_dict for DenseNet:
Missing key(s) in state_dict: ...
Solution: Ensure models/densenet_final_classification.pth exists and matches architecture in load_model().
Port already in use
# Find process using port 5001
lsof -i :5001
# Kill the process
kill -9 <PID>
# Or use different port
PORT=5002 python app.py
Module import errors
# Ensure all dependencies installed
pip install -r requirements.txt
# Verify virtual environment active
source .venv/bin/activate
API Examples
Python Client
import requests
import base64
from PIL import Image
from io import BytesIO
API_URL = "http://localhost:5001"
# Upload and classify CT scan
with open("ct_scan.jpg", "rb") as f:
files = {"file": f}
response = requests.post(f"{API_URL}/analyze", files=files)
result = response.json()
print(f"Diagnosis: {result['prediction']}")
print(f"Confidence: {result['confidence']}%")
# Decode and view heatmap
heatmap_data = base64.b64decode(result['heatmap_image'])
heatmap_img = Image.open(BytesIO(heatmap_data))
heatmap_img.show()
JavaScript/Flutter Client
const formData = new FormData();
formData.append('file', imageFile);
const response = await fetch('http://localhost:5001/analyze', {
method: 'POST',
body: formData
});
const result = await response.json();
console.log(`Diagnosis: ${result.prediction}`);
console.log(`Confidence: ${result.confidence}%`);
// Display heatmap from base64
const img = new Image();
img.src = `data:image/jpeg;base64,${result.heatmap_image}`;
Dependencies
- Flask 3.0.0: REST framework
- Gunicorn 21.2.0: WSGI server
- PyTorch 2.1.0: Deep learning
- TorchVision 0.16.0: Computer vision
- OpenCV 4.8.1.78: Image processing
- Pillow 10.1.0: Image I/O
- NumPy 1.24.3: Array operations
- Flask-CORS 4.0.0: Cross-origin support
- Flasgger 0.9.7.1: Swagger API docs
License
Proprietary - Medical Research Use Only
Support
For issues, email: support@lungcancerapi.com
Last Updated: March 8, 2026
Version: 1.0.0
Status: Production Ready β