UNIHIKER: Flame detection

0 471 Easy

In this tiny fun tutorial, I walk you through building a flame detection system using the UNIHIKER IoT Python single-board computer, a DC motor driver carrier board, and a USB camera. The system will detect flames in real-time using computer vision techniques and provide visual feedback via an LED indicator.

HARDWARE LIST
1 UNIHIKER
1 2x3A DC Motor Driver Carrier Board
1 USB camera
1 Lighter
STEP 1
Python code

The provided Python script leverages OpenCV for flame detection by analyzing the color spectrum typical of flames (yellow, orange, and red). When a flame is detected, the LEDs will light up as an alert.

CODE
from datetime import datetime
from sys import exit
from threading import Thread
from time import sleep

from numpy import ndarray
from pinpong.board import Board, Pin, NeoPixel
import cv2 as cv
import numpy as np


DISPLAY_WIDTH: int = 240
DISPLAY_HEIGHT: int = 320

DURATION: float = .5
LED_BLACK: tuple = (0, 0, 0)
LED_RED: tuple = (100, 0, 0)

LOWER_YELLOW: ndarray = np.array([18, 100, 100])
UPPER_YELLOW: ndarray = np.array([35, 255, 255])
LOWER_ORANGE: ndarray = np.array([5, 100, 100])
UPPER_ORANGE: ndarray = np.array([18, 255, 255])
LOWER_RED_1: ndarray = np.array([0, 100, 100])
UPPER_RED_1: ndarray = np.array([5, 255, 255])
LOWER_RED_2: ndarray = np.array([170, 100, 100])
UPPER_RED_2: ndarray = np.array([180, 255, 255])


def is_flame_detected(image: np.ndarray, sensitivity: int) -> bool:
    """
    Detects if a flame is present in the given image.

    :param image: The image to detect the flame in.
    :type image: np.ndarray
    :param sensitivity: The sensitivity level for detecting the flame (smaller values will detect smaller flames).
    :type sensitivity: int
    :return: True if a flame is detected, False otherwise.
    :rtype: bool
    """
    hsv = cv.cvtColor(image, cv.COLOR_BGR2HSV)

    mask_yellow = cv.inRange(hsv, LOWER_YELLOW, UPPER_YELLOW)
    mask_orange = cv.inRange(hsv, LOWER_ORANGE, UPPER_ORANGE)
    mask_red1 = cv.inRange(hsv, LOWER_RED_1, UPPER_RED_1)
    mask_red2 = cv.inRange(hsv, LOWER_RED_2, UPPER_RED_2)

    mask = mask_yellow | mask_orange | mask_red1 | mask_red2

    kernel = np.ones((5, 5), np.uint8)
    mask = cv.morphologyEx(mask, cv.MORPH_OPEN, kernel)
    mask = cv.morphologyEx(mask, cv.MORPH_CLOSE, kernel)

    contours, _ = cv.findContours(mask, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)

    for contour in contours:
        area = cv.contourArea(contour)
        if area > sensitivity:
            x, y, w, h = cv.boundingRect(contour)
            aspect_ratio = float(w) / h
            if 0.2 < aspect_ratio < 1.0:
                hull = cv.convexHull(contour)
                hull_area = cv.contourArea(hull)
                solidity = float(area) / hull_area
                if solidity > 0.5:
                    return True

    return False


def on_trackbar(val: int) -> None:
    """
    Callback function for the trackbar to update the sensitivity threshold.

    :param val: The new value of the trackbar.
    :type val: int
    :return: None
    """
    global sensitivity_threshold

    sensitivity_threshold = val


def set_led_color(duration: float, neopixel: NeoPixel) -> None:
    """
    Sets the color of the LEDs in a NeoPixel strip for a specified duration.

    :param duration: The duration (in seconds) for which the LEDs will display the color.
    :type duration: float
    :param neopixel: The NeoPixel strip object.
    :type neopixel: NeoPixel
    :return: None
    """
    for led in range(3):
        neopixel[led] = LED_RED

    sleep(duration)

    for led in range(3):
        neopixel[led] = LED_BLACK


def run_led_thread(duration: float, neopixel: NeoPixel) -> None:
    """
    Run LED Thread

    :param duration: The duration of the LED thread in seconds.
    :type duration: float
    :param neopixel: The neopixel object.
    :type neopixel: NeoPixel
    :return: None
    """
    led_thread = Thread(target=set_led_color, args=(duration, neopixel))
    led_thread.start()


if __name__ == '__main__':
    Board("UNIHIKER").begin()

    np_led = NeoPixel(pin_obj=Pin(Pin.P13), num=3)

    sensitivity_threshold = 2500

    cap = cv.VideoCapture(0)
    if not cap.isOpened():
        print('[ERROR] Could not open camera')
        exit(1)

    cap.set(cv.CAP_PROP_FRAME_WIDTH, DISPLAY_WIDTH)
    cap.set(cv.CAP_PROP_FRAME_HEIGHT, DISPLAY_HEIGHT)
    cap.set(cv.CAP_PROP_BUFFERSIZE, 1)

    cv.namedWindow('display_window', cv.WND_PROP_FULLSCREEN)
    cv.setWindowProperty('display_window', cv.WND_PROP_FULLSCREEN, cv.WINDOW_FULLSCREEN)

    cv.createTrackbar('Sensitivity', 'display_window', sensitivity_threshold, 5000, on_trackbar)

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

        if not ret:
            break

        if cv.waitKey(1) & 0xff == ord('q'):
            break

        flipped_frame = cv.flip(frame, 1)
        flipped_frame.flags.writeable = False

        flame_detected = is_flame_detected(flipped_frame, sensitivity_threshold)

        if flame_detected:
            now = datetime.now()
            current_time = now.strftime("%Y-%m-%d %H:%M:%S")
            print(f"Flame detected at {current_time}")
            run_led_thread(duration=DURATION, neopixel=np_led)

        cv.imshow('display_window', flipped_frame)

    cap.release()
    cv.destroyAllWindows()
STEP 2
Upload via SCP/SMB

To upload the Python script to the UNIHIKER device, you can use SCP or SMB.

STEP 3
Application Run

Connect the USB camera to the UNIHIKER.

 

Power up the UNIHIKER and open a terminal.

 

Navigate to the directory where the script was uploaded and start.

 

Attention: Be careful with the fire!

 

You can use the slider to adjust the sensitivity and adapt it to the environment.

STEP 4
Annotations

What More Can Be Done?

 

Motorized Fire Suppression System: Use the motor driver to control a small motorized fire suppression system that activates when a flame is detected.

 

Cloud Integration: Send notifications or alerts to a cloud service or a smartphone application whenever a flame is detected.

 

Data Logging: Log flame detection events with timestamps to a file or database for later analysis.

Ideas for Expansion

 

Temperature Monitoring: Integrate a temperature sensor to enhance flame detection reliability.

 

Multiple Camera Support: Use multiple cameras to cover a larger area or different angles for flame detection.

 

Voice Alert System: Add a speaker and use text-to-speech to announce when a flame is detected.

License
All Rights
Reserved
licensBg
0