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.
505 lines
24 KiB
505 lines
24 KiB
# 导入代码依赖
|
|
import time
|
|
import av
|
|
import os
|
|
import cv2
|
|
import numpy as np
|
|
import threading
|
|
import importlib.util
|
|
import datetime
|
|
import math
|
|
import queue
|
|
from collections import deque
|
|
from core.DBManager import mDBM,DBManager
|
|
from myutils.MyLogger_logger import LogHandler
|
|
from myutils.ConfigManager import myCongif
|
|
from model.plugins.ModelBase import ModelBase
|
|
from core.ChannelManager import ChannelManager
|
|
from core.ACLModelManager import ACLModeManger
|
|
from PIL import Image
|
|
|
|
|
|
class VideoCaptureWithFPS:
|
|
'''视频捕获的封装类,是一个通道一个'''
|
|
def __init__(self, source):
|
|
self.source = source
|
|
self.width = None
|
|
self.height = None
|
|
self.cap = cv2.VideoCapture(self.source)
|
|
if self.cap.isOpened(): #若没有打开成功,在读取画面的时候,已有判断和处理 -- 这里也要检查下内存的释放情况
|
|
self.width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
|
self.height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
|
print(self.width,self.height)
|
|
#self.fps = fps # 线程保持最大帧率的刷新画面---过高的帧率会影响CPU性能,但过地的帧率会造成帧积压
|
|
self.fps = math.ceil(self.cap.get(cv2.CAP_PROP_FPS)/float(myCongif.get_data("verify_rate"))) #向上取整。
|
|
#print(self.fps)
|
|
self.running = True
|
|
#self.frame_queue = queue.Queue(maxsize=1)
|
|
self.frame = None
|
|
self.read_lock = threading.Lock()
|
|
self.thread = threading.Thread(target=self.update)
|
|
self.thread.start()
|
|
|
|
def update(self):
|
|
icount = 0
|
|
while self.running:
|
|
ret, frame = self.cap.read()
|
|
if not ret:
|
|
icount += 1
|
|
if icount > 5: #重连
|
|
self.cap.release()
|
|
self.cap = cv2.VideoCapture(self.source)
|
|
if self.cap.isOpened():
|
|
self.width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
|
|
self.height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
|
|
# self.fps = fps # 线程保持最大帧率的刷新画面---过高的帧率会影响CPU性能,但过地的帧率会造成帧积压
|
|
self.fps = math.ceil(
|
|
self.cap.get(cv2.CAP_PROP_FPS) / float(myCongif.get_data("verify_rate"))) # 向上取整。
|
|
icount = 0
|
|
else:
|
|
time.sleep(1)
|
|
continue
|
|
#resized_frame = cv2.resize(frame, (int(self.width / 2), int(self.height / 2)))
|
|
with self.read_lock:
|
|
self.frame = frame
|
|
# if not self.frame_queue.full():
|
|
# self.frame_queue.put(resized_frame)
|
|
|
|
# 跳过指定数量的帧以避免积压
|
|
for _ in range(self.fps):
|
|
self.cap.grab()
|
|
# time.sleep(self.fps) #按照视频源的帧率进行休眠
|
|
#print("Frame updated at:",time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
|
|
|
|
def read(self):
|
|
with self.read_lock:
|
|
frame = self.frame.copy() if self.frame is not None else None
|
|
if frame is not None:
|
|
return True, frame
|
|
else:
|
|
return False, None
|
|
# if not self.frame_queue.empty():
|
|
# return True, self.frame_queue.get()
|
|
# else:
|
|
# return False, None
|
|
|
|
def release(self):
|
|
self.running = False
|
|
self.thread.join()
|
|
self.cap.release()
|
|
|
|
|
|
class ModelManager:
|
|
def __init__(self):
|
|
self.verify_list = ChannelManager() #模型的主要数据 -- 2024-7-5修改为类管理通道数据
|
|
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")
|
|
self.icout_max = myCongif.get_data("RESET_INTERVAL") #跟视频帧序用一个变量
|
|
self.frame_rate = myCongif.get_data("frame_rate")
|
|
self.frame_interval = 1.0 / int(myCongif.get_data("verify_rate"))
|
|
#保存视频相关内容
|
|
self.FPS = myCongif.get_data("verify_rate") # 视频帧率--是否能实现动态帧率
|
|
self.fourcc = cv2.VideoWriter_fourcc(*'mp4v') # 使用 mp4 编码
|
|
#基于模型运行环境进行相应初始化工作
|
|
self.model_platform = myCongif.get_data("model_platform")
|
|
self.device_id = myCongif.get_data("device_id")
|
|
# acl初始化 -- 一个线程一个 -- 需要验证
|
|
if self.model_platform == "acl":
|
|
ACLModeManger.init_acl(self.device_id) #acl -- 全程序初始化
|
|
|
|
def __del__(self):
|
|
self.logger.debug("释放资源")
|
|
del self.verify_list #应该需要深入的删除--待完善
|
|
if self.model_platform == "acl":
|
|
ACLModeManger.del_acl(self.device_id) #acl -- 全程序反初始化 需要确保在执行析构前,其它资源已释放
|
|
|
|
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,threshold):
|
|
'''
|
|
根据路径,动态导入模块
|
|
:param model_name: 模块名称
|
|
:param model_path: 模块路径
|
|
:param threshold: 置信阈值
|
|
:return:
|
|
'''
|
|
if os.path.exists(model_path):
|
|
module_spec = importlib.util.spec_from_file_location(model_name, model_path)
|
|
if module_spec is None:
|
|
self.logger.error(f"{model_path} 加载错误")
|
|
return None
|
|
module = importlib.util.module_from_spec(module_spec)
|
|
module_spec.loader.exec_module(module)
|
|
md = getattr(module, "Model")(model_path,threshold) #实例化类
|
|
if not isinstance(md, ModelBase):
|
|
self.logger.error("{} not zf_model".format(md))
|
|
return None
|
|
if md.init_ok == False:
|
|
self.logger.error("离线模型加载初始化失败!")
|
|
return None
|
|
|
|
else:
|
|
self.logger.error("{}文件不存在".format(model_path))
|
|
return None
|
|
return md
|
|
|
|
def getschedule(self,c2m_id,myDBM):
|
|
'''
|
|
根据c2mID 查询该算法的布防时间
|
|
:param c2m_id:
|
|
:return: 以day为行,hour作为列的,布防标识值二维list
|
|
'''
|
|
strsql = f"select day,hour,status from schedule where channel2model_id ={c2m_id} order by hour asc,day asc;"
|
|
datas = myDBM.do_select(strsql)
|
|
onelist = []
|
|
twolist = []
|
|
threelist = []
|
|
fourlist = []
|
|
fivelist = []
|
|
sixlist = []
|
|
sevenlist = []
|
|
if datas:
|
|
for i in range(24):
|
|
onelist.append(datas[i*7 + 0][2])
|
|
twolist.append(datas[i*7 + 1][2])
|
|
threelist.append(datas[i*7 + 2][2])
|
|
fourlist.append(datas[i*7 + 3][2])
|
|
fivelist.append(datas[i*7 + 4][2])
|
|
sixlist.append(datas[i*7 + 5][2])
|
|
sevenlist.append(datas[i*7 + 6][2])
|
|
else:
|
|
self.logger.debug(f"没有数据--{c2m_id}")
|
|
onelist = [1]*24
|
|
twolist = [1]*24
|
|
threelist = [1]*24
|
|
fourlist = [1]*24
|
|
fivelist = [1]*24
|
|
sixlist = [1]*24
|
|
sevenlist = [1]*24
|
|
schedule_list = []
|
|
schedule_list.append(onelist)
|
|
schedule_list.append(twolist)
|
|
schedule_list.append(threelist)
|
|
schedule_list.append(fourlist)
|
|
schedule_list.append(fivelist)
|
|
schedule_list.append(sixlist)
|
|
schedule_list.append(sevenlist)
|
|
return schedule_list
|
|
|
|
def set_last_img(self,):
|
|
pass
|
|
|
|
def verify(self,frame,myModle_list,myModle_data,channel_id,schedule_list,result_list,isdraw=1):
|
|
'''验证执行主函数,实现遍历通道关联的模型,调用对应模型执行验证,模型文件遍历执行'''
|
|
img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
|
#img = np.ascontiguousarray(img, dtype=np.float32) / 255.0 # 转换为内存连续存储的数组 --该函数可以待定下是不是所有模型都可以做
|
|
# img = frame.to_ndarray(format="bgr24")
|
|
#img = frame
|
|
# 使用 模型 进行目标检测
|
|
i_warn_count = 0 #报警标签
|
|
#isverify = False
|
|
for i in range(len(myModle_list)): # 遍历通道关联的算法进行检测,若不控制模型数量,有可能需要考虑多线程执行。
|
|
model = myModle_list[i]
|
|
data = myModle_data[i]
|
|
schedule = schedule_list[i]
|
|
result = result_list[i]
|
|
#验证检测计划,是否在布防时间内
|
|
now = datetime.datetime.now() # 获取当前日期和时间
|
|
weekday = now.weekday() # 获取星期几,星期一是0,星期天是6
|
|
hour = now.hour
|
|
result.pop(0) # 保障结果数组定长 --先把最早的结果推出数组
|
|
if schedule[weekday][hour] == 1: #不在计划则不进行验证,直接返回图片
|
|
# 调用模型,进行检测,model是动态加载的,具体的判断标准由模型内执行 ---- *********
|
|
#isverify = True
|
|
detections, bwarn, warntext = model.verify(img, data,isdraw) #****************重要
|
|
# 对识别结果要部要进行处理
|
|
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
|
|
result.append(1) #要验证数组修改,是地址修改吗?
|
|
else: #没有产生报警也需要记录,统一计算占比
|
|
result.append(0)
|
|
else:
|
|
result.append(0)
|
|
# if not isverify: #没做处理,直接返回的,需要控制下帧率,太快读取没有意义。 --2024-7-5 取消休眠,帧率控制在dowork_thread完成
|
|
# time.sleep(1.0/self.frame_rate) #给个默认帧率,不超过30帧,---若经过模型计算,CPU下单模型也就12帧这样
|
|
|
|
# 将检测结果图像转换为帧--暂时用不到AVFrame--2024-7-5
|
|
# new_frame_rgb_avframe = av.VideoFrame.from_ndarray(img, format="rgb24") # AVFrame
|
|
# new_frame_rgb_avframe.pts = None # 添加此行确保有pts属性
|
|
|
|
# if isinstance(img, np.ndarray): -- 留个纪念
|
|
#处理完的图片后返回-bgr模式
|
|
img_bgr_ndarray = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
|
|
# 将检查结果转换为WebP格式图片 --在线程里面完成应该可以减少网页端处理时间
|
|
ret,frame_bgr_webp=cv2.imencode('.jpg', img_bgr_ndarray)
|
|
if not ret:
|
|
buffer_bgr_webp = None
|
|
else:
|
|
buffer_bgr_webp = frame_bgr_webp.tobytes()
|
|
return buffer_bgr_webp,img_bgr_ndarray
|
|
|
|
|
|
def dowork_thread(self,channel_id):
|
|
'''一个通道一个线程,关联的模型在一个线程检测,局部变量都是一个通道独有'''
|
|
channel_data = self.verify_list.get_channel(channel_id) #是对ChannelData 对象的引用
|
|
context = None
|
|
# 线程ACL初始化
|
|
if self.model_platform == "acl": # ACL线程中初始化内容
|
|
context = ACLModeManger.th_inti_acl(self.device_id)
|
|
#查询关联的模型 --- 在循环运行前把基础数据都准备好
|
|
myDBM = DBManager()
|
|
myDBM.connect()
|
|
strsql = (f"select t1.model_id,t1.check_area,t1.polygon ,t2.duration_time,t2.proportion,t2.model_path,t1.ID,"
|
|
f"t2.model_name,t1.conf_threshold "
|
|
f"from channel2model t1 left join model t2 on t1.model_id = t2.ID where t1.channel_id ={channel_id};")
|
|
#print(strsql)
|
|
myModels = myDBM.do_select(strsql)
|
|
#加载模型 --- 是不是要做个限制,一个视频通道关联算法模块的上限 --- 关联多了一个线程执行耗时较多,造成帧率太低,或者再多线程并发 #?
|
|
|
|
myModle_list = [] #存放模型对象List 一个模型一个
|
|
myModle_data = [] #存放检测参数 一个模型一个
|
|
schedule_list = [] #布防策略 -一个模型一个
|
|
result_list = [] #检测结果记录 -一个模型一个
|
|
warn_last_time =[] #最新的报警时间记录 -一个模型一个
|
|
proportion_list = []#占比设定 -一个模型一个
|
|
warn_save_count = []#没个模型触发报警后,保存录像的最新帧序号 -一个模型一个
|
|
|
|
#获取视频通道的模型相关数据-list
|
|
for model in myModels:
|
|
#基于基类实例化模块类
|
|
m = self._import_model("",model[5],model[8]) #动态加载模型处理文件py --需要验证模型文件是否能加载
|
|
#m = None
|
|
if m:
|
|
myModle_list.append(m) #没有成功加载的模型原画输出
|
|
myModle_data.append(model)
|
|
#model[6] -- c2m_id --布防计划 0-周一,6-周日
|
|
schedule_list.append(self.getschedule(model[6],myDBM))
|
|
result = [0 for _ in range(model[3] * myCongif.get_data("verify_rate"))] #初始化时间*验证帧率数量的结果list
|
|
result_list.append(result)
|
|
warn_last_time.append(time.time())
|
|
proportion_list.append(model[4]) #判断是否报警的占比
|
|
warn_save_count.append(0) #保存录像的最新帧初始化为0
|
|
|
|
#开始拉取画面循环检测
|
|
cap = None
|
|
#iread_count =0 #失败读取的次数
|
|
last_frame_time = time.time() #初始化个读帧时间
|
|
cap_sleep_time = myCongif.get_data("cap_sleep_time")
|
|
#可以释放数据库资源
|
|
del myDBM
|
|
warn_interval = myCongif.get_data("warn_interval")
|
|
while channel_data.bool_run: #基于tag 作为运行标识。 线程里只是读,住线程更新,最多晚一轮,应该不用线程锁。需验证
|
|
# 帧率控制帧率
|
|
current_time = time.time()
|
|
elapsed_time = current_time - last_frame_time
|
|
if elapsed_time < self.frame_interval:
|
|
time.sleep(self.frame_interval - elapsed_time) #若小于间隔时间则休眠
|
|
last_frame_time = time.time()
|
|
#*********取画面*************
|
|
if not cap: #第一次需要打开视频流
|
|
try:
|
|
cap = self._open_view(channel_data.str_url,channel_data.int_type) #创建子线程读画面
|
|
except:
|
|
self.logger.error("打开视频参数错误,终止线程!")
|
|
return
|
|
ret,frame = cap.read() #除了第一帧,其它应该都是有画面的
|
|
if not ret:
|
|
# if iread_count > 30: #2024-7-8 重连接机制放VideoCaptureWithFPS
|
|
# self.logger.warning(f"通道-{channel_id}:view disconnected. Reconnecting...")
|
|
# cap.release()
|
|
# cap = None
|
|
# time.sleep(cap_sleep_time)
|
|
# else:
|
|
# iread_count += 1
|
|
continue #没读到画面继续
|
|
#执行图片推理 -- 如何没有模型或不在工作时间,返回的是原画,要不要控制下帧率? -- 在verify中做了sleep
|
|
buffer_bgr_webp,img_bgr_ndarray = self.verify(frame,myModle_list,myModle_data,channel_id,schedule_list,result_list)
|
|
|
|
#分析图片放入内存中
|
|
channel_data.add_deque(img_bgr_ndarray) # 缓冲区大小由maxlen控制 超上限后,删除最前的数据
|
|
channel_data.increment_counter() #帧序列加一
|
|
# 一直更新最新帧,提供网页端显示
|
|
channel_data.update_last_frame(buffer_bgr_webp)
|
|
#print(f"{channel_id}--Frame updated at:",time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
|
|
#验证result_list -是否触发报警要求 --遍历每个模型执行的result
|
|
for i in range(len(result_list)):
|
|
result = result_list[i]
|
|
proportion = proportion_list[i]
|
|
count_one = float(sum(result)) #1,0 把1累加的和就是1的数量
|
|
ratio_of_ones = count_one / len(result)
|
|
#self.logger.debug(result)
|
|
if ratio_of_ones >= proportion: #触发报警
|
|
# 基于时间间隔判断
|
|
current_time = time.time()
|
|
elapsed_time = current_time - warn_last_time[i]
|
|
if elapsed_time < warn_interval:
|
|
continue
|
|
warn_last_time[i] = current_time
|
|
model_name = myModle_data[i][7]
|
|
w_s_count = warn_save_count[i]
|
|
buffer_count = channel_data.get_counter()
|
|
self.save_warn(model_name,w_s_count,buffer_count,channel_data.copy_deque(),
|
|
cap.width,cap.height,channel_id,None,self.FPS,self.fourcc)
|
|
self.send_warn()
|
|
#更新帧序列号
|
|
warn_save_count[i] = buffer_count
|
|
#结果记录要清空
|
|
for i in range(len(result)):
|
|
result[i] = 0
|
|
|
|
# end_time = time.time() # 结束时间
|
|
# print(f"Processing time: {end_time - start_time} seconds")
|
|
# 本地显示---测试使用
|
|
# if channel_id == 2:
|
|
# cv2.imshow(str(channel_id), img)
|
|
# if cv2.waitKey(1) & 0xFF == ord('q'):
|
|
# break
|
|
#结束线程
|
|
|
|
cap.release() #视频采集线程结束
|
|
if context:#ACL线程中反初始化内容 -- 若线程异常退出,这些资源就不能正常释放了
|
|
#先释放每个模型资源
|
|
for model in myModle_list:
|
|
del model
|
|
#再释放context
|
|
ACLModeManger.th_del_acl(context)
|
|
#cv2.destroyAllWindows()
|
|
|
|
def save_warn(self,model_name,w_s_count,buffer_count,buffer,width,height,channnel_id,myDBM,FPS,fourcc):
|
|
'''
|
|
保存报警信息 --- 涉及到I/O操作可以通过线程取执行 -- 避免主线程阻塞 --还未验证-2024-7-6
|
|
:param model_name: 模型名称,如人员入侵
|
|
:param w_s_count: 报警已存储的最新帧序列
|
|
:param buffer_count: 当前视频缓冲区的最新帧序列
|
|
:param buffer: 视频缓存区
|
|
:param width: 视频画面的width
|
|
:param height: 视频画面的height
|
|
:param channnel_id: 视频通道ID
|
|
:return: ret 数据库操作记录
|
|
'''
|
|
return
|
|
|
|
def save_warn_th(model_name,w_s_count,buffer_count,buffer,width,height,channnel_id,myDBM,FPS,fourcc):
|
|
now = datetime.datetime.now() # 获取当前日期和时间
|
|
current_time_str = now.strftime("%Y-%m-%d_%H-%M-%S")
|
|
filename = f"{channnel_id}_{current_time_str}"
|
|
save_path = myCongif.get_data("warn_video_path")
|
|
#保存视频
|
|
video_writer = cv2.VideoWriter(f"{save_path}{filename}.mp4", fourcc, FPS, (width, height))
|
|
if not video_writer.isOpened():
|
|
print(f"Failed to open video writer for model/warn/{filename}.mp4")
|
|
return False
|
|
ilen = len(buffer)
|
|
istart = 0;
|
|
iend = ilen
|
|
if buffer_count < w_s_count or (buffer_count-w_s_count) > ilen: #buffer_count重置过
|
|
#buffer区,都保存为视频
|
|
istart = 0
|
|
else:#只取差异的缓冲区大小
|
|
istart = ilen - (buffer_count-w_s_count)
|
|
for i in range(istart,iend):
|
|
video_writer.write(buffer[i])
|
|
video_writer.release()
|
|
#保存图片
|
|
ret = cv2.imwrite(f"model/warn/{filename}.png",buffer[-1])
|
|
#buffer使用完后删除
|
|
del buffer
|
|
if not ret:
|
|
print("保存图片失败")
|
|
return False
|
|
#保存数据库
|
|
myDBM = DBManager()
|
|
myDBM.connect()
|
|
strsql = (f"INSERT INTO warn (model_name ,video_path ,img_path ,creat_time,channel_id ) "
|
|
f"Values ('{model_name}','model/warn/{filename}.mp4','model/warn/{filename}.png',"
|
|
f"'{current_time_str}','{channnel_id}');")
|
|
ret = myDBM.do_sql(strsql)
|
|
del myDBM #释放数据库连接资源
|
|
return ret
|
|
|
|
th_chn = threading.Thread(target=save_warn_th,
|
|
args=(model_name,w_s_count,buffer_count,buffer,width,height,channnel_id,None,FPS,fourcc,)) # 一个视频通道一个线程,线程句柄暂时部保留
|
|
th_chn.start()
|
|
|
|
def send_warn(self):
|
|
'''发送报警信息'''
|
|
pass
|
|
|
|
def save_frame_to_video(self):
|
|
'''把缓冲区中的画面保存为录像'''
|
|
pass
|
|
|
|
def start_work(self,channel_id=0):
|
|
'''算法模型是在后台根据画面实时分析的
|
|
1.布防开关需要触发通道关闭和开启
|
|
2.布防策略的调整也需要关闭和重启工作
|
|
'''
|
|
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 = deque(maxlen=myCongif.get_data("buffer_len")) #创建个定长的视频buffer
|
|
# img = None
|
|
# icout = 0 #跟img_buffer对应,记录进入缓冲区的帧序列号
|
|
# run_data = [data[1],data[2],True,img_buffer,img,icout]
|
|
# self.verify_list[data[0]] = run_data #需要验证重复情况#? channel_id, str_url, int_type, bool_run, deque_length
|
|
self.verify_list.add_channel(data[0],data[1],data[2],True,myCongif.get_data("buffer_len"),myCongif.get_data("RESET_INTERVAL"))
|
|
th_chn = threading.Thread(target=self.dowork_thread, args=(data[0],)) #一个视频通道一个线程,线程句柄暂时部保留
|
|
th_chn.start()
|
|
|
|
def stop_work(self,channel_id=0):
|
|
'''停止工作线程,0-停止所有,非0停止对应通道ID的线程'''
|
|
self.verify_list.stop_channel(channel_id)
|
|
|
|
|
|
#print(f"Current working directory (ModelManager.py): {os.getcwd()}")
|
|
mMM = ModelManager()
|
|
def test1():
|
|
|
|
print(cv2.getBuildInformation())
|
|
source = 'rtsp://192.168.3.44/live1'
|
|
gstreamer_pipeline = (
|
|
f"rtspsrc location={source} protocols=udp latency=0 ! "
|
|
"rtph264depay ! h264parse ! avdec_h264 ! videoconvert ! appsink"
|
|
)
|
|
cap = cv2.VideoCapture(gstreamer_pipeline, cv2.CAP_GSTREAMER)
|
|
if not cap.isOpened():
|
|
print("Error: Unable to open the video source.")
|
|
return
|
|
else:
|
|
print("Successfully opened the video source.")
|
|
ret, frame = cap.read()
|
|
if ret:
|
|
cv2.imshow('Frame', frame)
|
|
cv2.waitKey(0)
|
|
cap.release()
|
|
cv2.destroyAllWindows()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
mMM.start_work()
|
|
#test1()
|
|
print("111")
|
|
# name = acl.get_soc_name()
|
|
# count, ret = acl.rt.get_device_count()
|
|
# print(name,count)
|
|
|
|
|
|
|
|
|
|
|