基于颜色空间的火灾检测

使用python语言,基于OTSU算法写一段视频火灾检测的代码,要求如下:
1.对视频的每一帧先利用公式gray=1.6r-g-0.8b,得到相应的灰度图,再利用otsu算法进行二值化,对每一帧执行先腐蚀再膨胀去除噪声,最终得到二值化视频
2.对于二值化视频中的每一帧,合并距离较近的火灾区域,去除面积较小的火灾区域,同时在两个窗口分别展示未经过任何处理的原视频和最终的二值化视频
3.计算二值化视频中所检测到的火灾面积和火灾个数,并且把对应数值在两个视频上面进行实时展示
4.两个视频均实时显示FPs,即每秒可以处理视频的帧数,在两个视频中均实时显示每秒钟火灾面积的大小,即变化速度
5.计算当前帧火灾区域与100帧前的火灾区域的交集和并集的比值,并把结果在两个视频上面进行实时展示
6.增加一个静止的空白画布,画布的大小和视频帧的大小一致,每间隔1秒钟,计算二值化视频帧中所检测到的火灾形心(只有一个)坐标,并把当前帧火灾形心坐标添加画布的对应位置,也就是每1秒钟空白窗口上面多一个点

import cv2
import numpy as np
import time


def detect_fire_in_video(video_file):
    cap = cv2.VideoCapture(video_file)

    # 获取视频文件的FPS
    original_FPS = cap.get(cv2.CAP_PROP_FPS)

    previous_frame_fire_area = 0  # 前一帧的火灾面积
    previous_time = time.time()  # 开始时间

    # 存储过去100帧的数据
    past_frames = []

    # 创建空白画布,大小和视频帧一致
    blank_canvas = np.zeros((int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)), int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), 3),
                            dtype=np.uint8)

    while (cap.isOpened()):
        # 计数器,记录火灾的个数和面积
        fire_count = 0
        fire_area = 0

        ret, frame = cap.read()
        if ret == True:
            current_time = time.time()

            # 初始化FPS和火灾面积变化速度
            fps = 0
            fire_area_change_rate = 0

            # 获取处理开始时的时间
            start = time.time()

            # Get original frame for contour drawing
            original_frame = frame.copy()

            # 格式化像素值为 float 类型
            frame = np.float32(frame)

            # 根据给定公式创建灰度图像
            gray = 1.6 * frame[:, :, 2] - frame[:, :, 1] - 0.8 * frame[:, :, 0]

            # Normalize gray scale image and convert to uint8
            gray = cv2.normalize(gray, None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)

            # Using Otsu's binarization
            _, binary = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

            # 使用腐蚀和膨胀去噪
            kernel = np.ones((5, 5), np.uint8)
            binary = cv2.erode(binary, kernel, iterations=1)
            binary = cv2.dilate(binary, kernel, iterations=1)

            # 当前帧添加进列表中
            past_frames.append(binary)

            # 如果累积的帧数大于100,移除最老的帧
            if len(past_frames) > 100:
                past_frames.pop(0)

            # 计算交集和并集的比值
            if len(past_frames) == 100:
                intersection = cv2.bitwise_and(past_frames[-1], past_frames[0])
                union = cv2.bitwise_or(past_frames[-1], past_frames[0])
                intersection_over_union = np.sum(intersection) / np.sum(union) if np.sum(
                    union) != 0 else 0  # 如果 union 非0,算比值,否则比值为0。

            # Find and filter small fire areas
            contours, _ = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
            for cnt in contours:
                if cv2.contourArea(cnt) < 5000:
                    continue
                fire_count += 1
                fire_area += cv2.contourArea(cnt)

            # 计算处理这一帧图像所用的时间和FPS
            time_diff = time.time() - start
            fps = 1 / time_diff if time_diff != 0 else original_FPS  # 如果 time_diff 非0, fps = 1/time_diff,否则使用原视频的FPS

            # 计算火灾面积的变化速度(每秒钟)
            fire_area_change_rate = (fire_area - previous_frame_fire_area) / (current_time - previous_time)

            # 在视频上展示火灾的个数、面积、FPS、火灾面积变化速度以及并交比值
            cv2.putText(original_frame, "Fire Count: %d" % fire_count, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7,
                        (0, 0, 255), 2)
            cv2.putText(original_frame, "Fire Area: %.2f" % fire_area, (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7,
                        (0, 0, 255), 2)
            cv2.putText(original_frame, "FPS: %.2f" % fps, (10, 90), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
            cv2.putText(original_frame, "Fire Area Change Rate: %.2f" % fire_area_change_rate, (10, 120),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
            if len(past_frames) == 100:
                cv2.putText(original_frame, "Intersection Over Union: %.2f" % intersection_over_union, (10, 150),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)

            # 在画布上添加火灾形心坐标点
            if current_time - previous_time >= 1:  # 每隔1秒添加一个点
                previous_time = current_time
                if fire_count > 0:
                    # 计算火灾形心坐标
                    M = cv2.moments(binary)
                    center_x = int(M["m10"] / M["m00"])
                    center_y = int(M["m01"] / M["m00"])
                    cv2.circle(blank_canvas, (center_x, center_y), 3, (0, 255, 0), -1)

            cv2.imshow('Frame', original_frame)
            cv2.imshow('Binary Frame', binary)
            cv2.imshow('Blank Canvas', blank_canvas)

            # Update previous_frame_fire_area and previous_time for the next frame
            # Note: we do it here to include time taken by cv2.imshow in frame_time
            previous_frame_fire_area = fire_area

            # Press 'q' key to exit
            if cv2.waitKey(25) & 0xFF == ord('q'):
                break
        else:
            break

    cap.release()
    cv2.destroyAllWindows()


detect_fire_in_video('7191.mp4')

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值