火焰识别系统(python实现基于颜色多帧差分)

实现如下:

通过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)(一) - 灰信网(软件开发博客聚合)

你可能感兴趣的:(图像识别,python,计算机视觉,图像识别,opencv)