Skip to content

Latest commit

 

History

History
467 lines (346 loc) · 9.88 KB

File metadata and controls

467 lines (346 loc) · 9.88 KB

API Documentation

This document describes the Flask API endpoints for the Rice Object Detection system.

Base URL

Local Development:

http://localhost:5000

Production:

http://YOUR_SERVER_IP:5000
https://your-domain.com

Endpoints

1. Root Endpoint

GET /

Returns a welcome message confirming the API is running.

Request:

curl http://localhost:5000/

Response:

Welcome to the Rice Quality Detection API! Send a POST request to /predict with an image.

Status Code: 200 OK


2. Predict Endpoint

POST /predict

Analyzes a rice grain image and returns detection results.

Request Headers:

Content-Type: image/jpeg

Request Body:

  • Raw JPEG image data (binary)

Example with cURL:

curl -X POST \
  -H "Content-Type: image/jpeg" \
  --data-binary @rice_sample.jpg \
  http://localhost:5000/predict

Example with Python:

import requests

url = "http://localhost:5000/predict"
headers = {"Content-Type": "image/jpeg"}

with open("rice_sample.jpg", "rb") as f:
    image_data = f.read()

response = requests.post(url, headers=headers, data=image_data)
print(response.json())

Example with ESP32-CAM (Arduino):

HTTPClient http;
http.begin("http://YOUR_SERVER_IP:5000/predict");
http.addHeader("Content-Type", "image/jpeg");

int httpResponseCode = http.POST(fb->buf, fb->len);
String response = http.getString();

Response Format

Success Response (200 OK):

{
  "detections": [
    {
      "box": [120, 85, 245, 210],
      "confidence": 0.87,
      "label": "Damaged"
    },
    {
      "box": [300, 150, 425, 275],
      "confidence": 0.92,
      "label": "Discolored"
    },
    {
      "box": [50, 200, 175, 325],
      "confidence": 0.78,
      "label": "Good"
    }
  ],
  "bad_rice_detected": true
}

Response Fields:

Field Type Description
detections Array List of all detected objects in the image
detections[].box Array[int] Bounding box coordinates [x1, y1, x2, y2]
detections[].confidence Float Detection confidence score (0.0 to 1.0)
detections[].label String Detected class name
bad_rice_detected Boolean true if any defective rice is detected, false otherwise

Bounding Box Format:

  • x1, y1: Top-left corner coordinates
  • x2, y2: Bottom-right corner coordinates
  • Coordinates are in pixels relative to the input image

Error Responses

415 Unsupported Media Type:

{
  "error": "Unsupported Media Type. Expected image/jpeg"
}

Cause: Incorrect Content-Type header or non-JPEG image data

Solution: Ensure Content-Type: image/jpeg header is set and image is in JPEG format


400 Bad Request:

{
  "error": "Invalid image data"
}

Cause: Corrupted or unreadable image data

Solution: Verify image is valid JPEG and not corrupted during transmission


Detection Classes

The model detects the following rice quality classes:

Class ID Label Description Triggers Relay
0 Good Healthy rice grain ❌ No
1 Damaged Physically damaged grain ✅ Yes
2 Discolored Color abnormalities ✅ Yes
3 Broken Fractured or incomplete grain ✅ Yes
4 Chalky Opaque or chalky appearance ✅ Yes
5 Organic Foreign Matters Non-rice contaminants ✅ Yes

Note

The bad_rice_detected flag is set to true if any of the defect classes (Damaged, Discolored, Broken, Chalky, Organic Foreign Matters) are detected.

Server-Side Configuration

Modifying Bad Rice Labels

To change which classes trigger the relay, edit server/app.py:

BAD_RICE_LABELS = ['Damaged', 'Discolored', 'Broken', 'Chalky', 'Organic Foreign Matters']

Example: To only trigger on "Damaged" and "Broken":

BAD_RICE_LABELS = ['Damaged', 'Broken']

Model Configuration

Current model settings in app.py:

MODEL_PATH = '../models/best.pt'  # Path to YOLOv8 model

To use a different model:

MODEL_PATH = '../models/your_custom_model.pt'

Performance Metrics

The server logs performance metrics for each request:

Image reception and decoding time: 0.0234 seconds
Model inference time: 0.1456 seconds
Total processing time on server: 0.1690 seconds
Detected 3 objects. Bad rice detected: True
--------------------------------------------------

Typical Performance:

  • Image Reception: 10-50ms
  • Model Inference: 100-500ms (CPU), 20-100ms (GPU)
  • Total Processing: 150-600ms

Integration Examples

ESP32-CAM Full Integration

// Capture image
camera_fb_t *fb = esp_camera_fb_get();

// Send to server
HTTPClient http;
http.begin(SERVER_URL);
http.addHeader("Content-Type", "image/jpeg");

int httpResponseCode = http.POST(fb->buf, fb->len);

if (httpResponseCode > 0) {
  String response = http.getString();
  
  // Parse JSON
  StaticJsonDocument<512> doc;
  deserializeJson(doc, response);
  
  bool badRiceDetected = doc["bad_rice_detected"] | false;
  
  if (badRiceDetected) {
    // Activate relay
    digitalWrite(RELAY_GPIO_NUM, HIGH);
    delay(1000);
    digitalWrite(RELAY_GPIO_NUM, LOW);
  }
}

http.end();
esp_camera_fb_return(fb);

Python Client

import requests
import json

def detect_rice_quality(image_path, server_url):
    """
    Send image to rice detection API and return results.
    
    Args:
        image_path: Path to JPEG image file
        server_url: API endpoint URL
    
    Returns:
        dict: Detection results
    """
    headers = {"Content-Type": "image/jpeg"}
    
    with open(image_path, "rb") as f:
        image_data = f.read()
    
    response = requests.post(server_url, headers=headers, data=image_data)
    
    if response.status_code == 200:
        results = response.json()
        print(f"Detections: {len(results['detections'])}")
        print(f"Bad rice detected: {results['bad_rice_detected']}")
        return results
    else:
        print(f"Error: {response.status_code} - {response.text}")
        return None

# Usage
results = detect_rice_quality(
    "rice_sample.jpg",
    "http://localhost:5000/predict"
)

JavaScript (Node.js)

const fs = require('fs');
const axios = require('axios');

async function detectRiceQuality(imagePath, serverUrl) {
    const imageBuffer = fs.readFileSync(imagePath);
    
    try {
        const response = await axios.post(serverUrl, imageBuffer, {
            headers: {
                'Content-Type': 'image/jpeg'
            }
        });
        
        console.log('Detections:', response.data.detections.length);
        console.log('Bad rice detected:', response.data.bad_rice_detected);
        return response.data;
    } catch (error) {
        console.error('Error:', error.message);
        return null;
    }
}

// Usage
detectRiceQuality(
    'rice_sample.jpg',
    'http://localhost:5000/predict'
);

Rate Limiting

Currently, there is no rate limiting implemented. For production use, consider adding rate limiting to prevent abuse:

from flask_limiter import Limiter
from flask_limiter.util import get_remote_address

limiter = Limiter(
    app,
    key_func=get_remote_address,
    default_limits=["100 per hour", "10 per minute"]
)

@app.route('/predict', methods=['POST'])
@limiter.limit("30 per minute")
def predict():
    # ... existing code

Authentication

Currently, the API is open (no authentication required). For production deployment, consider implementing:

Option 1: API Token

API_TOKEN = "your-secret-token"

@app.route('/predict', methods=['POST'])
def predict():
    token = request.headers.get('Authorization')
    if token != f"Bearer {API_TOKEN}":
        return jsonify({"error": "Unauthorized"}), 401
    # ... existing code

Client usage:

curl -X POST \
  -H "Content-Type: image/jpeg" \
  -H "Authorization: Bearer your-secret-token" \
  --data-binary @rice_sample.jpg \
  http://localhost:5000/predict

Option 2: IP Whitelisting

ALLOWED_IPS = ['192.168.1.100', '10.0.0.50']

@app.route('/predict', methods=['POST'])
def predict():
    if request.remote_addr not in ALLOWED_IPS:
        return jsonify({"error": "Forbidden"}), 403
    # ... existing code

Testing the API

Using Postman

  1. Create New Request

    • Method: POST
    • URL: http://localhost:5000/predict
  2. Set Headers

    • Key: Content-Type
    • Value: image/jpeg
  3. Set Body

    • Type: binary
    • Select a JPEG image file
  4. Send Request

Using Sample Images

Test with sample rice images:

# Download sample image
curl -o rice_sample.jpg https://example.com/rice_sample.jpg

# Test API
curl -X POST \
  -H "Content-Type: image/jpeg" \
  --data-binary @rice_sample.jpg \
  http://localhost:5000/predict

Troubleshooting

Empty Detections Array

{
  "detections": [],
  "bad_rice_detected": false
}

Possible Causes:

  • No rice grains in image
  • Image quality too poor
  • Model confidence threshold not met
  • Incorrect camera positioning

Solutions:

  • Improve lighting
  • Adjust camera distance
  • Ensure rice grains are visible
  • Lower confidence threshold in model

Slow Response Times

Causes:

  • Large image size
  • CPU inference (no GPU)
  • Network latency

Solutions:

  • Reduce image resolution from ESP32-CAM
  • Use GPU-enabled server
  • Optimize model (quantization)
  • Deploy server closer to ESP32-CAM

Additional Resources


For hardware setup, see: Hardware Setup Guide
For deployment instructions, see: Deployment Guide