監(jiān)控警戒區(qū)基于掩碼算法的簡單實現(xiàn)(附代碼)
效果視頻講解見連接:https://www.bilibili.com/video/BV1By4y1y7Vw/
這是利用圖片掩碼實現(xiàn)的一個視頻監(jiān)控區(qū)域警戒功能代碼,當(dāng)人進(jìn)出警戒區(qū)域時,自動記錄一張圖片到本地。

按代碼功能主要分為三個部分:
1、動態(tài)截屏
2、yolov5目標(biāo)檢測
3、掩碼生成及檢測目標(biāo)是否進(jìn)出該區(qū)域
完整代碼:
#動態(tài)截圖,識別目標(biāo),設(shè)置并記錄警戒區(qū)域的目標(biāo)
import numpy as np
from numpy import random
from PIL import ImageGrab
import CV2
import time
import win32api
import torch
import torch.backends.cudnn as cudnn
from models.experimental import attempt_load
from utils.general import (check_img_size, non_max_suppression, scale_coords, plot_one_box)
from utils.torch_utils import select_device, load_classifier
print('Setup complete. Using torch %s %s' % (torch.__version__, torch.cuda.get_device_properties(0) if torch.cuda.is_available() else 'CPU'))
# Initialize
device = select_device()
frame_h = 480
frame_w = 800
obj_count = 0 #警戒區(qū)目標(biāo)
obj_count_old = 0 #警戒區(qū)舊目標(biāo)
take_photo_num = 0;#拍照次數(shù)
#每個監(jiān)測不一定都檢測得到,所以做個緩沖區(qū)用于取平均值,因為要避免某幀的目標(biāo)丟失,會造成目標(biāo)數(shù)量的跳變,引發(fā)拍照記錄
obj_count_buf = np.array([0,0,0,0,0,0,0,0,0,0])#10個值
# Load model
model = attempt_load('weights/yolov5s.pt', map_location=device)? # load FP32 model cuda
# Get names and colors
names = model.module.names if hasattr(model, 'module') else model.names
colors = [[random.randint(0, 255) for _ in range(3)] for _ in range(len(names))]
#imgsz = check_img_size(486, s=model.stride.max())? # check img_size
frame_mask = np.zeros((frame_h,frame_w, 3),dtype = np.uint8)#做一個相同尺寸格式的圖片mask
postion = [(413,179),(275,391),(632,381),(571,204)]#警戒區(qū)位置點
CV2.fillPoly(frame_mask, [np.array(postion)], (0,0,255))#警戒區(qū)內(nèi)數(shù)字填充255,0,0成為mask
def process_img(original_image):#原圖處理函數(shù)
??? processed_img = CV2.cvtColor(original_image,CV2.COLOR_BGR2RGB)#BGR格式轉(zhuǎn)換RGB
??? processed_img = CV2.resize(processed_img,(frame_w,frame_h))#改變輸入尺寸
??? return processed_img
def MouseEvent(a,b,c,d,e):#鼠標(biāo)處理事件響應(yīng)函數(shù)
??? if(a==1): #獲取左鍵點擊坐標(biāo)點
??????? print(b,c)
?????? ?
CV2.namedWindow('frame')
CV2.setMouseCallback('frame', MouseEvent)? # 窗口與回調(diào)函數(shù)綁定
while(1):
??? # get a frame
??? frame = np.array(ImageGrab.grab(bbox=(0, 100, 800,600)))
??? if np.shape(frame): #frame有數(shù)據(jù)才能往下執(zhí)行
??????? #processing
??????? frame = process_img(frame)
??????? img = frame.copy() #img為gpu格式,常規(guī)方法不能讀取,im0為img的copy版可直接讀取
??????? #print("img:",np.shape(img))
??????? img = np.transpose(img,(2,0,1))#torch.Size([480, 800, 3])轉(zhuǎn)torch.Size([3, 480, 800])
??????? #print("img:",np.shape(img))
??????? img = torch.from_numpy(img).to(device)
??????? img = img.float()? # uint8 to fp32
??????? img /= 255.0? # 0 - 255 to 0.0 - 1.0
??????? #print(np.shape(img))#>>>torch.Size([3, 416, 352])
??????? if img.ndimension() == 3:
??????????? img = img.unsqueeze(0)#這個函數(shù)主要是對數(shù)據(jù)維度進(jìn)行擴充,在0的位置加了一維
??????? #print(np.shape(img))#>>>torch.Size([1, 3, 416, 352])
??????? pred = model(img)[0]
??????? # Apply NMS 非極大值抑制
??????? pred = non_max_suppression(pred, 0.5, 0.5)#大于0.4閾值的輸出,只顯示classes:>= 1,不能顯示0?
??????? #繪圖
??????? if pred != [None]:
??????????? for i,det in enumerate(pred):
??????????????? # Rescale boxes from img_size to im0 size
??????????????? det[:, :4] = scale_coords(img.shape[2:], det[:, :4], frame.shape).round()
??????????????? # Write results
??????????????? for *xyxy, conf, cls in reversed(det):
??????????????????? if cls == 0:#只顯示0(person)的標(biāo)簽,因為non_max_suppression(只顯示classes:>= 1)的標(biāo)簽
??????????????????????? label = '%s %.2f' % (names[int(cls)], conf)
??????????????????????? plot_one_box(xyxy, frame, label=label, color=colors[int(cls)], line_thickness=1)#utils.general專用畫框標(biāo)注函數(shù)
??????????????????????? xy = torch.tensor(xyxy).tolist()#張量轉(zhuǎn)換成列表形式
??????????????????????? x,y,x1,y1 = int(xy[0]),int(xy[1]),int(xy[2]),int(xy[3])#獲取左頂右底坐標(biāo)
??????????????????????? center_xy = (int(np.average([x,x1])),int(np.average([y,y1])))#計算中心點
??????????????????????? if (frame_mask[(center_xy[1],center_xy[0])] == [0,0,255]).all():#中心點在警戒區(qū)
??????????????????????????? obj_color = (255, 0, 0)#改變中心點顏色
??????????????????????????? obj_count += 1
??????????????????????? else:
??????????????????????????? obj_color = (255, 255, 0)#改變中心點顏色
??????????????????????? CV2.circle(frame, center_xy, 10, obj_color, 4)#開始畫點
??????? obj_count_buf = np.append(obj_count_buf[1:],obj_count)#保持更新10個緩沖區(qū)
??????? cbr = int(np.around(np.average(obj_count_buf)))
??????? CV2.putText(frame, 'obj_count :%s obj take_photo: %s'%(cbr,take_photo_num), (100, 20), CV2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 255), 2)#文字信息顯示
??????? frame = CV2.addWeighted(frame,1.0,frame_mask,0.1,0.0)#疊加掩碼圖片進(jìn)實時圖
??????? if (obj_count_old != cbr) :
??????????? take_photo_num += 1
??????????? CV2.imwrite("./photo/%s.jpg"%take_photo_num, frame, [int(CV2.IMWRITE_JPEG_QUALITY),50])#保存圖片
??????????? print('take photo number :%s'%take_photo_num)#顯示記錄的照片張數(shù)
??????????? CV2.putText(frame, 'take photo', (100, 300), CV2.FONT_HERSHEY_SIMPLEX, 3, (0, 0, 255), 3)#文字信息顯示
?????? ?
??????? obj_count_old =? cbr #保存上個數(shù)據(jù)
??????? obj_count = 0#目標(biāo)顯示清零,等待下次探測
?????? ?
??????? # show a frame
??????? #CV2.imshow("capture", frame[:,:,::-1])
??????? CV2.imshow("frame", frame)
??????? CV2.imshow("frame_mask", frame_mask[:,:,::-1])?????? ?
?????? ?
??? if CV2.waitKey(1) & 0xFF == ord('q'):
??????? break
?? ?
CV2.destroyAllWindows()