A Decision-Support System for Prioritising Plastic Cleanup Operations Using Calibrated Detection & Severity Ranking.
- Overview
- Features
- Prerequisites
- Installation
- Configuration
- Running the App
- Usage Guide
- API Endpoints
- PSI Scoring
- Project Structure
- Troubleshooting
MarineOps is a web application that helps marine conservation teams decide where to send cleanup crews first. Upload drone or satellite images of a coastal area, and the system will:
- Detect plastic debris using a YOLOv8 model
- Calculate a Plastic Severity Index (PSI) score per image and per location
- Rank locations by severity so you know exactly where to act
- πΈ Image upload with automatic validation (resolution, size, format)
- π YOLOv8 detection β identifies 9 classes of marine debris
- π PSI scoring β per-image and aggregated per-location severity scores
- πΊοΈ Interactive dashboard β charts, maps, and trend analysis via Plotly Dash
- π Detection history β browse all past scans, filter by location
- π Export reports β download results as PDF or CSV
- βοΈ Model calibration β isotonic regression to improve confidence accuracy
Before you begin, make sure you have the following installed:
- Python 3.10+ β python.org
- PostgreSQL 14+ β postgresql.org
- pgAdmin 4 (optional, for database inspection) β pgadmin.org
- Git β git-scm.com
git clone https://github.com/your-username/marineops.git
cd marineopspython -m venv .venv
# Windows
.venv\Scripts\activate
# macOS / Linux
source .venv/bin/activatepip install fastapi uvicorn[standard] sqlalchemy ultralytics scikit-learn \
reportlab numpy opencv-python pandas python-dotenv \
python-multipart httpx pillow dash plotly psycopg2-binary jinja2Open pgAdmin or psql and run:
CREATE DATABASE marineops;Copy your trained YOLOv8 weights into the project root:
marineops/
βββ best.pt β place here
Create a .env file in the project root:
DATABASE_URL=postgresql://postgres:yourpassword@localhost:5432/marineopsReplace yourpassword with your PostgreSQL password.
Run this once before the first launch:
python -c "from database import Base, engine; Base.metadata.create_all(bind=engine)"uvicorn main:app --reload --port 8000| URL | Description |
|---|---|
| http://localhost:8000 | Main application |
| http://localhost:8000/docs | API documentation (Swagger UI) |
| http://localhost:8000/dashboard | Plotly Dash analytics |
- Go to the Upload page
- Select an image file (JPEG, PNG β min 320Γ320px, max 20MB)
- Enter the location name (e.g.
Choisy,Grand Baie) - Click Detect β results appear within seconds
Go to the History page to see:
- Photo Upload History β one row per image, with PSI score, object count, confidence, and timestamp
- Location History β one row per location, with aggregated PSI, total objects, and severity
Use the Filter by location box to search. Clearing it shows all records.
From the History page, click:
- β¬ CSV β downloads a spreadsheet of all detections
- β¬ PDF β downloads a formatted report
If you have a labelled validation dataset, run calibration to improve confidence accuracy:
curl -X POST http://localhost:8000/calibrateOr use the Calibrate button in the UI. The calibrator is saved automatically and loaded on every server restart.
| Method | Endpoint | Description |
|---|---|---|
POST |
/validate |
Validate an image before detection |
POST |
/detect |
Run detection on an uploaded image |
POST |
/calibrate |
Train the confidence calibrator |
GET |
/analytics |
Get aggregated statistics (supports ?location= filter) |
GET |
/report/csv |
Download CSV report |
GET |
/report/pdf |
Download PDF report |
Full interactive docs at http://localhost:8000/docs.
The Plastic Severity Index measures how polluted a scanned area is.
PSI (per object) = class_weight Γ calibrated_confidenceΒ² Γ (object_area / image_area)
PSI (per image) = Ξ£(PSI per object) Γ 100
PSI (per location) = Ξ£(PSI per image) for all images at that location
| Class | Weight |
|---|---|
fishing_net |
2.0 |
buoy |
2.0 |
other_fishing_gear |
2.0 |
pet_bottle |
1.5 |
other_bottle |
1.5 |
other_container |
1.5 |
styrene_foam |
1.2 |
fragment |
1.0 |
| PSI | Severity |
|---|---|
| < 0.5 | π’ Low |
| 0.5 β 1.49 | π‘ Moderate |
| 1.5 β 2.99 | π High |
| β₯ 3.0 | π΄ Critical |
marineops/
βββ main.py # FastAPI app β all endpoints
βββ database.py # SQLAlchemy models and DB session
βββ dashboard.py # Plotly Dash app
βββ best.pt # YOLOv8 model weights
βββ calibrator.pkl # Saved calibrator (auto-generated)
βββ .env # Environment variables (not committed)
βββ uploads/ # Uploaded images (auto-created)
βββ static/
β βββ css/
β β βββ style.css
β βββ js/
β β βββ app.js
β βββ assets/
β βββ logo.png
βββ templates/
βββ index.html
Server won't start
# Make sure you're in the virtual environment
.venv\Scripts\activate # Windows
source .venv/bin/activate # macOS/Linux
# Then start
uvicorn main:app --reload --port 8000Database connection error
- Check your
.envfile has the correct password - Make sure PostgreSQL is running
- Confirm the
marineopsdatabase exists in pgAdmin
best.pt not found
- Place your YOLOv8 weights file in the project root and name it
best.pt
Port already in use
uvicorn main:app --reload --port 8080
# Then visit http://localhost:8080Static files returning 404
- Make sure the
static/folder exists in the project root - Check that
app.mount("/static", ...)appears before the dashboard mount inmain.py
This project was developed as part of an undergraduate research project at Middlesex University.