# Inference Guide

## Overview

This guide covers model inference and deployment for YOLOv8 French ID Card Detection models.

## 🎯 Inference Process

### 1. Basic Inference

#### Single Image Inference
```bash
python inference.py --input path/to/image.jpg
```

#### Batch Inference
```bash
python inference.py --input path/to/images/ --batch
```

### 2. Advanced Inference

#### Custom Model
```bash
python inference.py --model runs/train/yolov8_n_french_id_card/weights/best.pt --input image.jpg
```

#### Custom Thresholds
```bash
python inference.py --input image.jpg --conf 0.5 --iou 0.5
```

#### Output Directory
```bash
python inference.py --input image.jpg --output results/
```

## 📊 Understanding Results

### Detection Output Format

```python
{
    "image_path": "path/to/image.jpg",
    "detections": [
        {
            "bbox": [x1, y1, x2, y2],  # Bounding box coordinates
            "confidence": 0.95,          # Confidence score
            "class": "french",           # Class name
            "class_id": 0                # Class ID
        }
    ],
    "processing_time": 0.003,           # Inference time (seconds)
    "image_size": [640, 480]            # Original image size
}
```

### Visualization Output

The inference script generates:
- **Bounding boxes**: Drawn on detected ID cards
- **Confidence scores**: Displayed above each detection
- **Processing time**: Shown in console output

## 🚀 Performance Optimization

### Speed Optimization

#### Model Size Impact
```bash
# Fastest inference (nano model)
python inference.py --model-size n --input image.jpg

# Balanced speed/accuracy (small model)
python inference.py --model-size s --input image.jpg

# High accuracy (medium model)
python inference.py --model-size m --input image.jpg
```

#### GPU vs CPU
```bash
# GPU inference (recommended)
python inference.py --input image.jpg

# CPU inference (if no GPU)
export CUDA_VISIBLE_DEVICES=""
python inference.py --input image.jpg
```

### Memory Optimization

```bash
# Reduce batch size for large images
python inference.py --input images/ --batch --batch-size 4

# Use smaller image size
python inference.py --input image.jpg --img-size 416
```

## 📁 Output Structure

### Results Directory

```
runs/detect/
├── predict1/              # Latest inference run
│   ├── image1.jpg        # Original image with detections
│   ├── image2.jpg        # Another image with detections
│   └── labels/           # Detection labels (YOLO format)
├── predict2/              # Another inference run
└── ...
```

### Label Format

```
# YOLO format labels (class x_center y_center width height confidence)
0 0.5 0.3 0.2 0.4 0.95
```

## 🔧 Customization

### Confidence Thresholds

```bash
# High precision (fewer false positives)
python inference.py --input image.jpg --conf 0.7

# High recall (more detections)
python inference.py --input image.jpg --conf 0.3

# Balanced approach
python inference.py --input image.jpg --conf 0.5
```

### IoU Thresholds

```bash
# Strict overlap requirements
python inference.py --input image.jpg --iou 0.7

# Lenient overlap requirements
python inference.py --input image.jpg --iou 0.3
```

### Output Formats

```bash
# Save as images with bounding boxes
python inference.py --input image.jpg --save-images

# Save detection coordinates
python inference.py --input image.jpg --save-txt

# Save confidence scores
python inference.py --input image.jpg --save-conf
```

## 📈 Batch Processing

### Directory Processing

```bash
# Process all images in directory
python inference.py --input data/test/images/ --batch

# Process with custom output
python inference.py --input images/ --output results/ --batch
```

### Video Processing

```bash
# Process video file
python inference.py --input video.mp4

# Process webcam
python inference.py --input 0
```

### Real-time Processing

```python
# Custom real-time script
from ultralytics import YOLO
import cv2

model = YOLO('runs/train/yolov8_n_french_id_card/weights/best.pt')

cap = cv2.VideoCapture(0)
while cap.isOpened():
    ret, frame = cap.read()
    results = model(frame)
    
    # Process results
    annotated_frame = results[0].plot()
    cv2.imshow('Detection', annotated_frame)
    
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()
```

## 🔍 Error Handling

### Common Issues

**1. Model Not Found**
```bash
# Check available models
ls runs/train/*/weights/

# Use default model
python inference.py --input image.jpg
```

**2. Image Not Found**
```bash
# Check file path
ls -la path/to/image.jpg

# Use absolute path
python inference.py --input /full/path/to/image.jpg
```

**3. Memory Issues**
```bash
# Reduce image size
python inference.py --input image.jpg --img-size 416

# Use smaller model
python inference.py --model-size n --input image.jpg
```

### Debug Mode

```bash
# Enable verbose output
python inference.py --input image.jpg --verbose

# Check model loading
python -c "from ultralytics import YOLO; model = YOLO('model.pt'); print('Model loaded successfully')"
```

## 🎯 Production Deployment

### Docker Deployment

```dockerfile
# Dockerfile
FROM python:3.9-slim

WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .
EXPOSE 8000

CMD ["python", "inference.py", "--input", "0"]
```

### API Integration

```python
# app.py
from flask import Flask, request, jsonify
from ultralytics import YOLO
import cv2
import numpy as np

app = Flask(__name__)
model = YOLO('runs/train/yolov8_n_french_id_card/weights/best.pt')

@app.route('/detect', methods=['POST'])
def detect():
    file = request.files['image']
    image = cv2.imdecode(np.frombuffer(file.read(), np.uint8), cv2.IMREAD_COLOR)
    
    results = model(image)
    detections = []
    
    for result in results:
        boxes = result.boxes
        for box in boxes:
            detection = {
                'bbox': box.xyxy[0].tolist(),
                'confidence': float(box.conf[0]),
                'class': 'french'
            }
            detections.append(detection)
    
    return jsonify({'detections': detections})

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=8000)
```

### Web Interface

```html
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
    <title>ID Card Detection</title>
</head>
<body>
    <h1>French ID Card Detection</h1>
    <input type="file" id="imageInput" accept="image/*">
    <button onclick="detect()">Detect</button>
    <canvas id="canvas"></canvas>
    
    <script>
        async function detect() {
            const file = document.getElementById('imageInput').files[0];
            const formData = new FormData();
            formData.append('image', file);
            
            const response = await fetch('/detect', {
                method: 'POST',
                body: formData
            });
            
            const result = await response.json();
            console.log(result.detections);
        }
    </script>
</body>
</html>
```

## 📊 Performance Monitoring

### Speed Benchmarks

| Model Size | GPU (ms) | CPU (ms) | Memory (MB) |
|------------|----------|----------|-------------|
| n (nano)   | 2-5      | 20-50    | 100-200     |
| s (small)  | 4-8      | 40-80    | 200-400     |
| m (medium) | 8-15     | 80-150   | 400-800     |
| l (large)  | 12-25    | 120-250  | 800-1600    |

### Accuracy Benchmarks

| Model Size | mAP50 | Precision | Recall |
|------------|-------|-----------|--------|
| n (nano)   | 0.995 | 1.0       | 0.99   |
| s (small)  | 0.998 | 1.0       | 0.99   |
| m (medium) | 0.999 | 1.0       | 0.99   |
| l (large)  | 0.999 | 1.0       | 0.99   |

## 🔧 Advanced Features

### Custom Post-processing

```python
# Custom detection filtering
def filter_detections(detections, min_area=1000, max_area=50000):
    filtered = []
    for det in detections:
        bbox = det['bbox']
        area = (bbox[2] - bbox[0]) * (bbox[3] - bbox[1])
        if min_area <= area <= max_area:
            filtered.append(det)
    return filtered
```

### Multi-scale Detection

```python
# Detect at multiple scales
def multi_scale_detect(model, image, scales=[0.5, 1.0, 1.5]):
    all_detections = []
    for scale in scales:
        resized = cv2.resize(image, None, fx=scale, fy=scale)
        results = model(resized)
        # Process results...
    return all_detections
```

## 📋 Inference Checklist

- [ ] Model trained and evaluated
- [ ] Input images available
- [ ] GPU/CPU resources sufficient
- [ ] Output directory writable
- [ ] Appropriate thresholds set
- [ ] Error handling implemented

## 🎯 Best Practices

### 1. Threshold Selection

```bash
# Start with default thresholds
python inference.py --input image.jpg

# Adjust based on use case
python inference.py --input image.jpg --conf 0.5 --iou 0.5
```

### 2. Performance Optimization

```bash
# Use GPU if available
python inference.py --input image.jpg

# Batch process for efficiency
python inference.py --input images/ --batch
```

### 3. Quality Assurance

```bash
# Validate detections
python eval.py --model-size n

# Test on sample images
python inference.py --input test_images/ --batch
```

---

**Note**: Inference performance depends on hardware, model size, and image complexity. 