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.
151 lines
6.3 KiB
151 lines
6.3 KiB
import cv2
|
|
import threading
|
|
import base64
|
|
from myutils.ConfigManager import myCongif
|
|
#独立模型线程
|
|
from core.ModelNode import ModelNode
|
|
from core.ChannelData import ChannelData #其实ChannelNode会更加贴切一些
|
|
|
|
'''
|
|
通道对象管理类,只针对通道节点的维护,和工作线程的开启和停止, ChannelData的操作必须维护在ChannelManager里面!不能输出ChannelData对象!
|
|
'''
|
|
class ChannelManager:
|
|
def __init__(self):
|
|
self._channels = {}
|
|
self.cm_lock = threading.RLock() # 用于保证字典操作的线程安全
|
|
|
|
# 独立Model_th相关参数 --- modelNode 用一个类封装下model线程和其相关参数
|
|
self.model_list = {} # model_id -- modelNode
|
|
self.workType = int(myCongif.get_data("workType"))
|
|
self.device_id = myCongif.get_data("device_id")
|
|
|
|
#增加节点
|
|
def add_channel(self, channel_id,deque_length,icount_max,warnM):
|
|
ret = False
|
|
with self.cm_lock:
|
|
if channel_id in self._channels: #若已经有数据,先删除后再增加
|
|
self._channels[channel_id].stop_work(0) # 停止工作
|
|
del self._channels[channel_id]
|
|
if self.workType == 2: # 若有model线程停止了,则删除该model节点
|
|
self.delModelNode()
|
|
#channel_id,deque_length,icount_max,warnM
|
|
ch_data = ChannelData(channel_id, deque_length, icount_max,warnM)
|
|
self._channels[channel_id] = ch_data
|
|
ret = True
|
|
return ret
|
|
|
|
#删除节点
|
|
def delete_channel(self, channel_id): #需要验证资源的释放清空
|
|
'''删除节点,包含了停止该节点工作线程'''
|
|
ret = True
|
|
with self.cm_lock:
|
|
if channel_id == 0:
|
|
for clannel_data in self._channels:
|
|
clannel_data.stop_work(0)
|
|
self._channels.clear() #清空节点
|
|
else:
|
|
if channel_id in self._channels:
|
|
self._channels[channel_id].stop_work(0) #停止工作
|
|
del self._channels[channel_id]
|
|
if self.workType == 2: #若有model线程停止了,则删除该model节点
|
|
self.delModelNode()
|
|
return ret
|
|
|
|
#开始工作线程
|
|
def start_channel(self,channel_id,cap_data,model_data,schedule,type):
|
|
'''
|
|
启动通道的工作线程 -- 启动应该没有一下子启动所有
|
|
:param channel_id: 启动通道的ID channel_id == 0的情况已经在上一层处理了,这里不会有0
|
|
:param cap_data: [source,type]
|
|
:param model_data: 跟该通道关联的模型数据
|
|
:param schedule
|
|
:param type: 0-启动所有工作线程,1-启动CAP采集线程,2-启动model工资线程
|
|
:return:
|
|
'''
|
|
ret = False
|
|
with self.cm_lock:
|
|
if channel_id in self._channels:
|
|
c_node = self._channels[channel_id]
|
|
model_node = None
|
|
if self.workType == 2 and type !=1: #需要确保当type!=1时,model_data必须有数据 -- 调用时已经有判断
|
|
model_node = self.CreateModelNode(model_data[0], model_data[5], channel_id)
|
|
ret = c_node.start_work(cap_data,model_data,schedule,type,model_node)
|
|
return ret
|
|
|
|
|
|
#停止工作线程---要把视频采集线程停止掉
|
|
def stop_channel(self,channel_id,type): #9-10截止目前就重启模型线程时用到该函数(channel_id,2)
|
|
'''
|
|
停止通道的工作线程
|
|
:param channel_id: 0-停止所有通道的工作线程,其他值为具体停止哪个工作线程
|
|
:param type: 0-停止所有工作线程,1-停止CAP采集线程,2-停止model工资线程
|
|
:return:
|
|
'''
|
|
with self.cm_lock:
|
|
ret = False
|
|
if channel_id == 0:
|
|
# for clannel_id,clannel_data in self.channels.items():
|
|
for clannel_data in self._channels:
|
|
clannel_data.stop_work(type)
|
|
ret = True
|
|
else:
|
|
if channel_id in self._channels:
|
|
self._channels[channel_id].stop_work(type)
|
|
ret =True
|
|
|
|
if self.workType == 2: #若有model线程停止了,则删除该model节点
|
|
self.delModelNode()
|
|
return ret
|
|
|
|
def get_channel_data(self,channel_id):
|
|
cdata = None
|
|
if channel_id in self._channels:
|
|
cdata = self._channels[channel_id]
|
|
return cdata
|
|
|
|
def cm_get_last_frame(self,channel_id): #这里如果加锁的话,阻塞会比较厉害,但具体程度也需要验证。
|
|
frame = None
|
|
if channel_id in self._channels:
|
|
try:
|
|
frame = self._channels[channel_id].get_last_frame()
|
|
except Exception as e:
|
|
print(e)
|
|
return frame
|
|
|
|
def cm_get_cap_frame(self,channel_id):
|
|
img_base64 = None
|
|
if channel_id in self._channels:
|
|
channel_data = self._channels[channel_id]
|
|
if channel_data.cap:
|
|
try:
|
|
for i in range(5):
|
|
ret, frame = channel_data.cap.read()
|
|
if ret:
|
|
ret, frame_bgr_webp = cv2.imencode('.jpg', frame)
|
|
if ret:
|
|
# 将图像数据编码为Base64
|
|
img_base64 = base64.b64encode(frame_bgr_webp).decode('utf-8')
|
|
break
|
|
except Exception as e:
|
|
print(e)
|
|
return img_base64
|
|
|
|
'''模型独立线程修改2024-9-9,要求是双模式兼容'''
|
|
def CreateModelNode(self, model_id, model_path, channel_id):
|
|
if model_id in self.model_list:
|
|
modelN = self.model_list[model_id]
|
|
else:
|
|
modelN = ModelNode(self.device_id,model_path)
|
|
self.model_list[model_id] = modelN
|
|
return modelN
|
|
|
|
def delModelNode(self): #关于modelnodel :1.考虑modelnode是否可以不删除,清空inmq即可,2.mdel_list是否需要加锁。#?
|
|
return
|
|
for model_id, modelNode in self.model_list.items():
|
|
if modelNode.ch_count == 0:
|
|
del self.model_list[model_id]
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# 示例使用
|
|
pass
|
|
|