You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

167 lines
6.8 KiB

# 导入代码依赖
import time
import av
import os
import cv2
import torch
import numpy as np
import threading
import importlib.util
from core.DBManager import mDBM,DBManager
from myutils.MyLogger_logger import LogHandler
from myutils.ConfigManager import myCongif
class VideoCaptureWithFPS:
def __init__(self, src=0, target_fps=10):
self.cap = cv2.VideoCapture(src)
self.target_fps = target_fps
self.frame_interval = 1.0 / target_fps
self.last_frame_time = time.time()
def read(self):
current_time = time.time()
elapsed_time = current_time - self.last_frame_time
if elapsed_time < self.frame_interval: #小于间隔时间会休眠
time.sleep(self.frame_interval - elapsed_time)
self.last_frame_time = time.time()
ret, frame = self.cap.read()
return ret, frame
def release(self):
self.cap.release()
self.cap = None
class ModelManager:
def __init__(self):
self.verify_list = {}
self.bRun = True
self.logger = LogHandler().get_logger("ModelManager")
# 本地YOLOv5仓库路径
self.yolov5_path = myCongif.get_data("yolov5_path")
self.buflen = myCongif.get_data("buffer_len")
def _open_view(self,url,itype): #打开摄像头 0--USB摄像头,1-RTSP,2-海康SDK
if itype == 0:
cap = VideoCaptureWithFPS(int(url))
elif itype == 1:
cap = VideoCaptureWithFPS(url)
else:
raise Exception("视频参数错误!")
return cap
def _import_model(self,model_name,model_path):
'''根据路径,动态导入模块'''
if os.path.exists(model_path):
module_spec = importlib.util.spec_from_file_location(model_name, model_path)
module = importlib.util.module_from_spec(module_spec)
module_spec.loader.exec_module(module)
else:
self.logger.error("{}文件不存在".format(model_path))
return None
return module
def dowork_thread(self,channel_id):
'''一个通道一个线程,关联的模型在一个线程检测'''
cap = None
#查询关联的模型 --- 在循环运行前把基础数据都准备好
myDBM = DBManager()
myDBM.connection()
strsql = (f"select t1.model_id,t1.check_area,t1.polygon ,t2.duration_time,t2.proportion,t2.model_path "
f"from channel2model t1 left join model t2 on t1.model_id = t2.ID where t1.channel_id ={channel_id};")
myModels = myDBM.do_select(strsql)
#加载模型 --- 是不是要做个限制,一个视频通道关联算法模块的上限 --- 关联多了一个线程执行耗时较多,造成帧率太低,或者再多线程并发 #?
myModle_list = [] #存放模型对象List
myModle_data = [] #存放检测参数
for model in myModels:
#基于基类实例化模块类
m = self._import_model("",model[5]) #动态加载模型 -- 待完善
myModle_list.append(m)
myModle_data.append(model)
#开始循环检测
#print(mydata[0],mydata[1],mydata[2],mydata[3]) # url type tag img_buffer
#[url,type,True,img_buffer]
while self.verify_list[channel_id][2]: #基于tag 作为运行标识。 线程里只是读,住线程更新,最多晚一轮,应该不用线程锁。需验证
if not cap: #还没连接视频源
try:
cap = self._open_view(self.verify_list[channel_id][0],self.verify_list[channel_id][1])
except:
self.logger.error("参数错误,终止线程")
return
ret,frame = cap.read()
if not ret:
self.logger.warning("view disconnected. Reconnecting...")
cap.release()
cap = None
time.sleep(myCongif.get_data("cap_sleep_time"))
continue #没读到画面继续
#图像处理
img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# img = frame.to_ndarray(format="bgr24")
#检查布防时间是否在布防时间内
# 使用 模型 进行目标检测
i_warn_count = 0
for i in range(len(myModle_list)):#如果比较多可以考虑做线程进行检测
model = myModle_list[i]
data = myModle_data[i]
# 进行模型检测
detections,bwarn,warntext = model.verify(img,data)
#对识别结果要部要进行处理
if bwarn: # 整个识别有产生报警
# 绘制报警文本
cv2.putText(img, 'Intruder detected!', (50, (i_warn_count+1)*50),
cv2.FONT_HERSHEY_SIMPLEX, 1,(0, 0, 255), 2)
i_warn_count += 1
# 保存报警信息? --- 待完成
self.save_warn()
# 推送报警? --- 待完成
self.send_warn()
# 将检测结果图像转换为帧 -- 需要确认前面对img的处理都是累加的。
new_frame = av.VideoFrame.from_ndarray(img, format="rgb24")
# 分析图片放入内存中 ---
#new_frame = cv2.resize(new_frame, (640, 480)) # 降低视频分辨率
self.verify_list[channel_id][3].append(new_frame)
if len(self.verify_list[channel_id]) > self.buflen: # 保持缓冲区大小不超过10帧
self.verify_list[channel_id][3].pop(0)
self.logger.debug("drop one frame!")
def start_work(self,channel_id=0):
'''算法模型是在后台根据画面实时分析的'''
if channel_id ==0:
strsql = "select id,ulr,type from channel where is_work = 1;" #要考虑布防和撤防开关的的调整
else:
strsql = f"select id,ulr,type from channel where is_work = 1 and id = {channel_id};" #单通道启动检测线程
datas = mDBM.do_select(strsql)
for data in datas:
img_buffer = []
run_data = [data[1],data[2],True,img_buffer]
self.verify_list[data[0]] = run_data #需要验证重复情况
th_chn = threading.Thread(target=self.dowork_thread, args=(data[0],)) #一个视频通道一个线程,线程句柄暂时部保留
th_chn.start()
def stop_work(self,channel_id=0):
if channel_id ==0: #所有线程停止
for data in self.verify_list:
data[2] = False
del data[3]
time.sleep(2)
self.verify_list.clear()
else:
data = self.verify_list[channel_id]
data[2] = False
del data[3]
time.sleep(1)
del self.verify_list[channel_id]
if __name__ == "__main__":
ModelManager().start_work()