Fire detection and cutting
1 modules
import cv2
import numpy as np
2 Conditions
- R>redThre: In a fire image, R is always higher than average value
- R>=G>=B
- S>=0.2
- S >= (255 - R)*saturationTh/redThre
where:
Then, the point which satisfy above conditions will be white and other points will be black.
In addition, in some bright point( such as the center in the following picture), R may be smaller than G. I add another condition: R>250 and G>250 will be recognized as fire.
cap = cv2.VideoCapture("3.flv")
redThre = 105
saturationTh = 42
const = 240
while cap.isOpened():
_, img = cap.read()
img = cv2.pyrDown(img)
B = img[:, :, 0]
G = img[:, :, 1]
R = img[:, :, 2]
#找到B、G、R中的最小值
minValue = np.array(np.where(R <= G, np.where(G <= B, R, np.where(R <= B, R, B)), np.where(G <= B, G, B)))
total = R+B+G
total_1 = total[:, :]+1# to avoid R+B+G=0
#计算S分量
m_divide_t = np.divide(minValue, total_1)
S = 1 - 3*m_divide_t
#需满足条件:1 R>redThre 2 R>=G>=B; 3 S>=0.2; 4 S >= (255 - R)*saturationTh/redThre
#并且,当R和G都大于250时,也识别为火焰,为了避免火焰完全呈白色的情况
fireImg = np.array(np.where(R > redThre, np.where(R >= G, np.where(G >= B, np.where(S >= 0.2, np.where(S >= (255 - R)*saturationTh/redThre, 255, 0), 0), 0), 0), 0))
fireImg_bu = np.array(np.where(R > 250, np.where(G > 250, 255, 0), 0))
3 merge the images
Merge the fireImg and fireImg _bu. And use GaussianBlur and threshold to optimize the image.
gray_fireImg1 and gray_fireImg2 are used to contrast influence of morphologyEx.
#将找到的火焰点都结合起来,并用高斯模糊和阈值处理图像
gray_fireImg = np.zeros([fireImg.shape[0], fireImg.shape[1], 1], np.uint8)
gray_fireImg[:, :, 0] = fireImg + fireImg_bu
gray_fireImg = cv2.GaussianBlur(gray_fireImg, (7, 7), 0)
_, gray_fireImg1 = cv2.threshold(gray_fireImg, 10, 255, cv2.THRESH_BINARY)
gray_fireImg2 = cv2.morphologyEx(gray_fireImg2, cv2.MORPH_CLOSE, kernel)
4 show the image
Show the image, and read the next image when handling a video.
cv2.imshow("0", img)
cv2.imshow("1", gray_fireImg1)
cv2.imshow("2", gray_fireImg2)
_, img = cap.read()
if cv2.waitKey(20) == 27:
break
cv2.destroyAllWindows()
5 result
Left one is gray_fireImg1.
Middle one is gray_fireImg2.
Right one is source video.
It seems that there is little difference between gray_fireImg1 and gray_fireImg2.
6 the whole code
import cv2
import numpy as np
cap = cv2.VideoCapture("3.flv")
redThre = 105
saturationTh = 42
const = 240
while cap.isOpened():
_, img = cap.read()
img = cv2.pyrDown(img)
B = img[:, :, 0]
G = img[:, :, 1]
R = img[:, :, 2]
#找到B、G、R中的最小值
minValue = np.array(np.where(R <= G, np.where(G <= B, R, np.where(R <= B, R, B)), np.where(G <= B, G, B)))
total = R+B+G
total_1 = total[:, :]+1
m_divide_t = np.divide(minValue, total_1)
#计算S分量
S = 1 - 3*m_divide_t
#需满足条件:0 R>redThre 1 R>=G>=B; 2 S>=0.2; 3 S >= (255 - R)*saturationTh/redThre
#并且,当R和G都大于250时,也识别为火焰,为了避免火焰完全呈白色的情况
fireImg = np.array(np.where(R > redThre, np.where(R >= G, np.where(G >= B, np.where(S >= 0.2, np.where(S >= (255 - R)*saturationTh/redThre, 255, 0), 0), 0), 0), 0))
fireImg_bu = np.array(np.where(R > 250, np.where(G > 250, 255, 0), 0))
gray_fireImg = np.zeros([fireImg.shape[0], fireImg.shape[1], 1], np.uint8)
gray_fireImg[:, :, 0] = fireImg + fireImg_bu
gray_fireImg = cv2.GaussianBlur(gray_fireImg, (7, 7), 0)
_, gray_fireImg1 = cv2.threshold(gray_fireImg, 10, 255, cv2.THRESH_BINARY)
gray_fireImg2 = cv2.morphologyEx(gray_fireImg2, cv2.MORPH_CLOSE, kernel)
cv2.imshow("0", img)
cv2.imshow("1", gray_fireImg1)
cv2.imshow("2", gray_fireImg2)
_, img = cap.read()
if cv2.waitKey(20) == 27:
break
cv2.destroyAllWindows()