实现如下:
通过OpenCV基于火焰颜色特征,通过二帧三针差分减少误差,实现火焰定位识别,然后通过ffmpeg实现推流,流媒体服务器为基于nginx的rtmp流插件实现,请百度nginx-rtmp。
具体实现如下:
# ffmpeg推流命令
def put_to_rtmp(rtmpUrl, sizeStr, fps_num):
command = ['ffmpeg',
'-y',
'-f', 'rawvideo',
'-vcodec','rawvideo',
'-pix_fmt', 'bgr24',
'-s', sizeStr,
'-r', str(fps_num),
'-i', '-',
'-c:v', 'libx264',
'-pix_fmt', 'yuv420p',
'-preset', 'ultrafast',
'-f', 'flv',
rtmpUrl]
proc = sp.Popen(command, stdin=sp.PIPE, shell=True) #shell=
return proc#亮度对比
def contrast_brightness(image, c, b):#其中c为对比度,b为每个像素加上的值(调节亮度)
blank = np.zeros(image.shape, image.dtype)#创建一张与原图像大小及通道数都相同的黑色图像
dst = cv2.addWeighted(image, c, blank, 1-c, b) #c为加权值,b为每个像素所加的像素值
ret, dst = cv2.threshold(dst, 127, 255, cv2.THRESH_BINARY)
return dst
#制图可视化
def drawfire_bak(image,fireimage):
display_str = str('火焰预警')
image_np = Image.fromarray(image)
draw = ImageDraw.Draw(image_np)
contours, hierarchy = cv2.findContours(fireimage,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
v_box = []
for i in range(len(contours)):
cnt = contours[i]
area = cv2.contourArea(cnt)
if len(contours) < 4:
break
x,y,w,h = cv2.boundingRect(cnt)
if area>1:
v_box.append([x,y])
v_box.append([x+w, y+h])if (len(v_box)>0):
v_box = np.array(v_box)
minvx,minvy = np.amin(v_box,axis=0)
maxvx, maxvy = np.amax(v_box,axis=0)if (len(v_box)>0 ):
font = ImageFont.truetype('simhei.ttf', 20,encoding='utf-8')
display_str_height = font.getsize(display_str)[1]
display_str_heights = (1 + 2 * 0.05) * display_str_height
if minvy > display_str_heights:
text_bottom = minvy
else:
text_bottom = maxvy
text_width, text_height = font.getsize(display_str)
margin = np.ceil(0.05 * text_height)
draw.rectangle(
[(minvx, text_bottom - text_height - 2 * margin),
(minvx + text_width,text_bottom)],fill='blue')
draw.text(
(minvx + margin, text_bottom - text_height - margin),
display_str,fill='yellow',font=font)
image = np.array(image_np)
cv2.rectangle(image, (minvx,minvy), (maxvx, maxvy), (0, 255, 0), 1)
return image#实现火焰识别 rtmpUrl识别结果推流输出地址,url原始输入流地址
def fire_model(url, rtmpUrl):
cap = cv2.VideoCapture(url)
width =int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height =int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
redThre = 135
saturationTh = 55
ctrl = 3#fourcc = cv2.VideoWriter_fourcc(*'XVID')
size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))
sizeStr = str(size[0]) + 'x' + str(size[1])
fps = cap.get(cv2.CAP_PROP_FPS)
if fps == 0:
raise NameError
elif fps < 100:
fps_num = int(fps)
else:
fps_num = int(fps/10000)
proc = put_to_rtmp(rtmpUrl, sizeStr ,fps_num)## 二帧差分
if(ctrl==2):
frameNum = 0
while(True):
ret, frame = cap.read()
frameNum += 1
if ret == True:
tempframe = frame
if(frameNum==1):
previousframe = cv2.cvtColor(tempframe, cv2.COLOR_BGR2GRAY)
if(frameNum>=2):
currentframe = cv2.cvtColor(tempframe, cv2.COLOR_BGR2GRAY)
currentframe = cv2.absdiff(currentframe,previousframe)
#median = cv2.medianBlur(currentframe,3)
ret, threshold_frame = cv2.threshold(currentframe, 20, 255, cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(threshold_frame)
gauss_image = cv2.GaussianBlur(threshold_frame, (3, 3), 0)B = frame[:, :, 0]
G = frame[:, :, 1]
R = frame[:, :, 2]
minValue = https://www.it610.com/article/np.array(np.where(R <= G, np.where(G < B, R,
np.where(R < B, R, B)), np.where(G < B, G, B)))
S = 1 - 3.0 * minValue / (R + G + B + 1)
#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 = np.array(np.where(R > redThre,
np.where(R > G,
np.where(G > B,
np.where(S > (255 - R)*saturationTh/redThre, 255, 0), 0), 0), 0))gray_fireImg = np.zeros([fireImg.shape[0], fireImg.shape[1], 1], np.uint8)
gray_fireImg[:, :, 0] = fireImg
gray_fireImg = cv2.GaussianBlur(gray_fireImg, (3, 3), 0)kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
gauss_image = cv2.morphologyEx(gauss_image, cv2.MORPH_OPEN, kernel)
cv2.imshow("gauss_image",gauss_image)gray_fireImg = contrast_brightness(gray_fireImg, 5., 25)
cv2.imshow("gray_fireImg",gray_fireImg)
gray_fireImg = cv2.bitwise_and(gray_fireImg,gauss_image,mask=mask_inv)image = drawfire_bak(frame, gray_fireImg)
cv2.imshow("img", image)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
#rtmp流写入
try:
proc.stdin.write(image.tobytes())
except Exception as e:
proc.stdin.close()
proc = put_to_rtmp(rtmpUrl, sizeStr ,fps_num)
previousframe = cv2.cvtColor(tempframe, cv2.COLOR_BGR2GRAY)
else:
break
proc.stdin.close()
cap.release()
cv2.destroyAllWindows()
## 三帧差分法
else:
one_frame = np.zeros((height,width),dtype=np.uint8)
two_frame = np.zeros((height,width),dtype=np.uint8)
three_frame = np.zeros((height,width),dtype=np.uint8)
while(True):
ret, frame = cap.read()
if ret == True:
frame_gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
one_frame,two_frame,three_frame = two_frame,three_frame,frame_gray
abs1 = cv2.absdiff(one_frame,two_frame)#相减
_,thresh1 = cv2.threshold(abs1,20,255,cv2.THRESH_BINARY)#二值,大于20的为255,小于0
abs2 =cv2.absdiff(two_frame,three_frame)
_,thresh2 =cv2.threshold(abs2,20,255,cv2.THRESH_BINARY)binary =cv2.bitwise_and(thresh1,thresh2)B = frame[:, :, 0]
G = frame[:, :, 1]
R = frame[:, :, 2]
minValue = https://www.it610.com/article/np.array(np.where(R <= G, np.where(G < B, R,
np.where(R < B, R, B)), np.where(G < B, G, B)))
RGB_sum = R + G + B
RGB_sum[RGB_sum == 0] = 1
S = 1 - 3.0 * minValue / RGB_sum
#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))
estimate = (255 - R)*saturationTh/redThre
fireImg = np.array(np.where(R > redThre,
np.where(R > G,
np.where(G > B,
np.where(S > estimate, 255, 0), 0), 0), 0))gray_fireImg = np.zeros([fireImg.shape[0], fireImg.shape[1], 1], np.uint8)
gray_fireImg[:, :, 0] = fireImg
gray_fireImg = cv2.GaussianBlur(gray_fireImg, (3, 3), 0)#kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
#binary = cv2.morphologyEx(binary, cv2.MORPH_OPEN, kernel)gray_fireImg = contrast_brightness(gray_fireImg, 5., 25)
gray_fireImg = cv2.bitwise_and(gray_fireImg,binary)image = drawfire_bak(frame, gray_fireImg)
#cv2.imshow("img", image)
#if cv2.waitKey(1) & 0xFF == ord('q'):
#break
#rtmp流写入
try:
proc.stdin.write(image.tobytes())
except Exception as e:
proc.stdin.close()
proc = put_to_rtmp(rtmpUrl, sizeStr ,fps_num)
else:
break
proc.stdin.close()
cap.release()
cv2.destroyAllWindows()
参考文章:识别检测类系统(基于pytorch)(一)_明哲慕鸿的博客-CSDN博客_基于pytorch的物体识别
【图像识别|火焰识别系统(python实现基于颜色多帧差分)】识别检测类系统(基于pytorch)(一) - 灰信网(软件开发博客聚合)
推荐阅读
- java|Spring框架漏洞总结
- 机器学习|支持向量机
- 人工智能|入门机器学习(西瓜书+南瓜书)支持向量机总结(python代码实现)
- 机器学习|Task02 详读西瓜书+南瓜书第3章
- 机器学习|datawhale学习之一西瓜书和南瓜书概论
- Opencv -- 18图像像素类型转换与归一化
- opencv|Learing OpenCV---鼠标响应
- python|18 个 Python 编程坏习惯,一定要抛弃哦
- python|使用Python进行压缩与解压缩