Summary:

According to Earth.org, over 100,000 marine animals die each year due to plastic pollution in our oceans. This alarming statistic inspired me to take action. I developed an Object Detection AI named OceanWatch using a public dataset from Kaggle and the YOLOv8 model. OceanWatch is designed to detect pollution in aquatic environments. When pollution is identified, the AI alerts a designated phone number and sends the last five seconds of footage, enabling quick and accurate identification of the pollution source.

To ensure this solution is portable and functional beyond a laptop, I'm utilizing Raspberry Pi hardware paired with a Raspberry Pi camera to detect ocean water pollution in real-time.

WhatsApp Image 2024-08-24 at 3.10.45 PM.jpeg

To validate the accuracy of this object detection AI, I used a video for testing since I don’t have access to an ocean for live trials. You can view the side-by-side comparison here:

https://drive.google.com/file/d/10C56BenBvfAIFT_f99V1LIioOJgab7a_/preview

Here is my code for the camera detection:

import os
import time
from collections import deque
from datetime import datetime, timedelta
from threading import Thread

import cv2
from ultralytics import YOLO

from email_send_v1 import send_mail

model_path = os.path.join('.', 'runs', 'detect', 'train2', 'weights', 'best.pt')
model = YOLO(model_path)

input_video_path = r"filepath.mp4"
cap = cv2.VideoCapture(input_video_path)

threshold = 0.5
fps = cap.get(cv2.CAP_PROP_FPS)
buffer_size = int(fps * 5)

frame_buffer = deque(maxlen=buffer_size)
last_video_time = None
cooldown_time = timedelta(seconds=5)

output_folder = 'sending_videos'
os.makedirs(output_folder, exist_ok=True)

def save_video(buffer, fps):
    if len(buffer) == 0:
        return

    height, width, _ = buffer[0][1].shape
    fourcc = cv2.VideoWriter_fourcc(*'mp4v')
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    output_path = os.path.join(output_folder, f'{timestamp}.mp4')
    out = cv2.VideoWriter(output_path, fourcc, fps, (width, height))

    for _, frame in buffer:
        out.write(frame)

    out.release()
    send_mail(fr"sending_videos\\{timestamp}.mp4", 1)

def cleanup_old_videos():
    while True:
        now = time.time()
        for filename in os.listdir(output_folder):
            file_path = os.path.join(output_folder, filename)
            if os.path.isfile(file_path):
                file_age = now - os.path.getmtime(file_path)
                if file_age > 60:
                    os.remove(file_path)
        time.sleep(30)

cleanup_thread = Thread(target=cleanup_old_videos, daemon=True)
cleanup_thread.start()

while True:
    ret, frame = cap.read()

    frame_buffer.append((time.time(), frame.copy()))

    results = model(frame)[0]

    for result in results.boxes.data.tolist():
        x1, y1, x2, y2, score, class_id = result

        if score > threshold and class_id != 1:
            cv2.rectangle(frame, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 4)
            cv2.putText(frame, results.names[int(class_id)].upper(), (int(x1), int(y1 - 10)), cv2.FONT_HERSHEY_SIMPLEX,
                        1.3, (0, 255, 0), 3, cv2.LINE_AA)

            current_time = datetime.now()

            if (last_video_time is None or current_time - last_video_time >= cooldown_time) and len(
                    frame_buffer) >= buffer_size:
                save_thread = Thread(target=save_video, args=(list(frame_buffer), fps))
                save_thread.start()
                frame_buffer.clear()
                last_video_time = current_time

    resized_frame = cv2.resize(frame, (800, 450))
    cv2.imshow('OceanWatch', resized_frame)

    if cv2.waitKey(1) == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

Here is my code for sending the text message:

import os
import smtplib
import ssl
from email import encoders
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

from moviepy.editor import VideoFileClip

def compress_video(file_path):
    clip = VideoFileClip(file_path)
    width, height = clip.size
    if height > 720:
        clip_resized = clip.resize(height=360)
        compressed_path = file_path.replace(".mp4", "_compressed.mp4")
        clip_resized.write_videofile(compressed_path, codec="libx264")
        return compressed_path
    else:
        return file_path

def send_mail(file_path, cameranum):
    sender_mail = "[email protected]"
    receiver_mail = "[email protected]"
    subject = "Litter Detected!"
    body = (f"Litter has been detected from Camera #{cameranum}. Please dispatch cleaning officers to prevent "
            f"further damage to the environment.")
    password = "password"

    if file_path.lower().endswith(('.mp4', '.avi', '.mov', '.mkv')):
        file_path = compress_video(file_path)

    message = MIMEMultipart()
    message["From"] = sender_mail
    message["To"] = receiver_mail
    message["Subject"] = subject

    message.attach(MIMEText(body, "plain"))

    with open(file_path, "rb") as attachment:
        part = MIMEBase("application", "octet-stream")
        part.set_payload(attachment.read())

    encoders.encode_base64(part)
    part.add_header("Content-Disposition", f"attachment; filename= {os.path.basename(file_path)}")

    message.attach(part)

    context = ssl.create_default_context()

    with smtplib.SMTP_SSL("smtp.gmail.com", 465, context=context) as server:
        server.login(sender_mail, password)
        server.sendmail(sender_mail, receiver_mail, message.as_string())

Works Cited: