实现如下:
通过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 = 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 = 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的物体识别
识别检测类系统(基于pytorch)(一) - 灰信网(软件开发博客聚合)