需求分析:
使用python语言,基于OTSU算法写一段视频火灾检测的代码,要求如下:
1.对视频的每一帧先利用公式gray=1.6r-g-0.8b,得到相应的灰度图,再利用otsu算法进行二值化,对每一帧执行先腐蚀再膨胀去除噪声,最终得到二值化视频
2.对于二值化视频中的每一帧,合并距离较近的火灾区域,去除面积较小的火灾区域,同时在两个窗口分别展示未经过任何处理的原视频和最终的二值化视频
3.计算二值化视频中所检测到的火灾面积和火灾个数,并且把对应数值在两个视频上面进行实时展示
4.两个视频均实时显示FPs,即每秒可以处理视频的帧数,在两个视频中均实时显示每秒钟火灾面积的大小,即变化速度
代码块:
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() # 开始时间
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)
# 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)
original_frame = cv2.drawContours(original_frame, [cnt], -1, (0,255,0), 2)
# 计算处理这一帧图像所用的时间和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)
cv2.imshow('Frame', original_frame)
cv2.imshow('Binary Frame', binary)
# Update previous_frame_fire_area and previous_time for the next frame
previous_frame_fire_area = fire_area
previous_time = current_time
# 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')