这里是通过寻找每一帧与前面5帧的交集(每一帧的交集取并集),与当前帧火灾面积的比值,也就是OV,用于排除误检,如果OV指数过大则认为最近5帧相似度很高(火灾),如果OV指数处于一定的范围/检测火灾确定范围/,则认为这是火灾,如果OV指数很小,则说明这是移动的物体,排除误检
import cv2
import numpy as np
import matplotlib.pyplot as plt
# 定义火灾检测函数
def fire_detection(frame, prev_frames_fire_area, gray_threshold=127, erosion_iterations=2, dilation_iterations=2):
# 将彩色图像转换为灰度图像
gray = 1.6 * frame[:, :, 2] - frame[:, :, 1] - 0.8 * frame[:, :, 0]
gray = np.uint8(np.clip(gray, 0, 255))
# 使用OTSU算法进行二值化
_, 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=erosion_iterations)
binary = cv2.dilate(binary, kernel, iterations=dilation_iterations)
# 计算当前帧的火灾区域
fire_area = cv2.countNonZero(binary)
# 这段代码的主要目的是维护一个长度为10的队列(prev_frames_fire_area),
# 用于存储最近10帧的火灾区域信息。在每一帧处理完后,当前帧的二值化结果(binary)会被添加到队列末尾,然后检查队列长度是否超过10帧。
# 如果超过,就将队列头部的元素弹出,保持队列长度不超过10。
#
# 这样的设计是为了在后续的代码中使用这个队列来计算当前帧与前面10帧的火灾区域的交集,以便计算重叠比例。
# 这种滑动窗口的方式确保了只保留最近的10帧信息,以便在整个视频处理过程中保持一定的历史信息。
# 计算火灾区域与5帧之前的帧的交集
if len(prev_frames_fire_area) >= 10:
intersection = binary
for prev_frame_fire_area in prev_frames_fire_area[-10:]:
intersection = cv2.bitwise_and(intersection, prev_frame_fire_area)
else:
intersection = np.zeros_like(binary)
# 重叠比例(OverlapRatio)是通过计算当前帧的火灾区域与过去一定数量(这里是10帧)的火灾区域的交集与当前帧火灾区域的比例来定义的。
# 具体计算步骤如下:
# 计算当前帧的火灾区域大小(fire_area):使用cv2.countNonZero(binary)
# 函数来计算当前帧二值图像中非零像素的数量,即火灾区域的像素数。
# 计算当前帧与过去10帧的火灾区域的交集(intersection):如果历史帧的数量大于等于10,遍历过去10帧的二值图像,使用
# cv2.bitwise_and函数计算它们与当前帧的交集。
# 计算重叠比例(overlap_ratio):通过将交集的非零像素数量除以当前帧火灾区域的大小,得到重叠比例。
# 在这段代码中,计算重叠比例的过程涉及到过去10帧中的每一帧。
# 具体来说,对于每一帧,都计算当前帧火灾区域与该帧的交集,然后将这些交集再进行合并,最终计算重叠比例。
# 计算OV(重叠比例)
if fire_area > 0:
overlap_ratio = cv2.countNonZero(intersection) / fire_area
else:
overlap_ratio = 0.0
# 更新前面5帧的火灾区域
prev_frames_fire_area.append(binary)
if len(prev_frames_fire_area) > 10:
prev_frames_fire_area.pop(0)
return binary, overlap_ratio
# 打开视频文件
video_capture = cv2.VideoCapture('1-远距离森林火灾5.avi')
# 获取视频的帧率和大小
frame_rate = int(video_capture.get(5))
frame_width = int(video_capture.get(3))
frame_height = int(video_capture.get(4))
# 创建一个窗口来显示视频
cv2.namedWindow('Fire Detection', cv2.WINDOW_NORMAL)
cv2.resizeWindow('Fire Detection', frame_width * 2, frame_height)
# 读取第一帧
ret, prev_frame = video_capture.read()
prev_frames_fire_area = []
# 创建一个用于保存OV值的列表
ov_values = []
while ret:
# 运行火灾检测函数
binary, overlap_ratio = fire_detection(prev_frame, prev_frames_fire_area)
# 在同一个窗口中展示原视频和二值化视频
output_frame = np.hstack((prev_frame, cv2.cvtColor(binary, cv2.COLOR_GRAY2BGR)))
cv2.imshow('Fire Detection', output_frame)
# 保存OV值
ov_values.append(overlap_ratio)
# 读取下一帧
ret, prev_frame = video_capture.read()
# 通过按'q'键来退出循环
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放视频捕捉对象和关闭窗口
video_capture.release()
cv2.destroyAllWindows()
# 绘制OV变化曲线
plt.plot(ov_values)
plt.xlabel('Frame Number')
plt.ylabel('Overlap Ratio (OV)')
plt.title('Fire Detection OV Curve')
plt.show()