This commit is contained in:
Administrator 2025-08-23 10:12:26 +08:00
commit 7625fff310
631 changed files with 54820 additions and 0 deletions

10
README.md Normal file
View File

@ -0,0 +1,10 @@
1.2025.01.21把之前的tuoheng alg仓库代码重新开个仓库 (1)在config/service/dsp_test_service.yml里面添加参数控制存储用的oss还是minio storage_source: 1 2.2025.02.06 (1)修改代码把mqtt读取加入到系统中。config/service/dsp_test_service.yml中添加mqtt_flag,决定是否启用。 (2)修改了minio情况下的文件名命名方式。 3.2025.02.12 (1)增加了对alg算法开发的代码。可以通过配置文件config/service/dsp_test_service.yml中algSwitch: true决定是否启用。
4、2025.07.10 周树亮 - 增加人群计数自研车牌模型裸土覆盖3个场景
5、江朝庆 -- 0715
1代码整理删除冗余代码。
2增加requirements.txt,方便部署
3) logs
6 --0811

0
__init__.py Normal file
View File

443
common/Constant.py Normal file
View File

@ -0,0 +1,443 @@
# -*- coding: utf-8 -*-
# 编码格式
UTF_8 = "utf-8"
# 文件读模式
R = 'r'
ON_OR = "_on_or_"
ON_AI = "_on_ai_"
MP4 = ".mp4"
# 初始化进度
init_progess = "0.0000"
# 进度100%
success_progess = "1.0000"
# 拉流每帧图片缩小宽度大小限制, 大于1400像素缩小一半, 小于1400像素不变
width = 1400
COLOR = (
[0, 0, 255],
[255, 0, 0],
[211, 0, 148],
[0, 127, 0],
[0, 69, 255],
[0, 255, 0],
[255, 0, 255],
[0, 0, 127],
[127, 0, 255],
[255, 129, 0],
[139, 139, 0],
[255, 255, 0],
[127, 255, 0],
[0, 127, 255],
[0, 255, 127],
[255, 127, 255],
[8, 101, 139],
[171, 130, 255],
[139, 112, 74],
[205, 205, 180])
ONLINE = "online"
OFFLINE = "offline"
PHOTO = "photo"
RECORDING = "recording"
ONLINE_START_SCHEMA = {
"request_id": {
'type': 'string',
'required': True,
'empty': False,
'regex': r'^[a-zA-Z0-9]{1,36}$'
},
"command": {
'type': 'string',
'required': True,
'allowed': ["start"]
},
"pull_url": {
'type': 'string',
'required': True,
'empty': False,
'maxlength': 255
},
"push_url": {
'type': 'string',
'required': True,
'empty': False,
'maxlength': 255
},
"logo_url": {
'type': 'string',
'required': False,
'nullable': True,
'maxlength': 255
},
"models": {
'type': 'list',
'required': True,
'nullable': False,
'minlength': 1,
'maxlength': 3,
'schema': {
'type': 'dict',
'required': True,
'schema': {
"code": {
'type': 'string',
'required': True,
'empty': False,
'dependencies': "categories",
'regex': r'^[a-zA-Z0-9]{1,255}$'
},
"is_video": {
'type': 'string',
'required': True,
'empty': False,
'dependencies': "code",
'allowed': ["0", "1"]
},
"is_image": {
'type': 'string',
'required': True,
'empty': False,
'dependencies': "code",
'allowed': ["0", "1"]
},
"categories": {
'type': 'list',
'required': True,
'dependencies': "code",
'schema': {
'type': 'dict',
'required': True,
'schema': {
"id": {
'type': 'string',
'required': True,
'empty': False,
'regex': r'^[a-zA-Z0-9]{0,255}$'},
"config": {
'type': 'dict',
'required': False,
'dependencies': "id",
}
}
}
}
}
}
}
}
ONLINE_STOP_SCHEMA = {
"request_id": {
'type': 'string',
'required': True,
'empty': False,
'regex': r'^[a-zA-Z0-9]{1,36}$'
},
"command": {
'type': 'string',
'required': True,
'allowed': ["stop"]
}
}
OFFLINE_START_SCHEMA = {
"request_id": {
'type': 'string',
'required': True,
'empty': False,
'regex': r'^[a-zA-Z0-9]{1,36}$'
},
"command": {
'type': 'string',
'required': True,
'allowed': ["start"]
},
"push_url": {
'type': 'string',
'required': True,
'empty': False,
'maxlength': 255
},
"pull_url": {
'type': 'string',
'required': True,
'empty': False,
'maxlength': 255
},
"logo_url": {
'type': 'string',
'required': False,
'nullable': True,
'maxlength': 255
},
"models": {
'type': 'list',
'required': True,
'maxlength': 3,
'minlength': 1,
'schema': {
'type': 'dict',
'required': True,
'schema': {
"code": {
'type': 'string',
'required': True,
'empty': False,
'dependencies': "categories",
'regex': r'^[a-zA-Z0-9]{1,255}$'
},
"is_video": {
'type': 'string',
'required': True,
'empty': False,
'dependencies': "code",
'allowed': ["0", "1"]
},
"is_image": {
'type': 'string',
'required': True,
'empty': False,
'dependencies': "code",
'allowed': ["0", "1"]
},
"categories": {
'type': 'list',
'required': True,
'dependencies': "code",
'schema': {
'type': 'dict',
'required': True,
'schema': {
"id": {
'type': 'string',
'required': True,
'empty': False,
'regex': r'^[a-zA-Z0-9]{0,255}$'},
"config": {
'type': 'dict',
'required': False,
'dependencies': "id",
}
}
}
}
}
}
}
}
OFFLINE_STOP_SCHEMA = {
"request_id": {
'type': 'string',
'required': True,
'empty': False,
'regex': r'^[a-zA-Z0-9]{1,36}$'
},
"command": {
'type': 'string',
'required': True,
'allowed': ["stop"]
}
}
IMAGE_SCHEMA = {
"request_id": {
'type': 'string',
'required': True,
'empty': False,
'regex': r'^[a-zA-Z0-9]{1,36}$'
},
"command": {
'type': 'string',
'required': True,
'allowed': ["start"]
},
"logo_url": {
'type': 'string',
'required': False,
'nullable': True,
'maxlength': 255
},
"image_urls": {
'type': 'list',
'required': True,
'minlength': 1,
'schema': {
'type': 'string',
'required': True,
'empty': False,
'maxlength': 5000
}
},
"models": {
'type': 'list',
'required': True,
'schema': {
'type': 'dict',
'required': True,
'schema': {
"code": {
'type': 'string',
'required': True,
'empty': False,
'dependencies': "categories",
'regex': r'^[a-zA-Z0-9]{1,255}$'
},
"is_video": {
'type': 'string',
'required': True,
'empty': False,
'dependencies': "code",
'allowed': ["0", "1"]
},
"is_image": {
'type': 'string',
'required': True,
'empty': False,
'dependencies': "code",
'allowed': ["0", "1"]
},
"categories": {
'type': 'list',
'required': True,
'dependencies': "code",
'schema': {
'type': 'dict',
'required': True,
'schema': {
"id": {
'type': 'string',
'required': True,
'empty': False,
'regex': r'^[a-zA-Z0-9]{0,255}$'},
"config": {
'type': 'dict',
'required': False,
'dependencies': "id",
}
}
}
}
}
}
}
}
RECORDING_START_SCHEMA = {
"request_id": {
'type': 'string',
'required': True,
'empty': False,
'regex': r'^[a-zA-Z0-9]{1,36}$'
},
"command": {
'type': 'string',
'required': True,
'allowed': ["start"]
},
"pull_url": {
'type': 'string',
'required': True,
'empty': False,
'maxlength': 255
},
"push_url": {
'type': 'string',
'required': False,
'empty': True,
'maxlength': 255
},
"logo_url": {
'type': 'string',
'required': False,
'nullable': True,
'maxlength': 255
}
}
RECORDING_STOP_SCHEMA = {
"request_id": {
'type': 'string',
'required': True,
'empty': False,
'regex': r'^[a-zA-Z0-9]{1,36}$'
},
"command": {
'type': 'string',
'required': True,
'allowed': ["stop"]
}
}
PULL2PUSH_START_SCHEMA = {
"request_id": {
'type': 'string',
'required': True,
'empty': False,
'regex': r'^[a-zA-Z0-9]{1,36}$'
},
"command": {
'type': 'string',
'required': True,
'allowed': ["start"]
},
"video_urls": {
'type': 'list',
'required': True,
'nullable': False,
'schema': {
'type': 'dict',
'required': True,
'schema': {
"id": {
'type': 'string',
'required': True,
'empty': False,
'dependencies': "pull_url",
'regex': r'^[a-zA-Z0-9]{1,255}$'
},
"pull_url": {
'type': 'string',
'required': True,
'empty': False,
'dependencies': "push_url",
'regex': r'^(https|http|rtsp|rtmp|artc|webrtc|ws)://\w.+$'
},
"push_url": {
'type': 'string',
'required': True,
'empty': False,
'dependencies': "id",
'regex': r'^(https|http|rtsp|rtmp|artc|webrtc|ws)://\w.+$'
}
}
}
}
}
PULL2PUSH_STOP_SCHEMA = {
"request_id": {
'type': 'string',
'required': True,
'empty': False,
'regex': r'^[a-zA-Z0-9]{1,36}$'
},
"command": {
'type': 'string',
'required': True,
'allowed': ["start", "stop"]
},
"video_ids": {
'type': 'list',
'required': False,
'nullable': True,
'schema': {
'type': 'string',
'required': True,
'empty': False,
'regex': r'^[a-zA-Z0-9]{1,255}$'
}
}
}

14
common/YmlConstant.py Normal file
View File

@ -0,0 +1,14 @@
# -*- coding: utf-8 -*-
# 服务配置路径
service_yml_path = 'config/service/dsp_%s_service.yml'
# kafka配置路径
kafka_yml_path = 'config/kafka/dsp_%s_kafka.yml'
# 阿里云配置路径
aliyun_yml_path = "config/aliyun/dsp_%s_aliyun.yml"
# 百度配置路径
baidu_yml_path = 'config/baidu/dsp_%s_baidu.yml'
# minio配置路径
minio_yml_path = 'config/minio/dsp_%s_minio.yml'
# mqtt配置路径
mqtt_yml_path = 'config/mqtt/dsp_%s_mqtt.yml'

0
common/__init__.py Normal file
View File

View File

@ -0,0 +1,23 @@
from threading import Thread
from loguru import logger
class Common(Thread):
__slots__ = ('__func', '__param1', '__param2', '__result')
def __init__(self, func, param1, param2):
super(Common, self).__init__()
self.__func = func
self.__param1 = param1
self.__param2 = param2
self.__result = None
def get_result(self):
self.join()
return self.__result
def run(self):
logger.info("开始执行线程!")
self.__result = self.__func(self.__param1, self.__param2)
logger.info("线程停止完成!")

View File

@ -0,0 +1,67 @@
# -*- coding: utf-8 -*-
import time
from threading import Thread
from traceback import format_exc
from loguru import logger
from util.KafkaUtils import CustomerKafkaProducer
'''
问题反馈线程
'''
class FeedbackThread(Thread):
__slots__ = ('__fbQueue', '__kafka_config')
def __init__(self, fbQueue, kafka_config):
super().__init__()
self.__fbQueue = fbQueue
self.__kafka_config = kafka_config
'''
阻塞获取反馈消息
'''
def getFeedback(self):
return self.__fbQueue.get()
def run(self):
logger.info("启动问题反馈线程")
kafkaProducer = CustomerKafkaProducer(self.__kafka_config)
dsp_alg_results_topic = self.__kafka_config["topic"]["dsp-alg-results-topic"]
dsp_recording_result_topic = self.__kafka_config["topic"]["dsp-recording-result-topic"]
dsp_push_stream_result_topic = self.__kafka_config["topic"]["dsp-push-stream-result-topic"]
while True:
logger.info("问题反馈发送消息循环")
feedback = None
recording = None
pull_stream = None
try:
fb = self.getFeedback()
if fb is not None and len(fb) > 0:
feedback = fb.get("feedback")
recording = fb.get("recording")
pull_stream = fb.get("pull_stream")
if feedback is not None and len(feedback) > 0:
kafkaProducer.sender(dsp_alg_results_topic, feedback["request_id"], feedback, 1)
feedback = None
if recording is not None and len(recording) > 0:
kafkaProducer.sender(dsp_recording_result_topic, recording["request_id"], recording, 1)
recording = None
if pull_stream is not None and len(pull_stream) > 0:
kafkaProducer.sender(dsp_push_stream_result_topic, pull_stream["request_id"], pull_stream, 1)
pull_stream = None
else:
time.sleep(1)
except Exception:
if feedback and feedback.get("request_id"):
logger.error("问题反馈异常:{}, requestId:{}", format_exc(), feedback.get("request_id"))
elif recording and recording.get("request_id"):
logger.error("问题反馈异常:{}, requestId:{}", format_exc(), recording.get("request_id"))
elif pull_stream and pull_stream.get("request_id"):
logger.error("问题反馈异常:{}, requestId:{}", format_exc(), pull_stream.get("request_id"))
else:
logger.error("问题反馈异常:{}", format_exc())
logger.info("问题反馈线程执行完成")

View File

@ -0,0 +1,423 @@
# -*- coding: utf-8 -*-
from concurrent.futures import ThreadPoolExecutor
from threading import Thread
from time import sleep, time
from traceback import format_exc
from loguru import logger
import cv2
from entity.FeedBack import message_feedback
from enums.ExceptionEnum import ExceptionType
from enums.ModelTypeEnum import ModelType
from exception.CustomerException import ServiceException
from util.AliyunSdk import AliyunOssSdk
from util.MinioSdk import MinioSdk
from util import TimeUtils
from enums.AnalysisStatusEnum import AnalysisStatus
from util.PlotsUtils import draw_painting_joint, draw_name_ocr, draw_name_crowd
from util.QueUtil import put_queue, get_no_block_queue, clear_queue
import io
from util.LocationUtils import locate_byMqtt
class FileUpload(Thread):
__slots__ = ('_fb_queue', '_context', '_image_queue', '_analyse_type', '_msg', '_mqtt_list')
def __init__(self, *args):
super().__init__()
self._fb_queue, self._context, self._msg, self._image_queue, self._analyse_type, self._mqtt_list = args
self._storage_source = self._context['service']['storage_source']
self._algStatus = False # 默认关闭
# self._algStatus = True # 默认关闭
self._algSwitch = self._context['service']['algSwitch']
# 0521:
default_enabled = str(self._msg.get("defaultEnabled", "True")).lower() == "true"
if default_enabled:
print("执行默认程序defaultEnabled=True")
self._algSwitch = True
# 这里放默认逻辑的代码
else:
print("执行替代程序defaultEnabled=False")
# 这里放非默认逻辑的代码
self._algSwitch = False
print("---line46 :FileUploadThread.py---", self._algSwitch)
# 如果任务是在线、离线处理,则用此类
class ImageFileUpload(FileUpload):
__slots__ = ()
# @staticmethod
def handle_image(self, frame_msg, frame_step):
# (high_score_image["code"], all_frames, draw_config["font_config"])
# high_score_image["code"][code][cls] = (frame, frame_index_list[i], cls_list)
det_xywh, frame, current_frame, all_frames, font_config = frame_msg
'''
det_xywh:{
'code':{
1: [[detect_targets_code, box, score, label_array, color,is_new]]
}
} #is_new--是否是新的目标。
模型编号modeCode
检测目标detectTargetCode
'''
print('*' * 100, ' mqtt_list:', len(self._mqtt_list))
model_info = []
# 更加模型编码解析数据
for code, det_list in det_xywh.items():
if len(det_list) > 0:
for cls, target_list in det_list.items():
if len(target_list) > 0:
aFrame = frame.copy()
for target in target_list:
# 自研车牌模型判断
if ModelType.CITY_CARPLATE_MODEL.value[1] == str(code):
draw_name_ocr(target[1], aFrame, target[4])
elif ModelType.CITY_DENSECROWDCOUNT_MODEL.value[1] == str(code) or\
ModelType.CITY_UNDERBUILDCOUNT_MODEL.value[1] == str(code):
draw_name_crowd(target[1], aFrame, target[4])
else:
draw_painting_joint(target[1], aFrame, target[3], target[2], target[4], font_config,
target[5])
igH, igW = aFrame.shape[0:2]
if len(self._mqtt_list) >= 1:
# camParas = self._mqtt_list[0]['data']
camParas = self._mqtt_list[0]
gps = locate_byMqtt(target[1], igW, igH, camParas, outFormat='wgs84')
else:
gps = [None, None]
model_info.append(
{"modelCode": str(code), "detectTargetCode": str(cls), "aFrame": aFrame, 'gps': gps})
if len(model_info) > 0:
image_result = {
"or_frame": frame,
"model_info": model_info,
"current_frame": current_frame,
"last_frame": current_frame + frame_step
}
return image_result
return None
def run(self):
msg, context = self._msg, self._context
service = context["service"]
base_dir, env, request_id = context["base_dir"], context["env"], msg["request_id"]
logger.info("启动图片上传线程, requestId: {}", request_id)
image_queue, fb_queue, analyse_type = self._image_queue, self._fb_queue, self._analyse_type
service_timeout = int(service["timeout"])
frame_step = int(service["filter"]["frame_step"]) + 120
if msg['taskType'] == 0:
self._algStatus = False
else:
self._algStatus = True
try:
with ThreadPoolExecutor(max_workers=2) as t:
# 初始化oss客户端
if self._storage_source == 1:
minioSdk = MinioSdk(base_dir, env, request_id)
else:
aliyunOssSdk = AliyunOssSdk(base_dir, env, request_id)
start_time = time()
while True:
try:
if time() - start_time > service_timeout:
logger.error("图片上传线程运行超时, requestId: {}", request_id)
break
raise ServiceException(ExceptionType.TASK_EXCUTE_TIMEOUT.value[0],
ExceptionType.TASK_EXCUTE_TIMEOUT.value[1])
# 获取队列中的消息
image_msg = get_no_block_queue(image_queue)
if image_msg is not None:
if image_msg[0] == 2:
logger.info("图片上传线程收到命令:{}, requestId: {}", image_msg[1], request_id)
if 'stop' == image_msg[1]:
logger.info("开始停止图片上传线程, requestId:{}", request_id)
break
if 'algStart' == image_msg[1]: self._algStatus = True; logger.info(
"图片上传线程,执行算法开启命令, requestId:{}", request_id)
if 'algStop' == image_msg[1]: self._algStatus = False; logger.info(
"图片上传线程,执行算法关闭命令, requestId:{}", request_id)
if image_msg[0] == 1:
image_result = self.handle_image(image_msg[1], frame_step)
if image_result is not None:
task = []
or_image = cv2.imencode(".jpg", image_result["or_frame"])[1]
or_image_name = build_image_name(image_result["current_frame"],
image_result["last_frame"],
analyse_type,
"OR", "0", "0", request_id)
if self._storage_source == 1:
or_future = t.submit(minioSdk.put_object, or_image, or_image_name)
else:
or_future = t.submit(aliyunOssSdk.put_object, or_image_name, or_image.tobytes())
task.append(or_future)
model_info_list = image_result["model_info"]
msg_list = []
for model_info in model_info_list:
ai_image = cv2.imencode(".jpg", model_info["aFrame"])[1]
ai_image_name = build_image_name(image_result["current_frame"],
image_result["last_frame"],
analyse_type,
"AI",
model_info["modelCode"],
model_info["detectTargetCode"],
request_id)
if self._storage_source == 1:
ai_future = t.submit(minioSdk.put_object, ai_image,
ai_image_name)
else:
ai_future = t.submit(aliyunOssSdk.put_object, ai_image_name,
ai_image.tobytes())
task.append(ai_future)
# msg_list.append(message_feedback(request_id,
# AnalysisStatus.RUNNING.value,
# analyse_type, "", "", "",
# or_image_name,
# ai_image_name,
# model_info['modelCode'],
# model_info['detectTargetCode']))
remote_image_list = []
for tk in task:
remote_image_list.append(tk.result())
for ii, model_info in enumerate(model_info_list):
msg_list.append(message_feedback(request_id,
AnalysisStatus.RUNNING.value,
analyse_type, "", "", "",
remote_image_list[0],
remote_image_list[ii + 1],
model_info['modelCode'],
model_info['detectTargetCode'],
longitude=model_info['gps'][0],
latitude=model_info['gps'][1],
))
if (not self._algSwitch) or (self._algStatus and self._algSwitch):
for msg in msg_list:
put_queue(fb_queue, msg, timeout=2, is_ex=False)
del task, msg_list
else:
sleep(1)
del image_msg
except Exception:
logger.error("图片上传异常:{}, requestId:{}", format_exc(), request_id)
finally:
logger.info("停止图片上传线程0, requestId:{}", request_id)
clear_queue(image_queue)
logger.info("停止图片上传线程1, requestId:{}", request_id)
def build_image_name(*args):
"""
{requestId}/{time_now}_frame-{current_frame}-{last_frame}_type_{random_num}-{mode_type}" \
"-{modeCode}-{target}_{image_type}.jpg
"""
current_frame, last_frame, mode_type, image_type, modeCode, target, request_id = args
random_num = TimeUtils.now_date_to_str(TimeUtils.YMDHMSF)
time_now = TimeUtils.now_date_to_str("%Y-%m-%d-%H-%M-%S")
return "%s/%s_frame-%s-%s_type_%s-%s-%s-%s_%s.jpg" % (request_id, time_now, current_frame, last_frame,
random_num, mode_type, modeCode, target, image_type)
# 如果任务是图像处理,则用此类
class ImageTypeImageFileUpload(Thread):
__slots__ = ('_fb_queue', '_context', '_image_queue', '_analyse_type', '_msg')
def __init__(self, *args):
super().__init__()
self._fb_queue, self._context, self._msg, self._image_queue, self._analyse_type = args
self._storage_source = self._context['service']['storage_source']
@staticmethod
def handle_image(det_xywh, copy_frame, font_config):
"""
det_xywh:{
'code':{
1: [[detect_targets_code, box, score, label_array, color]]
}
}
模型编号modeCode
检测目标detectTargetCode
"""
model_info = []
# 更加模型编码解析数据
for code, det_info in det_xywh.items():
if det_info is not None and len(det_info) > 0:
for cls, target_list in det_info.items():
if target_list is not None and len(target_list) > 0:
aiFrame = copy_frame.copy()
for target in target_list:
# 自研车牌模型判断
if ModelType.CITY_CARPLATE_MODEL.value[1] == str(code):
draw_name_ocr(target, aiFrame, font_config[cls])
elif ModelType.CITY_DENSECROWDCOUNT_MODEL.value[1] == str(code) or \
ModelType.CITY_UNDERBUILDCOUNT_MODEL.value[1] == str(code):
draw_name_crowd(target, aiFrame, font_config[cls])
else:
draw_painting_joint(target[1], aiFrame, target[3], target[2], target[4], font_config)
model_info.append({
"modelCode": str(code),
"detectTargetCode": str(cls),
"frame": aiFrame
})
if len(model_info) > 0:
image_result = {
"or_frame": copy_frame,
"model_info": model_info,
"current_frame": 0,
"last_frame": 0
}
return image_result
return None
def run(self):
context, msg = self._context, self._msg
base_dir, env, request_id = context["base_dir"], context["env"], msg["request_id"]
logger.info("启动图片识别图片上传线程, requestId: {}", request_id)
image_queue, fb_queue, analyse_type = self._image_queue, self._fb_queue, self._analyse_type
service_timeout = int(context["service"]["timeout"])
with ThreadPoolExecutor(max_workers=2) as t:
try:
# 初始化oss客户端
if self._storage_source == 1:
minioSdk = MinioSdk(base_dir, env, request_id)
else:
aliyunOssSdk = AliyunOssSdk(base_dir, env, request_id)
start_time = time()
while True:
try:
if time() - start_time > service_timeout:
logger.error("图片上传进程运行超时, requestId: {}", request_id)
break
# 获取队列中的消息
image_msg = image_queue.get()
if image_msg is not None:
if image_msg[0] == 2:
if 'stop' == image_msg[1]:
logger.info("开始停止图片上传线程, requestId:{}", request_id)
break
if image_msg[0] == 1:
task, msg_list = [], []
det_xywh, image_url, copy_frame, font_config, result = image_msg[1]
remote_names = []
if det_xywh is None:
ai_image_name = build_image_name(0, 0, analyse_type, "AI", result.get("modelCode"),
result.get("type"), request_id)
if self._storage_source == 1:
ai_future = t.submit(minioSdk.put_object, copy_frame, ai_image_name)
else:
ai_future = t.submit(aliyunOssSdk.put_object, ai_image_name, copy_frame)
task.append(ai_future)
remote_names.append(ai_image_name)
# msg_list.append(message_feedback(request_id,
# AnalysisStatus.RUNNING.value,
# analyse_type, "", "", "",
# image_url,
# ai_image_name,
# result.get("modelCode"),
# result.get("type"),
# analyse_results=result))
else:
image_result = self.handle_image(det_xywh, copy_frame, font_config)
if image_result:
# 图片帧数编码
if image_url is None:
or_result, or_image = cv2.imencode(".jpg", image_result.get("or_frame"))
image_url_0 = build_image_name(image_result.get("current_frame"),
image_result.get("last_frame"),
analyse_type,
"OR", "0", "O", request_id)
if self._storage_source == 1:
or_future = t.submit(minioSdk.put_object, or_image, image_url_0)
else:
or_future = t.submit(aliyunOssSdk.put_object, image_url_0,
or_image.tobytes())
task.append(or_future)
remote_names.append(image_url_0)
model_info_list = image_result.get("model_info")
for model_info in model_info_list:
ai_result, ai_image = cv2.imencode(".jpg", model_info.get("frame"))
ai_image_name = build_image_name(image_result.get("current_frame"),
image_result.get("last_frame"),
analyse_type,
"AI",
model_info.get("modelCode"),
model_info.get("detectTargetCode"),
request_id)
if self._storage_source == 1:
ai_future = t.submit(minioSdk.put_object, ai_image, ai_image_name)
else:
ai_future = t.submit(aliyunOssSdk.put_object, ai_image_name,
ai_image.tobytes())
task.append(ai_future)
remote_names.append(ai_image_name)
# msg_list.append(message_feedback(request_id,
# AnalysisStatus.RUNNING.value,
# analyse_type, "", "", "",
# image_url,
# ai_image_name,
# model_info.get('modelCode'),
# model_info.get('detectTargetCode'),
# analyse_results=result))
remote_url_list = []
for thread_result in task:
remote_url_list.append(thread_result.result())
# 以下代码是为了获取图像上传后,返回的全路径地址
if det_xywh is None:
msg_list.append(message_feedback(request_id,
AnalysisStatus.RUNNING.value,
analyse_type, "", "", "",
image_url,
remote_url_list[0],
result.get("modelCode"),
result.get("type"),
analyse_results=result))
else:
if image_result:
if image_url is None:
for ii in range(len(remote_names) - 1):
msg_list.append(message_feedback(request_id,
AnalysisStatus.RUNNING.value,
analyse_type, "", "", "",
remote_url_list[0],
remote_url_list[1 + ii],
model_info.get('modelCode'),
model_info.get('detectTargetCode'),
analyse_results=result))
else:
for ii in range(len(remote_names)):
msg_list.append(message_feedback(request_id,
AnalysisStatus.RUNNING.value,
analyse_type, "", "", "",
image_url,
remote_url_list[ii],
model_info_list[ii].get('modelCode'),
model_info_list[ii].get(
'detectTargetCode'),
analyse_results=result))
for msg in msg_list:
put_queue(fb_queue, msg, timeout=2, is_ex=False)
else:
sleep(1)
except Exception as e:
logger.error("图片上传异常:{}, requestId:{}", format_exc(), request_id)
finally:
clear_queue(image_queue)
logger.info("停止图片识别图片上传线程, requestId:{}", request_id)

View File

@ -0,0 +1,315 @@
# -*- coding: utf-8 -*-
from concurrent.futures import ThreadPoolExecutor
from threading import Thread
from time import sleep, time
from traceback import format_exc
from loguru import logger
import cv2
from entity.FeedBack import message_feedback
from enums.ExceptionEnum import ExceptionType
from exception.CustomerException import ServiceException
from util.AliyunSdk import AliyunOssSdk
from util.MinioSdk import MinioSdk
from util import TimeUtils
from enums.AnalysisStatusEnum import AnalysisStatus
from util.PlotsUtils import draw_painting_joint
from util.QueUtil import put_queue, get_no_block_queue, clear_queue
import io
class FileUpload(Thread):
__slots__ = ('_fb_queue', '_context', '_image_queue', '_analyse_type', '_msg')
def __init__(self, *args):
super().__init__()
self._fb_queue, self._context, self._msg, self._image_queue, self._analyse_type = args
self._storage_source = self._context['service']['storage_source']
class ImageFileUpload(FileUpload):
__slots__ = ()
@staticmethod
def handle_image(frame_msg, frame_step):
# (high_score_image["code"], all_frames, draw_config["font_config"])
# high_score_image["code"][code][cls] = (frame, frame_index_list[i], cls_list)
det_xywh, frame, current_frame, all_frames, font_config = frame_msg
'''
det_xywh:{
'code':{
1: [[detect_targets_code, box, score, label_array, color]]
}
}
模型编号modeCode
检测目标detectTargetCode
'''
model_info = []
# 更加模型编码解析数据
for code, det_list in det_xywh.items():
if len(det_list) > 0:
for cls, target_list in det_list.items():
if len(target_list) > 0:
aFrame = frame.copy()
for target in target_list:
draw_painting_joint(target[1], aFrame, target[3], target[2], target[4], font_config, target[5])
model_info.append({"modelCode": str(code), "detectTargetCode": str(cls), "aFrame": aFrame})
if len(model_info) > 0:
image_result = {
"or_frame": frame,
"model_info": model_info,
"current_frame": current_frame,
"last_frame": current_frame + frame_step
}
return image_result
return None
def run(self):
msg, context = self._msg, self._context
service = context["service"]
base_dir, env, request_id = context["base_dir"], context["env"], msg["request_id"]
logger.info("启动图片上传线程, requestId: {}", request_id)
image_queue, fb_queue, analyse_type = self._image_queue, self._fb_queue, self._analyse_type
service_timeout = int(service["timeout"])
frame_step = int(service["filter"]["frame_step"]) + 120
try:
with ThreadPoolExecutor(max_workers=2) as t:
# 初始化oss客户端
if self._storage_source==1:
minioSdk = MinioSdk(base_dir, env, request_id )
else:
aliyunOssSdk = AliyunOssSdk(base_dir, env, request_id)
start_time = time()
while True:
try:
if time() - start_time > service_timeout:
logger.error("图片上传线程运行超时, requestId: {}", request_id)
break
raise ServiceException(ExceptionType.TASK_EXCUTE_TIMEOUT.value[0],
ExceptionType.TASK_EXCUTE_TIMEOUT.value[1])
# 获取队列中的消息
image_msg = get_no_block_queue(image_queue)
if image_msg is not None:
if image_msg[0] == 2:
if 'stop' == image_msg[1]:
logger.info("开始停止图片上传线程, requestId:{}", request_id)
break
if image_msg[0] == 1:
image_result = self.handle_image(image_msg[1], frame_step)
if image_result is not None:
task = []
or_image = cv2.imencode(".jpg", image_result["or_frame"])[1]
or_image_name = build_image_name(image_result["current_frame"],
image_result["last_frame"],
analyse_type,
"OR", "0", "0", request_id)
if self._storage_source==1:
or_future = t.submit(minioSdk.put_object, or_image,or_image_name)
else:
or_future = t.submit(aliyunOssSdk.put_object, or_image_name, or_image.tobytes())
task.append(or_future)
model_info_list = image_result["model_info"]
msg_list = []
for model_info in model_info_list:
ai_image = cv2.imencode(".jpg", model_info["aFrame"])[1]
ai_image_name = build_image_name(image_result["current_frame"],
image_result["last_frame"],
analyse_type,
"AI",
model_info["modelCode"],
model_info["detectTargetCode"],
request_id)
if self._storage_source==1:
ai_future = t.submit(minioSdk.put_object, ai_image,
ai_image_name)
else:
ai_future = t.submit(aliyunOssSdk.put_object, ai_image_name,
ai_image.tobytes())
task.append(ai_future)
#msg_list.append(message_feedback(request_id,
# AnalysisStatus.RUNNING.value,
# analyse_type, "", "", "",
# or_image_name,
# ai_image_name,
# model_info['modelCode'],
# model_info['detectTargetCode']))
remote_image_list=[]
for tk in task:
remote_image_list.append( tk.result())
for ii,model_info in enumerate(model_info_list):
msg_list.append( message_feedback(request_id,
AnalysisStatus.RUNNING.value,
analyse_type, "", "", "",
remote_image_list[0],
remote_image_list[ii+1],
model_info['modelCode'],
model_info['detectTargetCode']) )
for msg in msg_list:
put_queue(fb_queue, msg, timeout=2, is_ex=False)
del task, msg_list
else:
sleep(1)
del image_msg
except Exception:
logger.error("图片上传异常:{}, requestId:{}", format_exc(), request_id)
finally:
logger.info("停止图片上传线程0, requestId:{}", request_id)
clear_queue(image_queue)
logger.info("停止图片上传线程1, requestId:{}", request_id)
def build_image_name(*args):
"""
{requestId}/{time_now}_frame-{current_frame}-{last_frame}_type_{random_num}-{mode_type}" \
"-{modeCode}-{target}_{image_type}.jpg
"""
current_frame, last_frame, mode_type, image_type, modeCode, target, request_id = args
random_num = TimeUtils.now_date_to_str(TimeUtils.YMDHMSF)
time_now = TimeUtils.now_date_to_str("%Y-%m-%d-%H-%M-%S")
return "%s/%s_frame-%s-%s_type_%s-%s-%s-%s_%s.jpg" % (request_id, time_now, current_frame, last_frame,
random_num, mode_type, modeCode, target, image_type)
class ImageTypeImageFileUpload(Thread):
__slots__ = ('_fb_queue', '_context', '_image_queue', '_analyse_type', '_msg')
def __init__(self, *args):
super().__init__()
self._fb_queue, self._context, self._msg, self._image_queue, self._analyse_type = args
self._storage_source = self._context['service']['storage_source']
@staticmethod
def handle_image(det_xywh, copy_frame, font_config):
"""
det_xywh:{
'code':{
1: [[detect_targets_code, box, score, label_array, color]]
}
}
模型编号modeCode
检测目标detectTargetCode
"""
model_info = []
# 更加模型编码解析数据
for code, det_info in det_xywh.items():
if det_info is not None and len(det_info) > 0:
for cls, target_list in det_info.items():
if target_list is not None and len(target_list) > 0:
aiFrame = copy_frame.copy()
for target in target_list:
draw_painting_joint(target[1], aiFrame, target[3], target[2], target[4], font_config)
model_info.append({
"modelCode": str(code),
"detectTargetCode": str(cls),
"frame": aiFrame
})
if len(model_info) > 0:
image_result = {
"or_frame": copy_frame,
"model_info": model_info,
"current_frame": 0,
"last_frame": 0
}
return image_result
return None
def run(self):
context, msg = self._context, self._msg
base_dir, env, request_id = context["base_dir"], context["env"], msg["request_id"]
logger.info("启动图片识别图片上传线程, requestId: {}", request_id)
image_queue, fb_queue, analyse_type = self._image_queue, self._fb_queue, self._analyse_type
service_timeout = int(context["service"]["timeout"])
with ThreadPoolExecutor(max_workers=2) as t:
try:
# 初始化oss客户端
if self._storage_source==1:
minioSdk = MinioSdk(base_dir, env, request_id )
else:
aliyunOssSdk = AliyunOssSdk(base_dir, env, request_id)
start_time = time()
while True:
try:
if time() - start_time > service_timeout:
logger.error("图片上传进程运行超时, requestId: {}", request_id)
break
# 获取队列中的消息
image_msg = image_queue.get()
if image_msg is not None:
if image_msg[0] == 2:
if 'stop' == image_msg[1]:
logger.info("开始停止图片上传线程, requestId:{}", request_id)
break
if image_msg[0] == 1:
task, msg_list = [], []
det_xywh, image_url, copy_frame, font_config, result = image_msg[1]
if det_xywh is None:
ai_image_name = build_image_name(0, 0, analyse_type, "AI", result.get("modelCode"),
result.get("type"), request_id)
if self._storage_source==1:
ai_future = t.submit(minioSdk.put_object, copy_frame,ai_image_name)
else:
ai_future = t.submit(aliyunOssSdk.put_object, ai_image_name, copy_frame)
task.append(ai_future)
msg_list.append(message_feedback(request_id,
AnalysisStatus.RUNNING.value,
analyse_type, "", "", "",
image_url,
ai_image_name,
result.get("modelCode"),
result.get("type"),
analyse_results=result))
else:
image_result = self.handle_image(det_xywh, copy_frame, font_config)
if image_result:
# 图片帧数编码
if image_url is None:
or_result, or_image = cv2.imencode(".jpg", image_result.get("or_frame"))
image_url = build_image_name(image_result.get("current_frame"),
image_result.get("last_frame"),
analyse_type,
"OR", "0", "O", request_id)
if self._storage_source==1:
or_future = t.submit(minioSdk.put_object, or_image,image_url)
else:
or_future = t.submit(aliyunOssSdk.put_object, image_url,
or_image.tobytes())
task.append(or_future)
model_info_list = image_result.get("model_info")
for model_info in model_info_list:
ai_result, ai_image = cv2.imencode(".jpg", model_info.get("frame"))
ai_image_name = build_image_name(image_result.get("current_frame"),
image_result.get("last_frame"),
analyse_type,
"AI",
model_info.get("modelCode"),
model_info.get("detectTargetCode"),
request_id)
if self._storage_source==1:
ai_future = t.submit(minioSdk.put_object, ai_image, ai_image_name)
else:
ai_future = t.submit(aliyunOssSdk.put_object, ai_image_name,
ai_image.tobytes())
task.append(ai_future)
msg_list.append(message_feedback(request_id,
AnalysisStatus.RUNNING.value,
analyse_type, "", "", "",
image_url,
ai_image_name,
model_info.get('modelCode'),
model_info.get('detectTargetCode'),
analyse_results=result))
for thread_result in task:
thread_result.result()
for msg in msg_list:
put_queue(fb_queue, msg, timeout=2, is_ex=False)
else:
sleep(1)
except Exception as e:
logger.error("图片上传异常:{}, requestId:{}", format_exc(), request_id)
finally:
clear_queue(image_queue)
logger.info("停止图片识别图片上传线程, requestId:{}", request_id)

View File

@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
from threading import Thread
from time import sleep, time
from traceback import format_exc
from loguru import logger
from common.Constant import init_progess
from enums.AnalysisStatusEnum import AnalysisStatus
from entity.FeedBack import message_feedback
from enums.ExceptionEnum import ExceptionType
from exception.CustomerException import ServiceException
from util.QueUtil import get_no_block_queue, put_queue, clear_queue
class Heartbeat(Thread):
__slots__ = ('__fb_queue', '__hb_queue', '__request_id', '__analyse_type', "_context")
def __init__(self, *args):
super().__init__()
self.__fb_queue, self.__hb_queue, self.__request_id, self.__analyse_type, self._context = args
def run(self):
request_id, hb_queue, progress = self.__request_id, self.__hb_queue, init_progess
analyse_type, fb_queue = self.__analyse_type, self.__fb_queue
service_timeout = int(self._context["service"]["timeout"]) + 120
try:
logger.info("开始启动心跳线程requestId:{}", request_id)
start_time = time()
hb_init_num = 0
while True:
if time() - start_time > service_timeout:
logger.error("心跳运行超时, requestId: {}", request_id)
raise ServiceException(ExceptionType.TASK_EXCUTE_TIMEOUT.value[0],
ExceptionType.TASK_EXCUTE_TIMEOUT.value[1])
sleep(3)
hb_msg = get_no_block_queue(hb_queue)
if hb_msg is not None:
command = hb_msg.get("command")
hb_value = hb_msg.get("hb_value")
if 'stop' == command:
logger.info("开始终止心跳线程, requestId:{}", request_id)
break
if hb_value is not None:
progress = hb_value
if hb_init_num % 30 == 0:
hb_init_num = 0
put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.RUNNING.value, analyse_type,
progress=progress), timeout=3, is_ex=True)
hb_init_num += 3
del hb_msg
except Exception:
logger.error("心跳线程异常:{}, requestId:{}", format_exc(), request_id)
finally:
clear_queue(hb_queue)
logger.info("心跳线程停止完成requestId:{}", request_id)

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,153 @@
# -*- coding: utf-8 -*-
import time
from traceback import format_exc
from multiprocessing import Process, Queue
from loguru import logger
from concurrency.Pull2PushStreamThread import PushSteamThread
from enums.StatusEnum import PushStreamStatus, ExecuteStatus
from util.LogUtils import init_log
from enums.ExceptionEnum import ExceptionType
from entity.FeedBack import pull_stream_feedback
from exception.CustomerException import ServiceException
from util.QueUtil import get_no_block_queue, put_queue
class PushStreamProcess(Process):
__slots__ = ('_fb_queue', 'event_queue', '_context', '_msg', '_analysisType')
def __init__(self, *args):
super().__init__()
self._fb_queue, self._context, self._msg, self._analysisType = args
self.event_queue = Queue()
def sendEvent(self, eBody):
try:
self.event_queue.put(eBody, timeout=2)
except Exception:
logger.error("添加事件到队列超时异常:{}, requestId:{}", format_exc(), self._msg["request_id"])
raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
ExceptionType.SERVICE_INNER_EXCEPTION.value[1])
def run(self):
msg, context = self._msg, self._context
requestId, videoUrls = msg["request_id"], msg["video_urls"]
base_dir, env = context['base_dir'], context['env']
fb_queue = self._fb_queue
task, videoStatus = {}, {}
ex = None
try:
init_log(base_dir, env)
if videoUrls is None or len(videoUrls) == 0:
raise ServiceException(ExceptionType.PUSH_STREAM_URL_IS_NULL.value[0],
ExceptionType.PUSH_STREAM_URL_IS_NULL.value[1])
if len(videoUrls) > 5:
logger.error("推流数量超过限制, 当前推流数量: {}, requestId:{}", len(videoUrls), requestId)
raise ServiceException(ExceptionType.PULL_STREAM_NUM_LIMIT_EXCEPTION.value[0],
ExceptionType.PULL_STREAM_NUM_LIMIT_EXCEPTION.value[1])
videoInfo = [{"id": url["id"], "status": PushStreamStatus.WAITING.value[0]} for url in videoUrls if
url.get("id")]
put_queue(fb_queue, pull_stream_feedback(requestId, ExecuteStatus.WAITING.value[0], "", "", videoInfo))
for videoUrl in videoUrls:
pushThread = PushSteamThread(videoUrl["pull_url"], videoUrl["push_url"], requestId, videoUrl["id"])
pushThread.start()
task[videoUrl["id"]] = pushThread
enable_time = time.time()
for video in videoInfo:
videoStatus[video.get("id")] = video.get("status")
count = 0
while True:
# 整个推流任务超时时间
if time.time() - enable_time > 43200:
logger.error("任务执行超时, requestId:{}", requestId)
for t in list(task.keys()):
if task[t].is_alive():
task[t].status = False
task[t].pushStreamUtil.close_push_stream_sp()
task[t].join(120)
videoStatus[t] = PushStreamStatus.TIMEOUT.value[0]
videoInfo_timeout = [{"id": k, "status": v} for k, v in videoStatus.items()]
put_queue(fb_queue, pull_stream_feedback(requestId, ExecuteStatus.TIMEOUT.value[0],
ExceptionType.TASK_EXCUTE_TIMEOUT.value[0],
ExceptionType.TASK_EXCUTE_TIMEOUT.value[1],
videoInfo_timeout))
break
# 接受停止指令
event_result = get_no_block_queue(self.event_queue)
if event_result is not None:
command = event_result.get("command")
videoIds = event_result.get("videoIds")
if "stop" == command:
# 如果videoIds是空停止所有任务
if videoIds is None or len(videoIds) == 0:
logger.info("停止所有执行的推流任务, requestId:{}", requestId)
for t in list(task.keys()):
if task[t].is_alive():
task[t].status = False
task[t].pushStreamUtil.close_push_stream_sp()
task[t].join(120)
videoStatus[t] = PushStreamStatus.SUCCESS.value[0]
videoInfo_sucess = [{"id": k, "status": v} for k, v in videoStatus.items()]
put_queue(fb_queue, pull_stream_feedback(requestId, ExecuteStatus.SUCCESS.value[0], "", "",
videoInfo_sucess))
break
else:
logger.info("停止指定的推流任务, requestId:{}", requestId)
alive_thread = 0
for t in list(task.keys()):
if task[t].is_alive():
if t in videoIds:
task[t].status = False
task[t].pushStreamUtil.close_push_stream_sp()
task[t].join(120)
videoStatus[t] = PushStreamStatus.SUCCESS.value[0]
else:
alive_thread += 1
if alive_thread == 0:
videoInfo_sucess = [{"id": k, "status": v} for k, v in videoStatus.items()]
put_queue(fb_queue, pull_stream_feedback(requestId, ExecuteStatus.SUCCESS.value[0], "",
"", videoInfo_sucess))
break
for t in list(task.keys()):
if task[t].status and not task[t].is_alive():
videoStatus[t] = PushStreamStatus.FAILED.value[0]
logger.error("检测到推流线程异常停止videoId:{}, requestId:{}", t, requestId)
if task[t].ex:
raise task[t].ex
raise Exception("检测到推流线程异常停止!")
if task[t].is_alive():
videoStatus[t] = task[t].excute_status
if count % 10 == 0:
videoInfo_hb = [{"id": k, "status": v} for k, v in videoStatus.items()]
put_queue(fb_queue, pull_stream_feedback(requestId, ExecuteStatus.RUNNING.value[0], "", "",
videoInfo_hb))
count = 0
count += 1
time.sleep(1)
except ServiceException as s:
ex = s.code, s.msg
logger.error("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, requestId)
except Exception:
ex = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1]
logger.error("服务异常: {}, requestId: {},", format_exc(), requestId)
finally:
if ex:
errorCode, errorMsg = ex
for t in list(task.keys()):
if task[t].is_alive():
task[t].status = False
task[t].pushStreamUtil.close_push_stream_sp()
task[t].join(120)
videoStatus[t] = PushStreamStatus.FAILED.value[0]
videoInfo_ex = [{"id": k, "status": v} for k, v in videoStatus.items()]
put_queue(fb_queue, pull_stream_feedback(requestId, ExecuteStatus.FAILED.value[0], errorCode, errorMsg,
videoInfo_ex))
for t in list(task.keys()):
if task[t].is_alive():
task[t].status = False
task[t].pushStreamUtil.close_push_stream_sp()
task[t].join(120)
logger.info("推流任务完成, requestId: {}", requestId)

View File

@ -0,0 +1,55 @@
# -*- coding: utf-8 -*-
from threading import Thread
import time
from traceback import format_exc
from loguru import logger
from enums.StatusEnum import PushStreamStatus
from exception.CustomerException import ServiceException
from util.PushStreamUtils import PushStreamUtil
class PushSteamThread(Thread):
__slots__ = ("pushStreamUtil", "requestId", "videoId", "status", "ex")
def __init__(self, pullUrl, pushUrl, requestId, videoId):
super().__init__()
self.pushStreamUtil = PushStreamUtil(pullUrl, pushUrl, requestId)
self.requestId = requestId
self.videoId = videoId
self.status = True
self.excute_status = PushStreamStatus.WAITING.value[0]
self.ex = None
def run(self):
logger.info("开始启动推流线程, 视频id: {}, requestId:{}", self.videoId, self.requestId)
while True:
try:
self.pushStreamUtil.start_push_stream()
self.excute_status = PushStreamStatus.RUNNING.value[0]
out, err = self.pushStreamUtil.push_stream_sp.communicate()
# 异常断流
if self.status:
logger.warning("推流异常,请检测拉流地址和推流地址是否正常!")
if self.pushStreamUtil.push_stream_sp.returncode != 0:
logger.error("推流异常:{}, 视频id: {}, requestId:{}", err.decode(), self.videoId,
self.requestId)
self.excute_status = PushStreamStatus.RETRYING.value[0]
self.pushStreamUtil.close_push_stream_sp()
time.sleep(5)
# 手动断流
if not self.status:
self.pushStreamUtil.close_push_stream_sp()
break
except ServiceException as s:
logger.error("异常: {}, 视频id: {}, requestId:{}", s.msg, self.videoId, self.requestId)
self.pushStreamUtil.close_push_stream_sp()
self.ex = s
break
except Exception as e:
logger.error("异常:{}, 视频id: {}, requestId:{}", format_exc(), self.videoId, self.requestId)
self.pushStreamUtil.close_push_stream_sp()
self.ex = e
break
logger.info("结束推流线程, 视频id: {}, requestId:{}", self.videoId, self.requestId)

View File

@ -0,0 +1,142 @@
# -*- coding: utf-8 -*-
from threading import Thread
from time import sleep, time
from traceback import format_exc
from loguru import logger
from common.YmlConstant import mqtt_yml_path
from util.RWUtils import getConfigs
from common.Constant import init_progess
from enums.AnalysisStatusEnum import AnalysisStatus
from entity.FeedBack import message_feedback
from enums.ExceptionEnum import ExceptionType
from exception.CustomerException import ServiceException
from util.QueUtil import get_no_block_queue, put_queue, clear_queue
from multiprocessing import Process, Queue
import paho.mqtt.client as mqtt
import json,os
class PullMqtt(Thread):
__slots__ = ('__fb_queue', '__mqtt_list', '__request_id', '__analyse_type', "_context")
def __init__(self, *args):
super().__init__()
self.__fb_queue, self.__mqtt_list, self.__request_id, self.__analyse_type, self._context = args
base_dir, env = self._context["base_dir"], self._context["env"]
self.__config = getConfigs(os.path.join(base_dir, mqtt_yml_path % env))
self.__broker = self.__config["broker"]
self.__port = self.__config["port"]
self.__topic = self.__config["topic"]
self.__lengthMqttList = self.__config["length"]
def put_queue(self,__queue,data):
if __queue.full():
a = __queue.get()
__queue.put( data,block=True, timeout=2 )
def on_connect(self,client,userdata,flags,rc):
client.subscribe(self.__topic)
# 当接收到MQTT消息时回调函数
def on_message(self,client, userdata, msg):
# 将消息解码为JSON格式
payload = msg.payload.decode('utf-8')
data = json.loads(payload)
#logger.info(str(data))
# 解析位姿信息
lon = data.get("lon")
lat = data.get("lat")
alt = data.get("alt")
yaw = data.get("yaw")
pitch = data.get("pitch")
roll = data.get("roll")
if len(self.__mqtt_list) == self.__lengthMqttList:
self.__mqtt_list.pop(0)
self.__mqtt_list.append(data)
# 打印无人机的位姿信息
#print(f"Longitude: {lon}, Latitude: {lat}, Altitude: {alt}, sat:{data.get('satcount')} , list length:{len(self.__mqtt_list)}")
def mqtt_connect(self):
# 创建客户端
self.client = mqtt.Client()
self.client.on_connect = self.on_connect
# 设置回调函数
self.client.on_message = self.on_message
# 连接到 Broker
self.client.connect(self.__broker, self.__port)
# 订阅主题
self.client.subscribe(self.__topic)
# 循环等待并处理网络事件
self.client.loop_forever()
def mqtt_disconnect(self):
start_time = time()
while True:
if time() - start_time > service_timeout:
logger.error("MQTT读取超时, requestId: %s,限定时间:%.1s , 已运行:%.1fs"%(request_id,service_timeout, time() - start_time))
raise ServiceException(ExceptionType.TASK_EXCUTE_TIMEOUT.value[0],
ExceptionType.TASK_EXCUTE_TIMEOUT.value[1])
client.loop_stop() # 停止循环
client.disconnect() # 断开连接
def run(self):
request_id, mqtt_list, progress = self.__request_id, self.__mqtt_list, init_progess
analyse_type, fb_queue = self.__analyse_type, self.__fb_queue
#service_timeout = int(self.__config["service"]["timeout"]) + 120
try:
logger.info("开始MQTT读取线程requestId:{}", request_id)
mqtt_init_num = 0
self.mqtt_connect()
except Exception:
logger.error("MQTT线程异常:{}, requestId:{}", format_exc(), request_id)
finally:
mqtt_list = []
logger.info("MQTT线程停止完成requestId:{}", request_id)
def start_PullMqtt(fb_queue, mqtt_list, request_id, analyse_type, context):
mqtt_thread = PullMqtt(fb_queue, mqtt_list, request_id, analyse_type, context)
mqtt_thread.setDaemon(True)
mqtt_thread.start()
return mqtt_thread
def start_PullVideo(mqtt_list):
for i in range(1000):
sleep(1)
if len(mqtt_list)>=10:
print( mqtt_list[4])
print(i,len(mqtt_list))
if __name__=="__main__":
#context = {'service':{'timeout':3600},'mqtt':{
# 'broker':"101.133.163.127",'port':1883,'topic':"test/topic","length":10}
# }
context = {
'base_dir':'/home/th/WJ/test/tuoheng_algN',
'env':'test'
}
analyse_type = '1'
request_id = '123456789'
event_queue, pull_queue, mqtt_list, image_queue, push_queue, push_ex_queue = Queue(), Queue(10), [], Queue(), Queue(), Queue()
fb_queue = Queue()
mqtt_thread = start_PullMqtt(fb_queue, mqtt_list, request_id, analyse_type, context)
start_PullVideo(mqtt_list)
print('---line117--')
#mqtt_thread.join()

View File

@ -0,0 +1,185 @@
# -*- coding: utf-8 -*-
from queue import Queue
from threading import Thread
from time import time, sleep
from traceback import format_exc
from loguru import logger
from enums.ExceptionEnum import ExceptionType
from enums.RecordingStatusEnum import RecordingStatus
from exception.CustomerException import ServiceException
from util.Cv2Utils import check_video_stream, clear_pull_p, build_video_info2, pull_read_video_stream2
from util.QueUtil import put_queue, get_no_block_queue, clear_queue, put_queue_result
class PullStreamThread(Thread):
__slots__ = ('_command', '_pull_queue', '_hb_queue', '_fb_queue', '_msg', '_context')
def __init__(self, *args):
super().__init__()
self._msg, self._context, self._pull_queue, self._hb_queue, self._fb_queue, self._frame_num = args
self._command = Queue()
def sendEvent(self, result):
put_queue(self._command, result, timeout=10, is_ex=False)
class RecordingPullStreamThread(PullStreamThread):
def run(self):
msg, context, frame_num = self._msg, self._context, self._frame_num
request_id, pull_url = msg["request_id"], msg['pull_url']
service = context["service"]
pull_stream_timeout = int(service["recording_pull_stream_timeout"])
read_stream_timeout = int(service["cv2_read_stream_timeout"])
service_timeout = int(service["timeout"])
command_queue, pull_queue, fb_queue, hb_queue = self._command, self._pull_queue, self._fb_queue, self._hb_queue
width, height, width_height_3, all_frames, w, h = None, None, None, 0, None, None
read_start_time, pull_p, ex = None, None, None
frame_list, frame_index_list = [], []
stop_ex = True
pull_stream_start_time = time()
try:
logger.info("录屏拉流线程开始启动, requestId: {}", request_id)
cv2_init_num, init_pull_num, concurrent_frame = 0, 1, 1
start_time = time()
while True:
# 检查任务是否超时
if time() - start_time > service_timeout:
logger.error("录屏拉流超时, requestId: {}", request_id)
raise ServiceException(ExceptionType.TASK_EXCUTE_TIMEOUT.value[0],
ExceptionType.TASK_EXCUTE_TIMEOUT.value[1])
# 最终停止拉流
event = get_no_block_queue(command_queue)
if event is not None:
# 当接收到停止指令,说明不会再处理视频帧了, 直接退出
if 'stop' == event.get("command"):
if len(frame_list) > 0:
put_queue(pull_queue, (4, (frame_list, frame_index_list, all_frames)), timeout=1)
logger.info("录屏拉流线程开始停止, requestId: {}", request_id)
break
# 主进程异常,停止子线程
if 'stop_ex' == event.get("command"):
logger.info("录屏异常拉开始停止拉流线程, requestId: {}", request_id)
stop_ex = False
break
# 如果是离线拉流
if pull_url.startswith('http'):
if check_video_stream(width, height):
logger.info("开始重新获取视频信息: {}次, requestId: {}", cv2_init_num, request_id)
# 当是离线地址重试3次还是拉取不到视频流关闭拉流管道返回失败信息
# 目前改为等待5分钟
# if cv2_init_num > 3:
if time() - start_time > 300:
logger.info("离线拉流重试失败, 重试次数: {}, requestId: {}", cv2_init_num, request_id)
raise ServiceException(ExceptionType.OR_VIDEO_ADDRESS_EXCEPTION.value[0],
ExceptionType.OR_VIDEO_ADDRESS_EXCEPTION.value[1])
cv2_init_num += 1
width, height, width_height_3, all_frames, w, h = build_video_info2(pull_url, request_id)
if width is not None:
put_queue(hb_queue, {"status": RecordingStatus.RECORDING_RUNNING.value[0]}, timeout=2)
else:
# if cv2_init_num < 2:
if time() - start_time < 300:
put_queue(hb_queue, {"status": RecordingStatus.RECORDING_RETRYING.value[0]}, timeout=2)
continue
# 当离线视频时, 队列满了, 等待1秒后再试
if pull_queue.full():
logger.info("pull拉流队列满了: {}, requestId: {}", pull_queue.qsize(), request_id)
sleep(1)
continue
# 如果是实时拉流
else:
if check_video_stream(width, height):
logger.info("开始重新获取视频信息: {}次, requestId: {}", cv2_init_num, request_id)
pull_stream_init_timeout = time() - pull_stream_start_time
if len(frame_list) > 0:
put_queue(pull_queue, (4, (frame_list, frame_index_list, all_frames)), timeout=1)
frame_list, frame_index_list = [], []
if pull_stream_init_timeout > pull_stream_timeout:
logger.error("开始拉流超时, 超时时间:{}, requestId:{}", pull_stream_init_timeout, request_id)
raise ServiceException(ExceptionType.PULLSTREAM_TIMEOUT_EXCEPTION.value[0],
ExceptionType.PULLSTREAM_TIMEOUT_EXCEPTION.value[1])
cv2_init_num += 1
width, height, width_height_3, all_frames, w, h = build_video_info2(pull_url, request_id)
if width is not None:
put_queue(hb_queue, {"status": RecordingStatus.RECORDING_RUNNING.value[0]}, timeout=1)
else:
if cv2_init_num < 3:
put_queue(hb_queue, {"status": RecordingStatus.RECORDING_RETRYING.value[0]}, timeout=1)
sleep(1)
continue
pull_stream_start_time = time()
cv2_init_num = 1
frame, pull_p, width, height = pull_read_video_stream2(pull_p, pull_url, width, height,
width_height_3, w, h, request_id)
if frame is None:
if pull_url.startswith('http'):
clear_pull_p(pull_p, request_id)
logger.info("总帧数: {}, 当前帧数: {}, requestId: {}", all_frames, concurrent_frame, request_id)
if len(frame_list) > 0:
put_queue(pull_queue, (4, (frame_list, frame_index_list, all_frames)), timeout=1)
if concurrent_frame < all_frames - 100:
logger.info("离线拉流异常结束requestId: {}", request_id)
raise ServiceException(ExceptionType.READSTREAM_TIMEOUT_EXCEPTION.value[0],
ExceptionType.READSTREAM_TIMEOUT_EXCEPTION.value[1])
logger.info("离线拉流线程结束, requestId: {}", request_id)
break
else:
logger.info("获取帧为空, 开始重试: {}次, requestId: {}", init_pull_num, request_id)
if len(frame_list) > 0:
put_queue(pull_queue, (4, (frame_list, frame_index_list, all_frames)), timeout=1)
frame_list, frame_index_list = [], []
if read_start_time is None:
read_start_time = time()
pull_stream_read_timeout = time() - read_start_time
if pull_stream_read_timeout > read_stream_timeout:
logger.info("拉流过程中断了重试超时, 超时时间: {}, requestId: {}", pull_stream_read_timeout,
request_id)
raise ServiceException(ExceptionType.READSTREAM_TIMEOUT_EXCEPTION.value[0],
ExceptionType.READSTREAM_TIMEOUT_EXCEPTION.value[1])
init_pull_num += 1
continue
init_pull_num = 1
read_start_time = None
if pull_queue.full():
sleep(1)
logger.info("pull拉流队列满了:{}, requestId: {}", pull_queue.qsize(), request_id)
continue
frame_list.append(frame)
frame_index_list.append(concurrent_frame)
if len(frame_list) >= frame_num:
put_queue(pull_queue, (4, (frame_list, frame_index_list, all_frames)), timeout=1)
frame_list, frame_index_list = [], []
concurrent_frame += 1
del frame
except ServiceException as s:
ex = s.code, s.msg
except Exception:
logger.exception("实时拉流异常: {}, requestId:{}", format_exc(), request_id)
ex = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1]
finally:
clear_pull_p(pull_p, request_id)
if stop_ex:
if ex:
error_code, error_msg = ex
result = put_queue_result(pull_queue, (1, error_code, error_msg), timeout=3)
else:
result = put_queue_result(pull_queue, (2,), timeout=3)
if result:
# 3分钟超时时间
cr_time = time()
while time() - cr_time < 180:
event = get_no_block_queue(command_queue)
if event is not None:
# 当接收到停止指令,说明不会再处理视频帧了, 直接退出
if 'stop' == event.get("command"):
logger.info("录屏拉流线程开始停止, requestId: {}", request_id)
break
sleep(1)
clear_queue(command_queue)
clear_queue(pull_queue)
clear_queue(hb_queue)
del frame_list, frame_index_list
logger.info("录屏拉流线程结束, requestId: {}", request_id)

View File

@ -0,0 +1,352 @@
# -*- coding: utf-8 -*-
import os
from multiprocessing import Process, Queue
from os import getpid
from time import time, sleep
from traceback import format_exc
import psutil
from loguru import logger
from concurrency.PullMqttThread import PullMqtt
from util.LogUtils import init_log
from concurrency.FileUploadThread import ImageFileUpload
from entity.FeedBack import message_feedback
from enums.AnalysisStatusEnum import AnalysisStatus
from enums.ExceptionEnum import ExceptionType
from exception.CustomerException import ServiceException
from util.Cv2Utils import check_video_stream, build_video_info, pull_read_video_stream, clear_pull_p
from util.QueUtil import get_no_block_queue, put_queue, clear_queue, put_queue_result
class PullVideoStreamProcess(Process):
__slots__ = ("_command_queue", "_msg", "_context", "_fb_queue", "_pull_queue", "_image_queue", "_analyse_type",
"_frame_num","_mqtt_list")
def __init__(self, *args):
super().__init__()
# 自带参数
self._command_queue = Queue()
# 传参
self._msg, self._context, self._fb_queue, self._pull_queue, self._image_queue, self._analyse_type, \
self._frame_num = args
self._mqtt_list = []
def sendCommand(self, result):
put_queue(self._command_queue, result, timeout=2, is_ex=True)
@staticmethod
def start_File_upload(fb_queue, context, msg, image_queue, analyse_type,mqtt_list):
image_thread = ImageFileUpload(fb_queue, context, msg, image_queue, analyse_type,mqtt_list)
image_thread.setDaemon(True)
image_thread.start()
return image_thread
@staticmethod
def start_PullMqtt(fb_queue, mqtt_list, request_id, analyse_type, context):
mqtt_thread = PullMqtt(fb_queue, mqtt_list, request_id, analyse_type, context)
mqtt_thread.setDaemon(True)
mqtt_thread.start()
return mqtt_thread
@staticmethod
def check(start_time, service_timeout, request_id, image_thread):
if time() - start_time > service_timeout:
logger.error("拉流进程运行超时, requestId: {}", request_id)
raise ServiceException(ExceptionType.TASK_EXCUTE_TIMEOUT.value[0],
ExceptionType.TASK_EXCUTE_TIMEOUT.value[1])
# 检测图片上传线程是否正常运行
if image_thread and not image_thread.is_alive():
logger.error("未检测到图片上传线程活动,图片上传线程可能出现异常, requestId:{}", request_id)
raise Exception("未检测到图片上传线程活动,图片上传线程可能出现异常!")
class OnlinePullVideoStreamProcess(PullVideoStreamProcess):
__slots__ = ()
def run(self):
# 避免循环调用性能影响, 优先赋值
context, msg, analyse_type, frame_num = self._context, self._msg, self._analyse_type, self._frame_num
base_dir, env, service = context['base_dir'], context['env'], context["service"]
request_id, pull_url = msg["request_id"], msg["pull_url"]
pull_stream_timeout, read_stream_timeout, service_timeout = int(service["cv2_pull_stream_timeout"]), \
int(service["cv2_read_stream_timeout"]), int(service["timeout"]) + 120
command_queue, pull_queue, image_queue, fb_queue ,mqtt_list= self._command_queue, self._pull_queue, self._image_queue, \
self._fb_queue,self._mqtt_list
image_thread, ex = None, None
width, height, width_height_3, all_frames, w_2, h_2, pull_p = None, None, None, 0, None, None, None
frame_list, frame_index_list = [], []
ex_status = True
try:
# 初始化日志
init_log(base_dir, env)
logger.info("开启启动实时视频拉流进程, requestId:{},pid:{},ppid:{}", request_id,os.getpid(),os.getppid())
#开启mqtt
if service["mqtt_flag"]==1:
mqtt_thread = self.start_PullMqtt(fb_queue, mqtt_list, request_id, analyse_type, context)
# 开启图片上传线程
image_thread = self.start_File_upload(fb_queue, context, msg, image_queue, analyse_type,mqtt_list)
cv2_init_num, init_pull_num, concurrent_frame = 0, 1, 1
start_time, pull_stream_start_time, read_start_time, full_timeout = time(), None, None, None
while True:
# 检测任务执行是否超时、图片上传线程是否正常
self.check(start_time, service_timeout, request_id, image_thread)
command_msg = get_no_block_queue(command_queue)
if command_msg is not None:
if 'stop' == command_msg.get("command"):
logger.info("开始停止实时拉流进程, requestId:{}", request_id)
break
if 'stop_ex' == command_msg.get("command"):
logger.info("开始停止实时拉流进程, requestId:{}", request_id)
ex_status = False
break
if command_msg.get("command") in ['algStart' , 'algStop' ]:
logger.info("拉流进程中requestId:{},向图片上传进程发送命令:{}", request_id,command_msg.get("command"))
put_queue(image_queue, (2, command_msg.get("command") ), timeout=1)
# 检测视频信息是否存在或拉流对象是否存在
if check_video_stream(width, height):
if len(frame_list) > 0:
put_queue(pull_queue, (4, (frame_list, frame_index_list, all_frames)), timeout=1)
frame_list, frame_index_list = [], []
logger.info("开始重新获取视频信息: {}次, requestId: {}", cv2_init_num, request_id)
if pull_stream_start_time is None:
pull_stream_start_time = time()
pull_stream_init_timeout = time() - pull_stream_start_time
if pull_stream_init_timeout > pull_stream_timeout:
logger.info("开始拉流超时, 超时时间:{}, requestId:{}", pull_stream_init_timeout, request_id)
# 如果超时了, 将异常信息发送给主进程,如果队列满了,抛出异常
raise ServiceException(ExceptionType.PULLSTREAM_TIMEOUT_EXCEPTION.value[0],
ExceptionType.PULLSTREAM_TIMEOUT_EXCEPTION.value[1])
cv2_init_num += 1
width, height, width_height_3, all_frames, w_2, h_2 = build_video_info(pull_url, request_id)
if width is None:
sleep(1)
continue
pull_stream_start_time, cv2_init_num = None, 1
frame, pull_p, width, height = pull_read_video_stream(pull_p, pull_url, width, height, width_height_3,
w_2, h_2, request_id)
if pull_queue.full():
logger.info("pull拉流队列满了:{}, requestId: {}", os.getppid(), request_id)
if full_timeout is None:
full_timeout = time()
if time() - full_timeout > 180:
logger.error("拉流队列阻塞超时, 请检查父进程是否正常requestId: {}", request_id)
raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
ExceptionType.SERVICE_INNER_EXCEPTION.value[1])
if psutil.Process(getpid()).ppid() == 1:
clear_pull_p(pull_p, request_id)
ex_status = False
for q in [command_queue, pull_queue, image_queue]:
clear_queue(q)
if image_thread and image_thread.is_alive():
put_queue(image_queue, (2, "stop"), timeout=1)
image_thread.join(120)
logger.info("检测到父进程异常停止, 请检测服务器资源是否负载过高, requestId: {}", request_id)
put_queue(self._fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value,
self._analyse_type,
ExceptionType.NO_RESOURCES.value[0],
ExceptionType.NO_RESOURCES.value[1]), timeout=2)
break
del frame
continue
full_timeout = None
if frame is None:
clear_pull_p(pull_p, request_id)
if len(frame_list) > 0:
put_queue(pull_queue, (4, (frame_list, frame_index_list, all_frames)), timeout=1)
frame_list, frame_index_list = [], []
logger.info("获取帧为空, 开始重试: {}次, requestId: {}", init_pull_num, request_id)
if read_start_time is None:
read_start_time = time()
pull_stream_read_timeout = time() - read_start_time
if pull_stream_read_timeout > read_stream_timeout:
logger.info("拉流过程中断了重试超时, 超时时间: {}, requestId: {}", pull_stream_read_timeout,
request_id)
raise ServiceException(ExceptionType.READSTREAM_TIMEOUT_EXCEPTION.value[0],
ExceptionType.READSTREAM_TIMEOUT_EXCEPTION.value[1])
init_pull_num += 1
sleep(1)
continue
init_pull_num, read_start_time = 1, None
frame_list.append(frame)
frame_index_list.append(concurrent_frame)
if len(frame_list) >= frame_num:
put_queue(pull_queue, (4, (frame_list, frame_index_list, all_frames)), timeout=1, is_ex=True)
frame_list, frame_index_list = [], []
concurrent_frame += 1
del frame
except ServiceException as s:
logger.error("实时拉流异常: {}, 队列大小:{}, requestId:{}", s.msg, pull_queue.qsize(), request_id)
ex = s.code, s.msg
except Exception:
logger.error("实时拉流异常: {}, 队列大小:{}, requestId:{}", format_exc(), pull_queue.qsize(), request_id)
ex = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1]
finally:
clear_pull_p(pull_p, request_id)
del frame_list, frame_index_list
if ex_status:
if ex:
code, msg = ex
r = put_queue_result(pull_queue, (1, code, msg), timeout=10)
else:
r = put_queue_result(pull_queue, (2,), timeout=10)
if r:
c_time = time()
while time() - c_time < 60:
command_msg = get_no_block_queue(command_queue)
if command_msg is not None:
if 'stop' == command_msg.get("command"):
logger.info("开始停止实时拉流进程, requestId:{}", request_id)
if image_thread and image_thread.is_alive():
put_queue(image_queue, (2, "stop"), timeout=1)
logger.info("停止图片上传线程, requestId:{}", request_id)
image_thread.join(120)
logger.info("停止图片上传线程结束, requestId:{}", request_id)
break
for q in [command_queue, pull_queue, image_queue]:
clear_queue(q)
if image_thread and image_thread.is_alive():
put_queue(image_queue, (2, "stop"), timeout=1)
logger.info("停止图片上传线程, requestId:{}", request_id)
image_thread.join(120)
logger.info("停止图片上传线程结束, requestId:{}", request_id)
logger.info("实时拉流线程结束, 图片队列: {}, 拉流队列: {}, 图片进程的状态: {} requestId: {}",
image_queue.qsize(), pull_queue.qsize(), image_thread.is_alive(), request_id)
class OfflinePullVideoStreamProcess(PullVideoStreamProcess):
__slots__ = ()
def run(self):
msg, context, frame_num, analyse_type = self._msg, self._context, self._frame_num, self._analyse_type
request_id, base_dir, env, pull_url = msg["request_id"], context['base_dir'], context['env'], msg["pull_url"]
ex, service_timeout, full_timeout = None, int(context["service"]["timeout"]) + 120, None
command_queue, pull_queue, image_queue, fb_queue = self._command_queue, self._pull_queue, self._image_queue, \
self._fb_queue
image_thread, pull_p = None, None
width, height, width_height_3, all_frames, w_2, h_2 = None, None, None, 0, None, None
frame_list, frame_index_list = [], []
ex_status = True
try:
# 初始化日志
init_log(base_dir, env)
logger.info("开启离线视频拉流进程, requestId:{}", request_id)
# 开启图片上传线程
image_thread = self.start_File_upload(fb_queue, context, msg, image_queue, analyse_type,[])
# 初始化拉流工具类
cv2_init_num, concurrent_frame = 0, 1
start_time = time()
while True:
# 检测任务执行是否超时、图片上传线程是否正常
self.check(start_time, service_timeout, request_id, image_thread)
command_msg = get_no_block_queue(command_queue)
if command_msg is not None:
if 'stop' == command_msg.get("command"):
logger.info("开始停止离线拉流进程, requestId:{}", request_id)
break
if 'stop_ex' == command_msg.get("command"):
logger.info("开始停止离线拉流进程, requestId:{}", request_id)
ex_status = False
break
if command_msg.get("command") in ['algStart' , 'algStop' ]:
logger.info("拉流进程中requestId:{},向图片上传进程发送命令:{}", request_id,command_msg.get("command"))
put_queue(image_queue, (2, command_msg.get("command") ), timeout=1)
# 检测视频信息是否存在或拉流对象是否存在
if check_video_stream(width, height):
logger.info("开始重新获取视频信息: {}次, requestId: {}", cv2_init_num, request_id)
if cv2_init_num > 3:
logger.info("离线拉流重试失败, 重试次数: {}, requestId: {}", cv2_init_num, request_id)
raise ServiceException(ExceptionType.OR_VIDEO_ADDRESS_EXCEPTION.value[0],
ExceptionType.OR_VIDEO_ADDRESS_EXCEPTION.value[1])
cv2_init_num += 1
sleep(1)
width, height, width_height_3, all_frames, w_2, h_2 = build_video_info(pull_url, request_id)
continue
if pull_queue.full():
logger.info("pull拉流队列满了:{}, requestId: {}", os.getppid(), request_id)
if full_timeout is None:
full_timeout = time()
if time() - full_timeout > 180:
logger.error("pull队列阻塞超时请检测父进程是否正常requestId: {}", request_id)
raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
ExceptionType.SERVICE_INNER_EXCEPTION.value[1])
if psutil.Process(getpid()).ppid() == 1:
clear_pull_p(pull_p, request_id)
ex_status = False
for q in [command_queue, pull_queue, image_queue]:
clear_queue(q)
put_queue(image_queue, (2, "stop"), timeout=1)
image_thread.join(120)
logger.info("检测到父进程异常停止, 请检测服务器资源是否负载过高, requestId: {}", request_id)
put_queue(self._fb_queue, message_feedback(request_id,
AnalysisStatus.FAILED.value,
self._analyse_type,
ExceptionType.NO_RESOURCES.value[0],
ExceptionType.NO_RESOURCES.value[1]), timeout=2)
break
continue
full_timeout = None
frame, pull_p, width, height = pull_read_video_stream(pull_p, pull_url, width, height,
width_height_3, w_2, h_2, request_id)
if frame is None:
logger.info("总帧数: {}, 当前帧数: {}, requestId: {}", all_frames, concurrent_frame, request_id)
clear_pull_p(pull_p, request_id)
if len(frame_list) > 0:
put_queue(pull_queue, (4, (frame_list, frame_index_list, all_frames)), timeout=1)
# 允许100帧的误差
if concurrent_frame < all_frames - 100:
logger.info("离线拉流异常结束requestId: {}", request_id)
raise ServiceException(ExceptionType.READSTREAM_TIMEOUT_EXCEPTION.value[0],
ExceptionType.READSTREAM_TIMEOUT_EXCEPTION.value[1])
logger.info("离线拉流线程结束, requestId: {}", request_id)
break
frame_list.append(frame)
frame_index_list.append(concurrent_frame)
if len(frame_list) >= frame_num:
put_queue(pull_queue, (4, (frame_list, frame_index_list, all_frames)), timeout=1, is_ex=True)
frame_list, frame_index_list = [], []
concurrent_frame += 1
del frame
except ServiceException as s:
logger.error("离线拉流异常: {}, 队列大小:{}, requestId:{}", s.msg, pull_queue.qsize(), request_id)
ex = s.code, s.msg
except Exception:
logger.error("离线拉流异常: {}, requestId:{}", format_exc(), request_id)
ex = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1]
finally:
clear_pull_p(pull_p, request_id)
del frame_list, frame_index_list
if ex_status:
if ex:
code, msg = ex
r = put_queue_result(pull_queue, (1, code, msg), timeout=10)
else:
r = put_queue_result(pull_queue, (2,), timeout=10)
if r:
c_time = time()
while time() - c_time < 180:
command_msg = get_no_block_queue(command_queue)
if command_msg is not None:
if 'stop' == command_msg.get("command"):
logger.info("开始停止实时拉流进程, requestId:{}", request_id)
if image_thread and image_thread.is_alive():
put_queue(image_queue, (2, "stop"), timeout=1)
logger.info("停止图片上传线程, requestId:{}", request_id)
image_thread.join(120)
logger.info("停止图片上传线程结束, requestId:{}", request_id)
break
for q in [command_queue, pull_queue, image_queue]:
clear_queue(q)
if image_thread and image_thread.is_alive():
put_queue(image_queue, (2, "stop"), timeout=1)
logger.info("停止图片上传线程, requestId:{}", request_id)
image_thread.join(120)
logger.info("停止图片上传线程结束, requestId:{}", request_id)
logger.info("离线拉流线程结束, 图片队列: {}, 拉流队列: {}, 图片进程的状态: {} requestId: {}",
image_queue.qsize(), pull_queue.qsize(), image_thread.is_alive(), request_id)

View File

@ -0,0 +1,349 @@
# -*- coding: utf-8 -*-
import os
from multiprocessing import Process, Queue
from os import getpid
from time import time, sleep
from traceback import format_exc
import psutil
from loguru import logger
from util.LogUtils import init_log
from concurrency.FileUploadThread import ImageFileUpload
from entity.FeedBack import message_feedback
from enums.AnalysisStatusEnum import AnalysisStatus
from enums.ExceptionEnum import ExceptionType
from exception.CustomerException import ServiceException
from util.Cv2Utils import check_video_stream, build_video_info, pull_read_video_stream, clear_pull_p
from util.QueUtil import get_no_block_queue, put_queue, clear_queue, put_queue_result
class PullVideoStreamProcess2(Process):
__slots__ = ("_command_queue", "_msg", "_context", "_fb_queue", "_pull_queue", "_image_queue", "_analyse_type",
"_frame_num")
def __init__(self, *args):
super().__init__()
# 自带参数
self._command_queue = Queue()
# 传参
self._msg, self._context, self._fb_queue, self._pull_queue, self._image_queue, self._analyse_type, \
self._frame_num = args
def sendCommand(self, result):
try:
self._command_queue.put(result, timeout=10)
except Exception:
logger.error("添加队列超时异常:{}, requestId:{}", format_exc(), self._msg.get("request_id"))
raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
ExceptionType.SERVICE_INNER_EXCEPTION.value[1])
@staticmethod
def start_File_upload(*args):
fb_queue, context, msg, image_queue, analyse_type = args
image_thread = ImageFileUpload(fb_queue, context, msg, image_queue, analyse_type)
image_thread.setDaemon(True)
image_thread.start()
return image_thread
@staticmethod
def check(start_time, service_timeout, request_id, image_thread):
if time() - start_time > service_timeout:
logger.error("分析超时, requestId: {}", request_id)
raise ServiceException(ExceptionType.ANALYSE_TIMEOUT_EXCEPTION.value[0],
ExceptionType.ANALYSE_TIMEOUT_EXCEPTION.value[1])
# 检测图片上传线程是否正常运行
if image_thread is not None and not image_thread.is_alive():
logger.error("未检测到图片上传线程活动,图片上传线程可能出现异常, requestId:{}", request_id)
raise Exception("未检测到图片上传线程活动,图片上传线程可能出现异常!")
class OnlinePullVideoStreamProcess2(PullVideoStreamProcess2):
__slots__ = ()
def run(self):
# 避免循环调用性能影响, 优先赋值
context, msg, analyse_type = self._context, self._msg, self._analyse_type
request_id, base_dir, env = msg["request_id"], context['base_dir'], context['env']
pull_url, frame_num = msg["pull_url"], self._frame_num
pull_stream_timeout = int(context["service"]["cv2_pull_stream_timeout"])
read_stream_timeout = int(context["service"]["cv2_read_stream_timeout"])
service_timeout = int(context["service"]["timeout"])
command_queue, pull_queue, image_queue = self._command_queue, self._pull_queue, self._image_queue
fb_queue = self._fb_queue
image_thread, pull_p = None, None
width, height, width_height_3, all_frames, w_2, h_2 = None, None, None, 0, None, None
frame_list, frame_index_list = [], []
ex = None
ex_status = True
full_timeout = None
try:
# 初始化日志
init_log(base_dir, env)
logger.info("开启实时视频拉流进程, requestId:{}", request_id)
# 开启图片上传线程
image_thread = self.start_File_upload(fb_queue, context, msg, image_queue, analyse_type)
# 初始化拉流工具类
cv2_init_num, init_pull_num, concurrent_frame = 0, 1, 1
start_time, pull_start_time, read_start_time = time(), None, None
while True:
# 检测任务执行是否超时、图片上传线程是否正常
self.check(start_time, service_timeout, request_id, image_thread)
command_msg = get_no_block_queue(command_queue)
if command_msg is not None:
if 'stop' == command_msg.get("command"):
logger.info("开始停止实时拉流进程, requestId:{}", request_id)
break
if 'stop_ex' == command_msg.get("command"):
logger.info("开始停止实时拉流进程, requestId:{}", request_id)
ex_status = False
break
# 检测视频信息是否存在或拉流对象是否存在
if check_video_stream(width, height):
if len(frame_list) > 0:
put_queue(pull_queue, (4, (frame_list, frame_index_list, all_frames)), timeout=1)
frame_list, frame_index_list = [], []
logger.info("开始重新获取视频信息: {}次, requestId: {}", cv2_init_num, request_id)
if pull_start_time is None:
pull_start_time = time()
pull_stream_init_timeout = time() - pull_start_time
if pull_stream_init_timeout > pull_stream_timeout:
logger.info("开始拉流超时, 超时时间:{}, requestId:{}", pull_stream_init_timeout, request_id)
raise ServiceException(ExceptionType.PULLSTREAM_TIMEOUT_EXCEPTION.value[0],
ExceptionType.PULLSTREAM_TIMEOUT_EXCEPTION.value[1])
cv2_init_num += 1
width, height, width_height_3, all_frames, w_2, h_2 = build_video_info(pull_url, request_id)
if width is None:
sleep(1)
continue
pull_start_time, cv2_init_num = None, 1
frame, pull_p, width, height = pull_read_video_stream(pull_p, pull_url, width, height, width_height_3,
w_2, h_2, request_id)
if frame is None:
if len(frame_list) > 0:
put_queue(pull_queue, (4, (frame_list, frame_index_list, all_frames)), timeout=1)
frame_list, frame_index_list = [], []
logger.info("获取帧为空, 开始重试: {}次, requestId: {}", init_pull_num, request_id)
if read_start_time is None:
read_start_time = time()
pull_stream_read_timeout = time() - read_start_time
if pull_stream_read_timeout > read_stream_timeout:
logger.info("拉流过程中断了重试超时, 超时时间: {}, requestId: {}", pull_stream_read_timeout,
request_id)
raise ServiceException(ExceptionType.READSTREAM_TIMEOUT_EXCEPTION.value[0],
ExceptionType.READSTREAM_TIMEOUT_EXCEPTION.value[1])
init_pull_num += 1
continue
init_pull_num, read_start_time = 1, None
if pull_queue.full():
logger.info("pull拉流队列满了:{}, requestId: {}", os.getppid(), request_id)
if full_timeout is None:
full_timeout = time()
if time() - full_timeout > 180:
logger.error("拉流队列阻塞异常, requestId: {}", request_id)
raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
ExceptionType.SERVICE_INNER_EXCEPTION.value[1])
if psutil.Process(getpid()).ppid() == 1:
clear_pull_p(pull_p, request_id)
ex_status = False
for q in [command_queue, pull_queue, image_queue]:
clear_queue(q)
if image_thread and image_thread.is_alive():
put_queue(image_queue, (2, "stop"), timeout=1)
image_thread.join(120)
logger.info("检测到父进程异常停止, 请检测服务器资源是否负载过高, requestId: {}", request_id)
put_queue(self._fb_queue, message_feedback(request_id,
AnalysisStatus.FAILED.value,
self._analyse_type,
ExceptionType.NO_RESOURCES.value[0],
ExceptionType.NO_RESOURCES.value[1]))
break
del frame
continue
full_timeout = None
frame_list.append(frame)
frame_index_list.append(concurrent_frame)
if len(frame_list) >= frame_num:
put_queue(pull_queue, (4, (frame_list, frame_index_list, all_frames)), timeout=1, is_ex=True)
frame_list, frame_index_list = [], []
concurrent_frame += 1
del frame
except ServiceException as s:
logger.error("实时拉流异常: {}, 队列大小:{}, requestId:{}", s.msg, pull_queue.qsize(), request_id)
ex = s.code, s.msg
except Exception:
logger.error("实时拉流异常: {}, 队列大小:{}, requestId:{}", format_exc(), pull_queue.qsize(), request_id)
ex = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1]
finally:
clear_pull_p(pull_p, request_id)
del frame_list, frame_index_list
if ex_status:
if ex:
code, msg = ex
r = put_queue_result(pull_queue, (1, code, msg), timeout=10)
else:
r = put_queue_result(pull_queue, (2,), timeout=10)
if r:
c_time = time()
while time() - c_time < 180:
command_msg = get_no_block_queue(command_queue)
if command_msg is not None:
if 'stop' == command_msg.get("command"):
logger.info("开始停止实时拉流进程, requestId:{}", request_id)
if image_thread and image_thread.is_alive():
put_queue(image_queue, (2, "stop"), timeout=1)
logger.info("停止图片上传线程, requestId:{}", request_id)
image_thread.join(120)
logger.info("停止图片上传线程结束, requestId:{}", request_id)
break
for q in [command_queue, pull_queue, image_queue]:
clear_queue(q)
if image_thread and image_thread.is_alive():
put_queue(image_queue, (2, "stop"), timeout=1)
logger.info("停止图片上传线程, requestId:{}", request_id)
image_thread.join(120)
logger.info("停止图片上传线程结束, requestId:{}", request_id)
logger.info("实时拉流线程结束, 图片队列: {}, 拉流队列: {}, 图片进程的状态: {} requestId: {}",
image_queue.qsize(), pull_queue.qsize(), image_thread.is_alive(), request_id)
class OfflinePullVideoStreamProcess2(PullVideoStreamProcess2):
__slots__ = ()
def run(self):
msg, context, frame_num, analyse_type = self._msg, self._context, self._frame_num, self._analyse_type
request_id, base_dir, env, pull_url = msg["request_id"], context['base_dir'], context['env'], msg["pull_url"]
ex, service_timeout = None, int(context["service"]["timeout"])
command_queue, pull_queue, image_queue, fb_queue = self._command_queue, self._pull_queue, self._image_queue, \
self._fb_queue
image_thread, pull_p = None, None
width, height, width_height_3, all_frames, w_2, h_2 = None, None, None, 0, None, None
frame_list, frame_index_list = [], []
ex_status = True
full_timeout = None
try:
# 初始化日志
init_log(base_dir, env)
logger.info("开启离线视频拉流进程, requestId:{}", request_id)
# 开启图片上传线程
image_thread = self.start_File_upload(fb_queue, context, msg, image_queue, analyse_type)
# 初始化拉流工具类
cv2_init_num = 0
concurrent_frame = 1
start_time = time()
while True:
# 检测任务执行是否超时、图片上传线程是否正常
self.check(start_time, service_timeout, request_id, image_thread)
command_msg = get_no_block_queue(command_queue)
if command_msg is not None:
if 'stop' == command_msg.get("command"):
logger.info("开始停止离线拉流进程, requestId:{}", request_id)
break
if 'stop_ex' == command_msg.get("command"):
logger.info("开始停止离线拉流进程, requestId:{}", request_id)
ex_status = False
break
# 检测视频信息是否存在或拉流对象是否存在
if check_video_stream(width, height):
if len(frame_list) > 0:
put_queue(pull_queue, (4, (frame_list, frame_index_list, all_frames)), timeout=1)
frame_list, frame_index_list = [], []
logger.info("开始重新获取视频信息: {}次, requestId: {}", cv2_init_num, request_id)
if cv2_init_num > 3:
clear_pull_p(pull_p, request_id)
logger.info("离线拉流重试失败, 重试次数: {}, requestId: {}", cv2_init_num, request_id)
raise ServiceException(ExceptionType.OR_VIDEO_ADDRESS_EXCEPTION.value[0],
ExceptionType.OR_VIDEO_ADDRESS_EXCEPTION.value[1])
cv2_init_num += 1
sleep(1)
width, height, width_height_3, all_frames, w_2, h_2 = build_video_info(pull_url, request_id)
continue
if pull_queue.full():
logger.info("pull拉流队列满了:{}, requestId: {}", os.getppid(), request_id)
if full_timeout is None:
full_timeout = time()
if time() - full_timeout > 300:
logger.error("拉流队列阻塞超时, 请检查父进程是否正常requestId: {}", request_id)
raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
ExceptionType.SERVICE_INNER_EXCEPTION.value[1])
if psutil.Process(getpid()).ppid() == 1:
clear_pull_p(pull_p, request_id)
ex_status = False
for q in [command_queue, pull_queue, image_queue]:
clear_queue(q)
if image_thread and image_thread.is_alive():
put_queue(image_queue, (2, "stop"), timeout=1)
image_thread.join(120)
logger.info("检测到父进程异常停止, 请检测服务器资源是否负载过高, requestId: {}", request_id)
put_queue(self._fb_queue, message_feedback(request_id,
AnalysisStatus.FAILED.value,
self._analyse_type,
ExceptionType.NO_RESOURCES.value[0],
ExceptionType.NO_RESOURCES.value[1]))
break
continue
full_timeout = None
frame, pull_p, width, height = pull_read_video_stream(pull_p, pull_url, width, height, width_height_3,
w_2, h_2, request_id)
if frame is None:
logger.info("总帧数: {}, 当前帧数: {}, requestId: {}", all_frames, concurrent_frame, request_id)
clear_pull_p(pull_p, request_id)
if len(frame_list) > 0:
put_queue(pull_queue, (4, (frame_list, frame_index_list, all_frames)), timeout=2, is_ex=False)
frame_list, frame_index_list = [], []
# 允许100帧的误差
if concurrent_frame < all_frames - 100:
logger.info("离线拉流异常结束requestId: {}", request_id)
raise ServiceException(ExceptionType.READSTREAM_TIMEOUT_EXCEPTION.value[0],
ExceptionType.READSTREAM_TIMEOUT_EXCEPTION.value[1])
logger.info("离线拉流线程结束, requestId: {}", request_id)
break
frame_list.append(frame)
frame_index_list.append(concurrent_frame)
if len(frame_list) >= frame_num:
put_queue(pull_queue, (4, (frame_list, frame_index_list, all_frames)), timeout=1, is_ex=True)
frame_list, frame_index_list = [], []
concurrent_frame += 1
del frame
except ServiceException as s:
logger.error("实时拉流异常: {}, 队列大小:{}, requestId:{}", s.msg, pull_queue.qsize(), request_id)
ex = s.code, s.msg
except Exception:
logger.error("实时拉流异常: {}, requestId:{}", format_exc(), request_id)
ex = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1]
finally:
clear_pull_p(pull_p, request_id)
del frame_list, frame_index_list
if ex_status:
if ex:
code, msg = ex
r = put_queue_result(pull_queue, (1, code, msg), timeout=10)
else:
r = put_queue_result(pull_queue, (2,), timeout=10)
if r:
c_time = time()
while time() - c_time < 180:
command_msg = get_no_block_queue(command_queue)
if command_msg is not None:
if 'stop' == command_msg.get("command"):
logger.info("开始停止离线拉流进程, requestId:{}", request_id)
if image_thread and image_thread.is_alive():
put_queue(image_queue, (2, "stop"), timeout=1)
logger.info("停止图片上传线程, requestId:{}", request_id)
image_thread.join(120)
logger.info("停止图片上传线程结束, requestId:{}", request_id)
break
for q in [command_queue, pull_queue, image_queue]:
clear_queue(q)
if image_thread and image_thread.is_alive():
put_queue(image_queue, (2, "stop"), timeout=1)
logger.info("停止图片上传线程, requestId:{}", request_id)
image_thread.join(120)
logger.info("停止图片上传线程结束, requestId:{}", request_id)
logger.info("离线拉流线程结束, 图片队列: {}, 拉流队列: {}, 图片进程的状态: {} requestId: {}",
image_queue.qsize(), pull_queue.qsize(), image_thread.is_alive(), request_id)

View File

@ -0,0 +1,181 @@
# -*- coding: utf-8 -*-
from concurrent.futures import ThreadPoolExecutor
from os.path import join
from threading import Thread
from traceback import format_exc
import cv2
import numpy as np
from loguru import logger
from util.Cv2Utils import write_or_video, write_ai_video, push_video_stream, close_all_p, video_conjuncing
from util.ImageUtils import url2Array, add_water_pic
from util.PlotsUtils import draw_painting_joint
from util.QueUtil import put_queue
class OnPushStreamThread(Thread):
__slots__ = ('_msg', '_push_queue', '_context', 'ex', '_logo', '_image_queue')
def __init__(self, *args):
super().__init__()
# 传参
self._msg, self._push_queue, self._image_queue, self._context = args
# 自带参数
self.ex = None
self._logo = None
if self._context["video"]["video_add_water"]:
self._logo = self._msg.get("logo_url")
if self._logo:
self._logo = url2Array(self._logo, enable_ex=False)
if not self._logo:
self._logo = cv2.imread(join(self._context['base_dir'], "image/logo.png"), -1)
def run(self):
request_id, push_queue, image_queue = self._msg.get("request_id"), self._push_queue, self._image_queue
orFilePath, aiFilePath, logo = self._context.get("orFilePath"), self._context.get("aiFilePath"), self._logo
or_video_file, ai_video_file, push_p = None, None, None
push_url = self._msg.get("push_url")
try:
logger.info("开始启动推流线程requestId:{}", request_id)
with ThreadPoolExecutor(max_workers=2) as t:
p_push_status, or_write_status, ai_write_status = [0, 0], [0, 0], [0, 0]
while True:
push_parm = push_queue.get()
if push_parm is not None:
# [(1, 原视频帧, 分析视频帧)]
# # [视频帧、当前帧数、 总帧数、 [(问题数组、code、allowedList、label_arraylist、rainbows)]]
# res = (1, (pull_frame[1], pull_frame[2], pull_frame[3], []))
# [(2, 操作指令)]
if push_parm[0] == 1: # 视频帧操作
frame, current_frame, all_frames, ques_list = push_parm[1]
copy_frame = frame.copy()
det_xywh = {}
if len(ques_list) > 0:
for qs in ques_list:
det_xywh[qs[1]] = {}
detect_targets_code = int(qs[0][0])
score = qs[0][-1]
label_array = qs[3][detect_targets_code]
color = qs[4][detect_targets_code]
if not isinstance(qs[0][1], (list, tuple, np.ndarray)):
xc, yc, x2, y2 = int(qs[0][1]), int(qs[0][2]), int(qs[0][3]), int(qs[0][4])
box = [(xc, yc), (x2, yc), (x2, y2), (xc, y2)]
else:
box = qs[0][1]
draw_painting_joint(box, copy_frame, label_array, score, color, "leftTop")
cd = det_xywh[qs[1]].get(detect_targets_code)
if cd is None:
det_xywh[qs[1]][detect_targets_code] = [
[detect_targets_code, box, score, label_array, color]]
else:
det_xywh[qs[1]][detect_targets_code].append(
[detect_targets_code, box, score, label_array, color])
if logo:
frame = add_water_pic(frame, logo, request_id)
copy_frame = add_water_pic(copy_frame, logo, request_id)
frame_merge = video_conjuncing(frame, copy_frame)
# 写原视频到本地
write_or_video_result = t.submit(write_or_video, frame, orFilePath, or_video_file,
or_write_status, request_id)
# 写识别视频到本地
write_ai_video_result = t.submit(write_ai_video, frame_merge, aiFilePath, ai_video_file,
ai_write_status, request_id)
if len(det_xywh) > 0:
put_queue(image_queue, (1, (det_xywh, frame, current_frame, all_frames)))
push_p = push_video_stream(frame_merge, push_p, push_url, p_push_status, request_id)
ai_video_file = write_ai_video_result.result()
or_video_file = write_or_video_result.result()
if push_parm[0] == 2:
if 'stop' == push_parm[1]:
logger.info("停止推流线程, requestId: {}", request_id)
close_all_p(push_p, or_video_file, ai_video_file, request_id)
or_video_file, ai_video_file, push_p = None, None, None
break
except Exception as e:
logger.error("推流线程异常:{}, requestId:{}", format_exc(), request_id)
self.ex = e
finally:
close_all_p(push_p, or_video_file, ai_video_file, request_id)
logger.info("推流线程停止完成requestId:{}", request_id)
class OffPushStreamThread(Thread):
__slots__ = ('_msg', '_push_queue', '_context', 'ex', '_logo', '_image_queue')
def __init__(self, *args):
super().__init__()
# 传参
self._msg, self._push_queue, self._image_queue, self._context = args
# 自带参数
self.ex = None
self._logo = None
if self._context["video"]["video_add_water"]:
self._logo = self._msg.get("logo_url")
if self._logo:
self._logo = url2Array(self._logo, enable_ex=False)
if not self._logo:
self._logo = cv2.imread(join(self._context['base_dir'], "image/logo.png"), -1)
def run(self):
request_id, push_queue, image_queue = self._msg.get("request_id"), self._push_queue, self._image_queue
aiFilePath, logo = self._context.get("aiFilePath"), self._logo
ai_video_file, push_p = None, None
push_url = self._msg.get("push_url")
try:
logger.info("开始启动推流线程requestId:{}", request_id)
with ThreadPoolExecutor(max_workers=1) as t:
p_push_status, or_write_status, ai_write_status = [0, 0], [0, 0], [0, 0]
while True:
push_parm = push_queue.get()
if push_parm is not None:
# [(1, 原视频帧, 分析视频帧)]
# # [视频帧、当前帧数、 总帧数、 [(问题数组、code、allowedList、label_arraylist、rainbows)]]
# res = (1, (pull_frame[1], pull_frame[2], pull_frame[3], []))
# [(2, 操作指令)]
if push_parm[0] == 1: # 视频帧操作
frame, current_frame, all_frames, ques_list = push_parm[1]
copy_frame = frame.copy()
det_xywh = {}
if len(ques_list) > 0:
for qs in ques_list:
det_xywh[qs[1]] = {}
detect_targets_code = int(qs[0][0])
score = qs[0][-1]
label_array = qs[3][detect_targets_code]
color = qs[4][detect_targets_code]
if not isinstance(qs[0][1], (list, tuple, np.ndarray)):
xc, yc, x2, y2 = int(qs[0][1]), int(qs[0][2]), int(qs[0][3]), int(qs[0][4])
box = [(xc, yc), (x2, yc), (x2, y2), (xc, y2)]
else:
box = qs[0][1]
draw_painting_joint(box, copy_frame, label_array, score, color, "leftTop")
cd = det_xywh[qs[1]].get(detect_targets_code)
if cd is None:
det_xywh[qs[1]][detect_targets_code] = [
[detect_targets_code, box, score, label_array, color]]
else:
det_xywh[qs[1]][detect_targets_code].append(
[detect_targets_code, box, score, label_array, color])
if logo:
frame = add_water_pic(frame, logo, request_id)
copy_frame = add_water_pic(copy_frame, logo, request_id)
frame_merge = video_conjuncing(frame, copy_frame)
# 写识别视频到本地
write_ai_video_result = t.submit(write_ai_video, frame_merge, aiFilePath, ai_video_file,
ai_write_status, request_id)
if len(det_xywh) > 0:
put_queue(image_queue, (1, (det_xywh, frame, current_frame, all_frames)))
push_p = push_video_stream(frame_merge, push_p, push_url, p_push_status, request_id)
ai_video_file = write_ai_video_result.result()
if push_parm[0] == 2:
if 'stop' == push_parm[1]:
logger.info("停止推流线程, requestId: {}", request_id)
close_all_p(push_p, None, ai_video_file, request_id)
ai_video_file, push_p = None, None
break
except Exception as e:
logger.error("推流线程异常:{}, requestId:{}", format_exc(), request_id)
self.ex = e
finally:
close_all_p(push_p, None, ai_video_file, request_id)
logger.info("推流线程停止完成requestId:{}", request_id)

View File

@ -0,0 +1,201 @@
# -*- coding: utf-8 -*-
from concurrent.futures import ThreadPoolExecutor, wait, ALL_COMPLETED
from os.path import join
from threading import Thread
from traceback import format_exc
import cv2
import numpy as np
from loguru import logger
from util.Cv2Utils import write_or_video, write_ai_video, push_video_stream, close_all_p, video_conjuncing
from util.ImageUtils import url2Array, add_water_pic
from util.PlotsUtils import draw_painting_joint
from util.QueUtil import put_queue
class OnPushStreamThread2(Thread):
__slots__ = ('_msg', '_push_queue', '_context', 'ex', '_logo', '_image_queue')
def __init__(self, *args):
super().__init__()
# 传参
self._msg, self._push_queue, self._image_queue, self._context = args
# 自带参数
self.ex = None
self._logo = None
if self._context["video"]["video_add_water"]:
self._logo = self._msg.get("logo_url")
if self._logo:
self._logo = url2Array(self._logo, enable_ex=False)
if not self._logo:
self._logo = cv2.imread(join(self._context['base_dir'], "image/logo.png"), -1)
def run(self):
request_id, push_queue, image_queue = self._msg.get("request_id"), self._push_queue, self._image_queue
orFilePath, aiFilePath, logo = self._context.get("orFilePath"), self._context.get("aiFilePath"), self._logo
or_video_file, ai_video_file, push_p = None, None, None
push_url = self._msg.get("push_url")
try:
logger.info("开始启动推流线程requestId:{}", request_id)
with ThreadPoolExecutor(max_workers=2) as t:
with ThreadPoolExecutor(max_workers=5) as tt:
p_push_status, or_write_status, ai_write_status = [0, 0], [0, 0], [0, 0]
while True:
push_r = push_queue.get()
if push_r is not None:
# [(1, 原视频帧, 分析视频帧)]
# [(code, retResults[2])]
# [(2, 操作指令)]
if push_r[0] == 1: # 视频帧操作
frame_list, frame_index_list, all_frames = push_r[1]
allowedList, rainbows, label_arrays, font_config = push_r[2]
for i, frame in enumerate(frame_list):
copy_frame = frame.copy()
det_xywh = {}
# 每帧可能存在多模型,多模型问题处理
thread_p = []
for det in push_r[3]:
code, retResults = det
det_xywh[code] = {}
# 如果识别到了检测目标
if len(retResults[i]) > 0:
for qs in retResults[i]:
detect_targets_code = int(qs[6])
if detect_targets_code not in allowedList:
logger.warning("当前检测目标不在检测目标中: {}, requestId: {}", detect_targets_code, request_id)
continue
score = qs[5]
label_array = label_arrays[detect_targets_code]
color = rainbows[detect_targets_code]
if not isinstance(qs[1], (list, tuple, np.ndarray)):
xc, yc, x2, y2 = int(qs[1]), int(qs[2]), int(qs[3]), int(qs[4])
box = [(xc, yc), (x2, yc), (x2, y2), (xc, y2)]
else:
box = qs[1]
# box, img, label_array, score=0.5, color=None, config=None
dp = tt.submit(draw_painting_joint, box, copy_frame, label_array, score,
color, font_config)
thread_p.append(dp)
cd = det_xywh[code].get(detect_targets_code)
if cd is None:
det_xywh[code][detect_targets_code] = [
[detect_targets_code, box, score, label_array, color]]
else:
det_xywh[code][detect_targets_code].append(
[detect_targets_code, box, score, label_array, color])
if logo:
frame = add_water_pic(frame, logo, request_id)
copy_frame = add_water_pic(copy_frame, logo, request_id)
if len(thread_p) > 0:
completed_results = wait(thread_p, timeout=60, return_when=ALL_COMPLETED)
completed_futures = completed_results.done
for r in completed_futures:
if r.exception():
raise r.exception()
frame_merge = video_conjuncing(frame, copy_frame)
# 写原视频到本地
write_or_video_result = t.submit(write_or_video, frame, orFilePath, or_video_file,
or_write_status, request_id)
# 写识别视频到本地
write_ai_video_result = t.submit(write_ai_video, frame_merge, aiFilePath, ai_video_file,
ai_write_status, request_id)
if len(det_xywh) > 0:
put_queue(image_queue, (1, (det_xywh, frame, frame_index_list[i], all_frames,
font_config)))
push_p = push_video_stream(frame_merge, push_p, push_url, p_push_status, request_id)
ai_video_file = write_ai_video_result.result()
or_video_file = write_or_video_result.result()
if push_r[0] == 2:
if 'stop' == push_r[1]:
logger.info("停止推流线程, requestId: {}", request_id)
close_all_p(push_p, or_video_file, ai_video_file, request_id)
or_video_file, ai_video_file, push_p = None, None, None
break
except Exception as e:
logger.error("推流线程异常:{}, requestId:{}", format_exc(), request_id)
self.ex = e
finally:
close_all_p(push_p, or_video_file, ai_video_file, request_id)
logger.info("推流线程停止完成requestId:{}", request_id)
# class OffPushStreamThread(Thread):
# __slots__ = ('_msg', '_push_queue', '_context', 'ex', '_logo', '_image_queue')
#
# def __init__(self, *args):
# super().__init__()
# # 传参
# self._msg, self._push_queue, self._image_queue, self._context = args
# # 自带参数
# self.ex = None
# self._logo = None
# if self._context["video"]["video_add_water"]:
# self._logo = self._msg.get("logo_url")
# if self._logo:
# self._logo = url2Array(self._logo, enable_ex=False)
# if not self._logo:
# self._logo = cv2.imread(join(self._context['base_dir'], "image/logo.png"), -1)
#
# def run(self):
# request_id, push_queue, image_queue = self._msg.get("request_id"), self._push_queue, self._image_queue
# aiFilePath, logo = self._context.get("aiFilePath"), self._logo
# ai_video_file, push_p = None, None
# push_url = self._msg.get("push_url")
# try:
# logger.info("开始启动推流线程requestId:{}", request_id)
# with ThreadPoolExecutor(max_workers=1) as t:
# p_push_status, or_write_status, ai_write_status = [0, 0], [0, 0], [0, 0]
# while True:
# push_parm = push_queue.get()
# if push_parm is not None:
# # [(1, 原视频帧, 分析视频帧)]
# # # [视频帧、当前帧数、 总帧数、 [(问题数组、code、allowedList、label_arraylist、rainbows)]]
# # res = (1, (pull_frame[1], pull_frame[2], pull_frame[3], []))
# # [(2, 操作指令)]
# if push_parm[0] == 1: # 视频帧操作
# frame, current_frame, all_frames, ques_list = push_parm[1]
# copy_frame = frame.copy()
# det_xywh = {}
# if len(ques_list) > 0:
# for qs in ques_list:
# det_xywh[qs[1]] = {}
# detect_targets_code = int(qs[0][0])
# score = qs[0][-1]
# label_array = qs[3][detect_targets_code]
# color = qs[4][detect_targets_code]
# if not isinstance(qs[0][1], (list, tuple, np.ndarray)):
# xc, yc, x2, y2 = int(qs[0][1]), int(qs[0][2]), int(qs[0][3]), int(qs[0][4])
# box = [(xc, yc), (x2, yc), (x2, y2), (xc, y2)]
# else:
# box = qs[0][1]
# draw_painting_joint(box, copy_frame, label_array, score, color, "leftTop")
# cd = det_xywh[qs[1]].get(detect_targets_code)
# if cd is None:
# det_xywh[qs[1]][detect_targets_code] = [
# [detect_targets_code, box, score, label_array, color]]
# else:
# det_xywh[qs[1]][detect_targets_code].append(
# [detect_targets_code, box, score, label_array, color])
# if logo:
# frame = add_water_pic(frame, logo, request_id)
# copy_frame = add_water_pic(copy_frame, logo, request_id)
# frame_merge = video_conjuncing(frame, copy_frame)
# # 写识别视频到本地
# write_ai_video_result = t.submit(write_ai_video, frame_merge, aiFilePath, ai_video_file,
# ai_write_status, request_id)
# if len(det_xywh) > 0:
# put_queue(image_queue, (1, (det_xywh, frame, current_frame, all_frames)))
# push_p = push_video_stream(frame_merge, push_p, push_url, p_push_status, request_id)
# ai_video_file = write_ai_video_result.result()
# if push_parm[0] == 2:
# if 'stop' == push_parm[1]:
# logger.info("停止推流线程, requestId: {}", request_id)
# close_all_p(push_p, None, ai_video_file, request_id)
# ai_video_file, push_p = None, None
# break
# except Exception as e:
# logger.error("推流线程异常:{}, requestId:{}", format_exc(), request_id)
# self.ex = e
# finally:
# close_all_p(push_p, None, ai_video_file, request_id)
# logger.info("推流线程停止完成requestId:{}", request_id)

View File

@ -0,0 +1,553 @@
#ne -*- coding: utf-8 -*-
from concurrent.futures import ThreadPoolExecutor
from multiprocessing import Process
from os import getpid
import os
from os.path import join
from time import time, sleep
from traceback import format_exc
import cv2
import numpy as np
import psutil
from loguru import logger
from enums.ExceptionEnum import ExceptionType
from enums.ModelTypeEnum import ModelType
from exception.CustomerException import ServiceException
from util import ImageUtils
from util.Cv2Utils import video_conjuncing, write_or_video, write_ai_video, push_video_stream, close_all_p
from util.ImageUtils import url2Array, add_water_pic
from util.LogUtils import init_log
from util.PlotsUtils import draw_painting_joint, filterBox, xywh2xyxy2, xy2xyxy, draw_name_joint, plot_one_box_auto, draw_name_ocr,draw_name_crowd
from util.QueUtil import get_no_block_queue, put_queue, clear_queue
class PushStreamProcess(Process):
__slots__ = ("_msg", "_push_queue", "_image_queue", '_push_ex_queue', '_hb_queue', "_context")
def __init__(self, *args):
super().__init__()
# 传参
self._msg, self._push_queue, self._image_queue, self._push_ex_queue, self._hb_queue, self._context = args
self._algStatus = False # 默认关闭
self._algSwitch = self._context['service']['algSwitch']
#0521:
default_enabled = str(self._msg.get("defaultEnabled", "True")).lower() == "true"
if default_enabled:
print("执行默认程序defaultEnabled=True")
self._algSwitch = True
# 这里放默认逻辑的代码
else:
print("执行替代程序defaultEnabled=False")
# 这里放非默认逻辑的代码
self._algSwitch = False
print("---line53 :PushVideoStreamProcess.py---",self._algSwitch)
def build_logo_url(self):
logo = None
if self._context["video"]["video_add_water"]:
logo = self._msg.get("logo_url")
if logo:
logo = url2Array(logo, enable_ex=False)
if logo is None:
logo = cv2.imread(join(self._context['base_dir'], "image/logo.png"), -1)
self._context["logo"] = logo
@staticmethod
def handle_image(det_xywh, det, frame_score, copy_frame, draw_config, code_list):
code, det_result = det
# 每个单独模型处理
# 模型编号、100帧的所有问题, 检测目标、颜色、文字图片
if len(det_result) > 0:
font_config, allowedList = draw_config["font_config"], draw_config[code]["allowedList"]
rainbows, label_arrays = draw_config[code]["rainbows"], draw_config[code]["label_arrays"]
for qs in det_result:
box, score, cls = xywh2xyxy2(qs)
if cls not in allowedList or score < frame_score:
continue
label_array, color = label_arrays[cls], rainbows[cls]
draw_painting_joint(box, copy_frame, label_array, score, color, font_config)
if det_xywh.get(code) is None:
det_xywh[code], code_list[code] = {}, {}
cd = det_xywh[code].get(cls)
if cd is None:
code_list[code][cls] = 1
det_xywh[code][cls] = [[cls, box, score, label_array, color]]
else:
code_list[code][cls] += 1
det_xywh[code][cls].append([cls, box, score, label_array, color])
class OnPushStreamProcess(PushStreamProcess):
__slots__ = ()
def run(self):
self.build_logo_url()
msg, context = self._msg, self._context
base_dir, env, orFilePath, aiFilePath, logo, service_timeout, frame_score = context["base_dir"], \
context['env'], context["orFilePath"], context["aiFilePath"], context["logo"], \
int(context["service"]["timeout"]) + 120, context["service"]["filter"]["frame_score"]
request_id, push_url = msg["request_id"], msg["push_url"]
push_queue, image_queue, push_ex_queue, hb_queue = self._push_queue, self._image_queue, self._push_ex_queue, \
self._hb_queue
or_video_file, ai_video_file, push_p, ex = None, None, None, None
ex_status = True
# 图片相似度开关
picture_similarity = bool(context["service"]["filter"]["picture_similarity"])
qs_np_tmp = None
pix_dis = 60
try:
init_log(base_dir, env)
logger.info("开始实时启动推流进程requestId:{},pid:{}, ppid:{}", request_id,os.getpid(),os.getppid())
with ThreadPoolExecutor(max_workers=2) as t:
# 定义三种推流、写原视频流、写ai视频流策略
# 第一个参数时间, 第二个参数重试次数
p_push_status, or_write_status, ai_write_status = [0, 0], [0, 0], [0, 0]
start_time = time()
while True:
# 检测推流执行超时时间, 1.防止任务运行超时 2.主进程挂了,子进程运行超时
if time() - start_time > service_timeout:
logger.error("推流超时, requestId: {}", request_id)
raise ServiceException(ExceptionType.TASK_EXCUTE_TIMEOUT.value[0],
ExceptionType.TASK_EXCUTE_TIMEOUT.value[1])
# 系统由于各种问题可能会杀死内存使用多的进程, 自己杀掉自己
if psutil.Process(getpid()).ppid() == 1:
logger.info("推流进程检测到父进程异常停止, 自动停止推流进程, requestId: {}", request_id)
ex_status = False
for q in [push_queue, image_queue, push_ex_queue, hb_queue]:
clear_queue(q)
break
# 获取推流的视频帧
push_r = get_no_block_queue(push_queue)
if push_r is not None:
if push_r[0] == 1:
frame_list, frame_index_list, all_frames, draw_config, push_objs = push_r[1]
for i, frame in enumerate(frame_list):
pix_dis = int((frame.shape[0]//10)*1.2)
# 复制帧用来画图
copy_frame = frame.copy()
det_xywh, thread_p = {}, []
det_xywh2 = {}
# 所有问题的矩阵集合
qs_np = None
qs_reurn = []
for det in push_objs[i]:
code, det_result = det
# 每个单独模型处理
# 模型编号、100帧的所有问题, 检测目标、颜色、文字图片
if len(det_result) > 0:
font_config, allowedList = draw_config["font_config"], draw_config[code]["allowedList"]
rainbows, label_arrays = draw_config[code]["rainbows"], draw_config[code]["label_arrays"]
for qs in det_result:
# 自研车牌模型处理
if ModelType.CITY_CARPLATE_MODEL.value[1] == str(code):
cls = 0
box = xy2xyxy(qs[1])
score = None
color = rainbows[cls]
label_array = None
rr = t.submit(draw_name_ocr, qs, copy_frame, color)
elif ModelType.CITY_DENSECROWDCOUNT_MODEL.value[1] == str(code) or\
ModelType.CITY_UNDERBUILDCOUNT_MODEL.value[1] == str(code):
cls = 0
# crowdlabel, points = qs
box = [(0, 0), (0, 0), (0, 0), (0, 0)]
score = None
color = rainbows[cls]
label_array = None
rr = t.submit(draw_name_crowd, qs, copy_frame, color)
else:
try: # 应对NaN情况
box, score, cls = xywh2xyxy2(qs)
except:
continue
if cls not in allowedList or score < frame_score:
continue
label_array, color = label_arrays[cls], rainbows[cls]
if ModelType.CHANNEL2_MODEL.value[1] == str(code) and cls == 2:
rr = t.submit(draw_name_joint, box, copy_frame,
draw_config[code]["label_dict"], score, color,
font_config, qs[6])
else:
rr = t.submit(draw_painting_joint, box, copy_frame, label_array,
score, color, font_config)
thread_p.append(rr)
if det_xywh.get(code) is None:
det_xywh[code] = {}
cd = det_xywh[code].get(cls)
if not (ModelType.CHANNEL2_MODEL.value[1] == str(code) and cls == 2):
if cd is None:
det_xywh[code][cls] = [[cls, box, score, label_array, color]]
else:
det_xywh[code][cls].append([cls, box, score, label_array, color])
if qs_np is None:
qs_np = np.array([box[0][0], box[0][1], box[1][0], box[1][1],
box[2][0], box[2][1], box[3][0], box[3][1],
score, cls, code],dtype=np.float32)
else:
result_li = np.array([box[0][0], box[0][1], box[1][0], box[1][1],
box[2][0], box[2][1], box[3][0], box[3][1],
score, cls, code],dtype=np.float32)
qs_np = np.row_stack((qs_np, result_li))
if logo:
frame = add_water_pic(frame, logo, request_id)
copy_frame = add_water_pic(copy_frame, logo, request_id)
if len(thread_p) > 0:
for r in thread_p:
r.result()
#print('----line173:',self._algSwitch,self._algStatus)
if self._algSwitch and (not self._algStatus):
frame_merge = video_conjuncing(frame, frame.copy())
else:
frame_merge = video_conjuncing(frame, copy_frame)
# 写原视频到本地
write_or_video_result = t.submit(write_or_video, frame, orFilePath, or_video_file,
or_write_status, request_id)
# 写识别视频到本地
write_ai_video_result = t.submit(write_ai_video, frame_merge, aiFilePath,
ai_video_file, ai_write_status, request_id)
push_stream_result = t.submit(push_video_stream, frame_merge, push_p, push_url,
p_push_status, request_id)
# 如果有问题, 走下面的逻辑
if qs_np is not None:
if len(qs_np.shape) == 1:
qs_np = qs_np[np.newaxis,...]
qs_np_id = qs_np.copy()
b = np.ones(qs_np_id.shape[0])
qs_np_id = np.column_stack((qs_np_id,b))
if qs_np_tmp is None:
if picture_similarity:
qs_np_tmp = qs_np_id.copy()
b = np.zeros(qs_np.shape[0])
qs_reurn = np.column_stack((qs_np,b))
else:
qs_reurn = filterBox(qs_np, qs_np_tmp, pix_dis)
if picture_similarity:
qs_np_tmp = np.append(qs_np_tmp,qs_np_id,axis=0)
qs_np_tmp[:, 11] += 1
qs_np_tmp = np.delete(qs_np_tmp, np.where((qs_np_tmp[:, 11] >= 75))[0], axis=0)
has = False
new_lab = []
for j in qs_reurn:
if j[11] == 1:
has = True
new_lab.append(j[9])
if has:
for q in qs_reurn:
if q[11] >= 1:
cls = int(q[9])
if not (cls in new_lab):
continue # 为了防止其他类别被带出
code = str(int(q[10])).zfill(3)
if det_xywh2.get(code) is None:
det_xywh2[code] = {}
cd = det_xywh2[code].get(cls)
score = q[8]
rainbows, label_arrays = draw_config[code]["rainbows"], draw_config[code]["label_arrays"]
label_array, color = label_arrays[cls], rainbows[cls]
box = [(int(q[0]), int(q[1])), (int(q[2]), int(q[3])),
(int(q[4]), int(q[5])), (int(q[6]), int(q[7]))]
is_new = False
if q[11] == 1:
is_new = True
if ModelType.CITY_CARPLATE_MODEL.value[1] == str(code) or \
ModelType.CITY_DENSECROWDCOUNT_MODEL.value[1] == str(code) or\
ModelType.CITY_UNDERBUILDCOUNT_MODEL.value[1] == str(code):
box = qs
if cd is None:
det_xywh2[code][cls] = [[cls, box, score, label_array, color, is_new]]
else:
det_xywh2[code][cls].append(
[cls, box, score, label_array, color, is_new])
if len(det_xywh2) > 0:
put_queue(image_queue, (1, [det_xywh2, frame, frame_index_list[i], all_frames,
draw_config["font_config"]]))
push_p = push_stream_result.result(timeout=60)
ai_video_file = write_ai_video_result.result(timeout=60)
or_video_file = write_or_video_result.result(timeout=60)
# 接收停止指令
if push_r[0] == 2:
logger.info("拉流进程收到控制命令为:{}, requestId: {}",push_r[1] ,request_id)
if 'algStart' == push_r[1]: self._algStatus = True;logger.info("算法识别开启, requestId: {}", request_id)
if 'algStop' == push_r[1]: self._algStatus = False;logger.info("算法识别关闭, requestId: {}", request_id)
if 'stop' == push_r[1]:
logger.info("停止推流进程, requestId: {}", request_id)
break
if 'stop_ex' == push_r[1]:
ex_status = False
logger.info("停止推流进程, requestId: {}", request_id)
break
del push_r
else:
sleep(1)
except ServiceException as s:
logger.error("推流进程异常:{}, requestId:{}", s.msg, request_id)
ex = s.code, s.msg
except Exception:
logger.error("推流进程异常:{}, requestId:{}", format_exc(), request_id)
ex = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1]
finally:
# 关闭推流管, 原视频写对象, 分析视频写对象
close_all_p(push_p, or_video_file, ai_video_file, request_id)
if ex:
code, msg = ex
put_queue(push_ex_queue, (1, code, msg), timeout=2)
else:
if ex_status:
# 关闭推流的时候, 等待1分钟图片队列处理完如果1分钟内没有处理完, 清空图片队列, 丢弃没有上传的图片
c_time = time()
while time() - c_time < 60:
if image_queue.qsize() == 0 or image_queue.empty():
break
sleep(2)
for q in [push_queue, image_queue, hb_queue]:
clear_queue(q)
logger.info("推流进程停止完成!图片队列大小: {}, requestId:{}", image_queue.qsize(), request_id)
class OffPushStreamProcess(PushStreamProcess):
__slots__ = ()
def run(self):
self.build_logo_url()
msg, context = self._msg, self._context
request_id = msg["request_id"]
base_dir, env = context["base_dir"], context['env']
push_queue, image_queue, push_ex_queue, hb_queue = self._push_queue, self._image_queue, self._push_ex_queue, \
self._hb_queue
aiFilePath, logo = context["aiFilePath"], context["logo"]
ai_video_file, push_p, push_url = None, None, msg["push_url"]
service_timeout = int(context["service"]["timeout"]) + 120
frame_score = context["service"]["filter"]["frame_score"]
ex = None
ex_status = True
# 图片相似度开关
picture_similarity = bool(context["service"]["filter"]["picture_similarity"])
qs_np_tmp = None
pix_dis = 60
if msg['taskType']==0: self._algStatus = False
else: self._algStatus = True
try:
init_log(base_dir, env)
logger.info("开始启动离线推流进程requestId:{}", request_id)
with ThreadPoolExecutor(max_workers=2) as t:
# 定义三种推流、写原视频流、写ai视频流策略
# 第一个参数时间, 第二个参数重试次数
p_push_status, ai_write_status = [0, 0], [0, 0]
start_time = time()
while True:
# 检测推流执行超时时间
if time() - start_time > service_timeout:
logger.error("离线推流超时, requestId: {}", request_id)
raise ServiceException(ExceptionType.TASK_EXCUTE_TIMEOUT.value[0],
ExceptionType.TASK_EXCUTE_TIMEOUT.value[1])
# 系统由于各种问题可能会杀死内存使用多的进程, 自己杀掉自己
if psutil.Process(getpid()).ppid() == 1:
logger.info("离线推流进程检测到父进程异常停止, 自动停止推流进程, requestId: {}", request_id)
ex_status = False
for q in [push_queue, image_queue, push_ex_queue, hb_queue]:
clear_queue(q)
break
# 获取推流的视频帧
push_r = get_no_block_queue(push_queue)
if push_r is not None:
# [(1, ...] 视频帧操作
# [(2, 操作指令)] 指令操作
if push_r[0] == 1:
frame_list, frame_index_list, all_frames, draw_config, push_objs = push_r[1]
# 处理每一帧图片
for i, frame in enumerate(frame_list):
pix_dis = int((frame.shape[0]//10)*1.2)
if frame_index_list[i] % 300 == 0 and frame_index_list[i] <= all_frames:
task_process = "%.2f" % (float(frame_index_list[i]) / float(all_frames))
put_queue(hb_queue, {"hb_value": task_process}, timeout=2)
# 复制帧用来画图
copy_frame = frame.copy()
# 所有问题记录字典
det_xywh, thread_p = {}, []
det_xywh2 = {}
# 所有问题的矩阵集合
qs_np = None
qs_reurn = []
for det in push_objs[i]:
code, det_result = det
# 每个单独模型处理
# 模型编号、100帧的所有问题, 检测目标、颜色、文字图片
if len(det_result) > 0:
font_config, allowedList = draw_config["font_config"], draw_config[code]["allowedList"]
rainbows, label_arrays = draw_config[code]["rainbows"], draw_config[code]["label_arrays"]
for qs in det_result:
# 自研车牌模型处理
if ModelType.CITY_CARPLATE_MODEL.value[1] == str(code):
cls = 0
box = xy2xyxy(qs[1])
score = None
color = rainbows[cls]
label_array = None
label_arrays = [None]
rr = t.submit(draw_name_ocr, qs, copy_frame, color)
elif ModelType.CITY_DENSECROWDCOUNT_MODEL.value[1] == str(code) or\
ModelType.CITY_UNDERBUILDCOUNT_MODEL.value[1] == str(code):
cls = 0
box = [(0,0),(0,0),(0,0),(0,0)]
score = None
color = rainbows[cls]
label_array = None
rr = t.submit(draw_name_crowd, qs, copy_frame, color)
else:
box, score, cls = xywh2xyxy2(qs)
if cls not in allowedList or score < frame_score:
continue
label_array, color = label_arrays[cls], rainbows[cls]
if ModelType.CHANNEL2_MODEL.value[1] == str(code) and cls == 2:
rr = t.submit(draw_name_joint, box, copy_frame, draw_config[code]["label_dict"], score, color, font_config, qs[6])
else:
rr = t.submit(draw_painting_joint, box, copy_frame, label_array, score, color, font_config)
thread_p.append(rr)
if det_xywh.get(code) is None:
det_xywh[code] = {}
cd = det_xywh[code].get(cls)
if not (ModelType.CHANNEL2_MODEL.value[1] == str(code) and cls == 2):
if cd is None:
det_xywh[code][cls] = [[cls, box, score, label_array, color]]
else:
det_xywh[code][cls].append([cls, box, score, label_array, color])
if qs_np is None:
qs_np = np.array([box[0][0], box[0][1], box[1][0], box[1][1],
box[2][0], box[2][1], box[3][0], box[3][1],
score, cls, code],dtype=np.float32)
else:
result_li = np.array([box[0][0], box[0][1], box[1][0], box[1][1],
box[2][0], box[2][1], box[3][0], box[3][1],
score, cls, code],dtype=np.float32)
qs_np = np.row_stack((qs_np, result_li))
if logo:
frame = add_water_pic(frame, logo, request_id)
copy_frame = add_water_pic(copy_frame, logo, request_id)
if len(thread_p) > 0:
for r in thread_p:
r.result()
if self._algSwitch and (not self._algStatus):
frame_merge = video_conjuncing(frame, frame.copy())
else:
frame_merge = video_conjuncing(frame, copy_frame)
# 写识别视频到本地
write_ai_video_result = t.submit(write_ai_video, frame_merge, aiFilePath,
ai_video_file,
ai_write_status, request_id)
push_stream_result = t.submit(push_video_stream, frame_merge, push_p, push_url,
p_push_status, request_id)
if qs_np is not None:
if len(qs_np.shape) == 1:
qs_np = qs_np[np.newaxis,...]
qs_np_id = qs_np.copy()
b = np.ones(qs_np_id.shape[0])
qs_np_id = np.column_stack((qs_np_id,b))
if qs_np_tmp is None:
if picture_similarity:
qs_np_tmp = qs_np_id.copy()
b = np.zeros(qs_np.shape[0])
qs_reurn = np.column_stack((qs_np,b))
else:
qs_reurn = filterBox(qs_np, qs_np_tmp, pix_dis)
if picture_similarity:
qs_np_tmp = np.append(qs_np_tmp,qs_np_id,axis=0)
qs_np_tmp[:, 11] += 1
qs_np_tmp = np.delete(qs_np_tmp, np.where((qs_np_tmp[:, 11] >= 75))[0], axis=0)
has = False
new_lab = []
for j in qs_reurn:
if j[11] == 1:
has = True
new_lab.append(j[9])
if has:
for q in qs_reurn:
if q[11] >= 1:
cls = int(q[9])
if not (cls in new_lab):
continue # 为了防止其他类别被带出
code = str(int(q[10])).zfill(3)
if det_xywh2.get(code) is None:
det_xywh2[code] = {}
cd = det_xywh2[code].get(cls)
score = q[8]
rainbows, label_arrays = draw_config[code]["rainbows"], draw_config[code]["label_arrays"]
label_array, color = label_arrays[cls], rainbows[cls]
box = [(int(q[0]), int(q[1])), (int(q[2]), int(q[3])),
(int(q[4]), int(q[5])), (int(q[6]), int(q[7]))]
is_new = False
if q[11] == 1:
is_new = True
if ModelType.CITY_CARPLATE_MODEL.value[1] == str(code) or \
ModelType.CITY_DENSECROWDCOUNT_MODEL.value[1] == str(code) or\
ModelType.CITY_UNDERBUILDCOUNT_MODEL.value[1] == str(code):
box = qs
if cd is None:
det_xywh2[code][cls] = [[cls, box, score, label_array, color, is_new]]
else:
det_xywh2[code][cls].append(
[cls, box, score, label_array, color, is_new])
if len(det_xywh2) > 0:
put_queue(image_queue, (1, [det_xywh2, frame, frame_index_list[i], all_frames, draw_config["font_config"]]))
push_p = push_stream_result.result(timeout=60)
ai_video_file = write_ai_video_result.result(timeout=60)
# 接收停止指令
if push_r[0] == 2:
logger.info("拉流进程收到控制命令为:{}, requestId: {}",push_r[1] ,request_id)
if 'algStart' == push_r[1]: self._algStatus = True;logger.info("算法识别开启, requestId: {}", request_id)
if 'algStop' == push_r[1]: self._algStatus = False;logger.info("算法识别关闭, requestId: {}", request_id)
if 'stop' == push_r[1]:
logger.info("停止推流进程, requestId: {}", request_id)
break
if 'stop_ex' == push_r[1]:
logger.info("停止推流进程, requestId: {}", request_id)
ex_status = False
break
del push_r
else:
sleep(1)
except ServiceException as s:
logger.error("推流进程异常:{}, requestId:{}", s.msg, request_id)
ex = s.code, s.msg
except Exception:
logger.error("推流进程异常:{}, requestId:{}", format_exc(), request_id)
ex = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1]
finally:
# 关闭推流管, 分析视频写对象
close_all_p(push_p, None, ai_video_file, request_id)
if ex:
code, msg = ex
put_queue(push_ex_queue, (1, code, msg), timeout=2)
else:
if ex_status:
# 关闭推流的时候, 等待1分钟图片队列处理完如果1分钟内没有处理完, 清空图片队列, 丢弃没有上传的图片
c_time = time()
while time() - c_time < 60:
if image_queue.qsize() == 0 or image_queue.empty():
break
sleep(2)
for q in [push_queue, image_queue, hb_queue]:
clear_queue(q)
logger.info("推流进程停止完成requestId:{}", request_id)

View File

@ -0,0 +1,356 @@
# -*- coding: utf-8 -*-
from concurrent.futures import ThreadPoolExecutor
from multiprocessing import Process
from os import getpid
from os.path import join
from time import time, sleep
from traceback import format_exc
import cv2
import numpy as np
import psutil
from loguru import logger
from enums.ExceptionEnum import ExceptionType
from exception.CustomerException import ServiceException
from util import ImageUtils
from util.Cv2Utils import video_conjuncing, write_or_video, write_ai_video, push_video_stream, close_all_p
from util.ImageUtils import url2Array, add_water_pic
from util.LogUtils import init_log
from util.PlotsUtils import draw_painting_joint, filterBox, xywh2xyxy2
from util.QueUtil import get_no_block_queue, put_queue, clear_queue
class PushStreamProcess2(Process):
__slots__ = ("_msg", "_push_queue", "_image_queue", '_push_ex_queue', '_hb_queue', "_context")
def __init__(self, *args):
super().__init__()
# 传参
self._msg, self._push_queue, self._image_queue, self._push_ex_queue, self._hb_queue, self._context = args
def build_logo_url(self):
logo = None
if self._context["video"]["video_add_water"]:
logo = self._msg.get("logo_url")
if logo:
logo = url2Array(logo, enable_ex=False)
if logo is None:
logo = cv2.imread(join(self._context['base_dir'], "image/logo.png"), -1)
self._context["logo"] = logo
class OnPushStreamProcess2(PushStreamProcess2):
__slots__ = ()
def run(self):
msg, context = self._msg, self._context
self.build_logo_url()
request_id = msg["request_id"]
base_dir, env = context["base_dir"], context['env']
push_queue, image_queue, push_ex_queue, hb_queue = self._push_queue, self._image_queue, self._push_ex_queue, \
self._hb_queue
orFilePath, aiFilePath, logo = context["orFilePath"], context["aiFilePath"], context["logo"]
or_video_file, ai_video_file, push_p, push_url = None, None, None, msg["push_url"]
service_timeout = int(context["service"]["timeout"]) + 120
frame_score = context["service"]["filter"]["frame_score"]
ex = None
ex_status = True
try:
init_log(base_dir, env)
logger.info("开始启动推流进程requestId:{}", request_id)
with ThreadPoolExecutor(max_workers=3) as t:
# 定义三种推流、写原视频流、写ai视频流策略
# 第一个参数时间, 第二个参数重试次数
p_push_status, or_write_status, ai_write_status = [0, 0], [0, 0], [0, 0]
start_time = time()
minID = 0
maxID = 0
while True:
# 检测推流执行超时时间
if time() - start_time > service_timeout:
logger.error("推流超时, requestId: {}", request_id)
raise ServiceException(ExceptionType.PUSH_STREAM_TIMEOUT_EXCEPTION.value[0],
ExceptionType.PUSH_STREAM_TIMEOUT_EXCEPTION.value[1])
# 系统由于各种问题可能会杀死内存使用多的进程, 自己杀掉自己
if psutil.Process(getpid()).ppid() == 1:
ex_status = False
logger.info("推流进程检测到父进程异常停止, 自动停止推流进程, requestId: {}", request_id)
for q in [push_queue, image_queue, push_ex_queue, hb_queue]:
clear_queue(q)
break
# 获取推流的视频帧
push_r = get_no_block_queue(push_queue)
if push_r is not None:
# [(1, ...] 视频帧操作
# [(2, 操作指令)] 指令操作
if push_r[0] == 1:
# 如果是多模型push_objs数组可能包含[模型1识别数组, 模型2识别数组, 模型3识别数组]
frame_list, frame_index_list, all_frames, draw_config, push_objs = push_r[1]
# 处理每一帧图片
for i, frame in enumerate(frame_list):
# 复制帧用来画图
copy_frame = frame.copy()
# 所有问题记录字典
det_xywh, thread_p = {}, []
det_tmp = {}
det_xywh2 = {}
# [模型1识别数组, 模型2识别数组, 模型3识别数组]
for s_det_list in push_objs:
code, det_result = s_det_list[0], s_det_list[1][i]
if len(det_result) > 0:
font_config, allowedList = draw_config["font_config"], draw_config[code]["allowedList"]
rainbows, label_arrays = draw_config[code]["rainbows"], draw_config[code]["label_arrays"]
for qs in det_result:
box, score, cls = xywh2xyxy2(qs)
if cls not in allowedList or score < frame_score:
continue
label_array, color = label_arrays[cls], rainbows[cls]
rr = t.submit(draw_painting_joint, box, copy_frame, label_array, score, color, font_config)
thread_p.append(rr)
if det_xywh.get(code) is None:
det_xywh[code] = {}
cd = det_xywh[code].get(cls)
is_new = False
if len(qs) == 8:
trackId = qs[7]
elif len(qs) == 5:
trackId = qs[4]
if trackId > minID:
is_new = True
if det_tmp.get(code) is None:
det_tmp[code] = [cls]
else:
if not (cls in det_tmp[code]):
det_tmp[code].append(cls)
qs_tmp = [cls, box, score, label_array, color, is_new]
if trackId > maxID:
maxID = trackId
if cd is None:
det_xywh[code][cls] = [qs_tmp]
else:
det_xywh[code][cls].append(qs_tmp)
minID = maxID
if logo:
frame = add_water_pic(frame, logo, request_id)
copy_frame = add_water_pic(copy_frame, logo, request_id)
if len(thread_p) > 0:
for r in thread_p:
r.result()
frame_merge = video_conjuncing(frame, copy_frame)
# 写原视频到本地
write_or_video_result = t.submit(write_or_video, frame, orFilePath, or_video_file,
or_write_status, request_id)
# 写识别视频到本地
write_ai_video_result = t.submit(write_ai_video, frame_merge, aiFilePath,
ai_video_file, ai_write_status, request_id)
push_p_result = t.submit(push_video_stream, frame_merge, push_p, push_url,
p_push_status,
request_id)
if det_xywh:
for index, (key, value) in enumerate(det_xywh.items()):
for k in value.keys():
if (key in det_tmp.keys()) and (k in det_tmp[key]):
det_xywh2[key] = {}
det_xywh2[key][k] = det_xywh[key][k]
if len(det_xywh2) > 0:
put_queue(image_queue, (1, [det_xywh2, frame, frame_index_list[i], all_frames, draw_config["font_config"]]))
push_p = push_p_result.result(timeout=60)
ai_video_file = write_ai_video_result.result(timeout=60)
or_video_file = write_or_video_result.result(timeout=60)
# 接收停止指令
if push_r[0] == 2:
if 'stop' == push_r[1]:
logger.info("停止推流线程, requestId: {}", request_id)
break
if 'stop_ex' == push_r[1]:
logger.info("停止推流线程, requestId: {}", request_id)
ex_status = False
break
del push_r
else:
sleep(1)
except ServiceException as s:
logger.error("推流进程异常:{}, requestId:{}", s.msg, request_id)
ex = s.code, s.msg
except Exception:
logger.error("推流进程异常:{}, requestId:{}", format_exc(), request_id)
ex = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1]
finally:
# 关闭推流管, 原视频写对象, 分析视频写对象
close_all_p(push_p, or_video_file, ai_video_file, request_id)
if ex:
code, msg = ex
put_queue(push_ex_queue, (1, code, msg), timeout=2)
else:
if ex_status:
# 关闭推流的时候, 等待1分钟图片队列处理完如果1分钟内没有处理完, 清空图片队列, 丢弃没有上传的图片
c_time = time()
while time() - c_time < 60:
if image_queue.qsize() == 0 or image_queue.empty():
break
sleep(2)
for q in [push_queue, image_queue, hb_queue]:
clear_queue(q)
logger.info("推流进程停止完成requestId:{}", request_id)
class OffPushStreamProcess2(PushStreamProcess2):
__slots__ = ()
def run(self):
self.build_logo_url()
msg, context = self._msg, self._context
request_id = msg["request_id"]
base_dir, env = context["base_dir"], context['env']
push_queue, image_queue, push_ex_queue, hb_queue = self._push_queue, self._image_queue, self._push_ex_queue, \
self._hb_queue
aiFilePath, logo = context["aiFilePath"], context["logo"]
ai_video_file, push_p, push_url = None, None, msg["push_url"]
service_timeout = int(context["service"]["timeout"]) + 120
frame_score = context["service"]["filter"]["frame_score"]
ex = None
ex_status = True
try:
init_log(base_dir, env)
logger.info("开始启动离线推流进程requestId:{}", request_id)
with ThreadPoolExecutor(max_workers=2) as t:
# 定义三种推流、写原视频流、写ai视频流策略
# 第一个参数时间, 第二个参数重试次数
p_push_status, ai_write_status = [0, 0], [0, 0]
start_time = time()
minID = 0
maxID = 0
while True:
# 检测推流执行超时时间
if time() - start_time > service_timeout:
logger.error("离线推流超时, requestId: {}", request_id)
raise ServiceException(ExceptionType.PUSH_STREAM_TIMEOUT_EXCEPTION.value[0],
ExceptionType.PUSH_STREAM_TIMEOUT_EXCEPTION.value[1])
# 系统由于各种问题可能会杀死内存使用多的进程, 自己杀掉自己
if psutil.Process(getpid()).ppid() == 1:
ex_status = False
logger.info("离线推流进程检测到父进程异常停止, 自动停止推流进程, requestId: {}", request_id)
for q in [push_queue, image_queue, push_ex_queue, hb_queue]:
clear_queue(q)
break
# 获取推流的视频帧
push_r = get_no_block_queue(push_queue)
if push_r is not None:
# [(1, ...] 视频帧操作
# [(2, 操作指令)] 指令操作
if push_r[0] == 1:
frame_list, frame_index_list, all_frames, draw_config, push_objs = push_r[1]
# 处理每一帧图片
for i, frame in enumerate(frame_list):
if frame_index_list[i] % 300 == 0 and frame_index_list[i] <= all_frames:
task_process = "%.2f" % (float(frame_index_list[i]) / float(all_frames))
put_queue(hb_queue, {"hb_value": task_process}, timeout=2)
# 复制帧用来画图
copy_frame = frame.copy()
# 所有问题记录字典
det_xywh, thread_p = {}, []
det_xywh2 = {}
det_tmp = {}
for s_det_list in push_objs:
code, det_result = s_det_list[0], s_det_list[1][i]
if len(det_result) > 0:
font_config, allowedList = draw_config["font_config"], draw_config[code]["allowedList"]
rainbows, label_arrays = draw_config[code]["rainbows"], draw_config[code]["label_arrays"]
for qs in det_result:
box, score, cls = xywh2xyxy2(qs)
if cls not in allowedList or score < frame_score:
continue
label_array, color = label_arrays[cls], rainbows[cls]
rr = t.submit(draw_painting_joint, box, copy_frame, label_array, score, color, font_config)
thread_p.append(rr)
if det_xywh.get(code) is None:
det_xywh[code] = {}
cd = det_xywh[code].get(cls)
is_new = False
if len(qs) == 8:
trackId = qs[7]
elif len(qs) == 5:
trackId = qs[4]
if trackId > minID:
is_new = True
if det_tmp.get(code) is None:
det_tmp[code] = [cls]
else:
if not (cls in det_tmp[code]):
det_tmp[code].append(cls)
qs_tmp = [cls, box, score, label_array, color, is_new]
if trackId > maxID:
maxID = trackId
if cd is None:
det_xywh[code][cls] = [qs_tmp]
else:
det_xywh[code][cls].append(qs_tmp)
minID = maxID
if logo:
frame = add_water_pic(frame, logo, request_id)
copy_frame = add_water_pic(copy_frame, logo, request_id)
if len(thread_p) > 0:
for r in thread_p:
r.result()
frame_merge = video_conjuncing(frame, copy_frame)
# 写识别视频到本地
write_ai_video_result = t.submit(write_ai_video, frame_merge, aiFilePath,
ai_video_file,
ai_write_status, request_id)
push_p_result = t.submit(push_video_stream, frame_merge, push_p, push_url,
p_push_status,
request_id)
if det_xywh:
for index, (key, value) in enumerate(det_xywh.items()):
for k in value.keys():
if (key in det_tmp.keys()) and (k in det_tmp[key]):
det_xywh2[key] = {}
det_xywh2[key][k] = det_xywh[key][k]
if len(det_xywh2) > 0:
put_queue(image_queue, (1, [det_xywh2, frame, frame_index_list[i], all_frames, draw_config["font_config"]]))
push_p = push_p_result.result(timeout=60)
ai_video_file = write_ai_video_result.result(timeout=60)
# 接收停止指令
if push_r[0] == 2:
if 'stop' == push_r[1]:
logger.info("停止推流线程, requestId: {}", request_id)
break
if 'stop_ex' == push_r[1]:
logger.info("停止推流线程, requestId: {}", request_id)
ex_status = False
break
del push_r
else:
sleep(1)
except ServiceException as s:
logger.error("推流进程异常:{}, requestId:{}", s.msg, request_id)
ex = s.code, s.msg
except Exception:
logger.error("推流进程异常:{}, requestId:{}", format_exc(), request_id)
ex = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1]
finally:
# 关闭推流管, 分析视频写对象
close_all_p(push_p, None, ai_video_file, request_id)
if ex:
code, msg = ex
put_queue(push_ex_queue, (1, code, msg), timeout=2)
else:
if ex_status:
# 关闭推流的时候, 等待1分钟图片队列处理完如果1分钟内没有处理完, 清空图片队列, 丢弃没有上传的图片
c_time = time()
while time() - c_time < 60:
if image_queue.qsize() == 0 or image_queue.empty():
break
sleep(2)
for q in [push_queue, image_queue, hb_queue]:
clear_queue(q)
logger.info("推流进程停止完成requestId:{}", request_id)

View File

@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
from threading import Thread
import time
from traceback import format_exc
from loguru import logger
from entity.FeedBack import recording_feedback
from enums.RecordingStatusEnum import RecordingStatus
from util.QueUtil import get_no_block_queue, put_queue, clear_queue
class RecordingHeartbeat(Thread):
__slots__ = ('_fb_queue', '_hb_queue', '_request_id')
def __init__(self, fb_queue, hb_queue, request_id):
super().__init__()
self._fb_queue = fb_queue
self._hb_queue = hb_queue
self._request_id = request_id
def run(self):
request_id = self._request_id
hb_queue, fb_queue = self._hb_queue, self._fb_queue
logger.info("开始启动录屏心跳线程requestId:{}", request_id)
hb_init_num, progress = 0, '0.0000'
status = RecordingStatus.RECORDING_WAITING.value[0]
try:
while True:
time.sleep(3)
hb_msg = get_no_block_queue(hb_queue)
if hb_msg is not None and len(hb_msg) > 0:
command_que = hb_msg.get("command")
progress_que = hb_msg.get("progress")
status_que = hb_msg.get("status")
if progress_que is not None:
progress = progress_que
if status_que is not None:
status = status_que
if 'stop' == command_que:
logger.info("开始终止心跳线程, requestId:{}", request_id)
break
if hb_init_num % 30 == 0:
put_queue(fb_queue, recording_feedback(request_id, status, progress=progress), timeout=5, is_ex=True)
hb_init_num += 3
except Exception:
logger.error("心跳线程异常:{}, requestId:{}", format_exc(), request_id)
finally:
clear_queue(hb_queue)
logger.info("心跳线程停止完成requestId:{}", request_id)

0
concurrency/__init__.py Normal file
View File

153
concurrency/uploadGPU.py Normal file
View File

@ -0,0 +1,153 @@
# -*- coding: utf-8 -*-
from threading import Thread
from time import sleep, time
from traceback import format_exc
#from common.Constant import init_progess
import json,os,psutil,GPUtil,platform,socket
from kafka import KafkaProducer, KafkaConsumer
#from util.KafkaUtils import CustomerKafkaProducer
from common.YmlConstant import service_yml_path, kafka_yml_path
class uploadGPUinfos(Thread):
__slots__ = ('__kafka_config', "_context")
def __init__(self, *args):
super().__init__()
self.__context,self.__kafka_config = args
self.__uploadInterval = self.__context['GPUpollInterval']
#kafkaProducer = CustomerKafkaProducer(self.__kafka_config)
self.__producer = KafkaProducer(
bootstrap_servers=self.__kafka_config['bootstrap_servers'],#tencent yun
value_serializer=lambda v: v.encode('utf-8'))
self.__topic = self.__kafka_config["topicGPU"]
def run(self):
while True:
try:
#获取当前的gpu状态信息
msg_dict = get_system_info()
#发送GPU状态到指定的topic
msg = json.dumps(msg_dict)
# 假设生产的消息为键值对不是一定要键值对且序列化方式为json
#future = kafkaProducer.sender(topic_on,msg)
future = self.__producer .send(self.__topic,msg)
try:
future.get(timeout=10)
except kafka_errors:
traceback.format_exc()
sleep(self.__uploadInterval)
except Exception as e:
print(e)
continue
#logger.error("上传GPU服务器线程状态异常:{}, requestId:{}", format_exc(), request_id)
def get_system_info():
# 初始化一个字典来存储系统信息
system_info = {}
# 获取CPU信息
system_info['CPU'] = {
'Physical Cores': psutil.cpu_count(logical=False), # 物理核心数
'Logical Cores': psutil.cpu_count(logical=True), # 逻辑核心数
'Current Frequency': psutil.cpu_freq().current, # 当前频率
'Usage Per Core': psutil.cpu_percent(interval=1, percpu=True), # 每个核心的使用率
'Total Usage': psutil.cpu_percent(interval=1) # 总体CPU使用率
}
# 获取内存信息
memory = psutil.virtual_memory()
system_info['Memory'] = {
'Total': memory.total / (1024 ** 3), # 总内存单位为GB
'Available': memory.available / (1024 ** 3), # 可用内存
'Used': memory.used / (1024 ** 3), # 已用内存
'Usage Percentage': memory.percent # 内存使用率
}
# 获取GPU信息
gpus = GPUtil.getGPUs()
system_info['GPU'] = []
for gpu in gpus:
gpu_info = {
'ID': gpu.id,
'Name': gpu.name,
'Load': gpu.load * 100, # GPU负载百分比
'Memory Total': gpu.memoryTotal, # 总显存单位为MB
'Memory Used': gpu.memoryUsed, # 已用显存
'Memory Free': gpu.memoryFree, # 可用显存
'Temperature': gpu.temperature # GPU温度
}
system_info['GPU'].append(gpu_info)
# 获取系统信息
system_info['System'] = {
'Platform': platform.system(), # 操作系统类型
'Platform Version': platform.version(), # 操作系统版本
'Platform Release': platform.release(), # 操作系统发行版本
'Platform Node': platform.node(), # 网络名称
'Machine': platform.machine(), # 硬件架构
'Processor': platform.processor() # CPU架构
}
# 获取本机局域网IP地址非回环地址
try:
# 获取所有网络接口信息
net_if_addrs = psutil.net_if_addrs()
for interface, addrs in net_if_addrs.items():
for addr in addrs:
# 筛选IPv4地址且非回环地址
if addr.family == socket.AF_INET and not addr.address.startswith("127."):
system_info['System']['Local IP Address'] = addr.address
break
if 'Local IP Address' in system_info['System']:
break
else:
system_info['System']['Local IP Address'] = "No local IP found"
except Exception as e:
system_info['System']['Local IP Address'] = "Unable to retrieve local IP address"
return system_info
if __name__=="__main__":
context = {
'GPUpollInterval':1,
'topic':'server-status',
}
kafka_config = {
'bootstrap_servers':['192.168.10.66:9092']
}
base_dir, env = '/home/thsw2/WJ/test/tuoheng_algN','test'
upload_thread = uploadGPUinfos(context,kafka_config)
upload_thread.setDaemon(False)
upload_thread.start()
# 主线程等待守护线程运行
try:
while True:
sleep(1)
except KeyboardInterrupt:
print("主线程退出")

View File

@ -0,0 +1,10 @@
access_key: "LTAI5tSJ62TLMUb4SZuf285A"
access_secret: "MWYynm30filZ7x0HqSHlU3pdLVNeI7"
oss:
endpoint: "http://oss-cn-shanghai.aliyuncs.com"
bucket: "ta-tech-image"
connect_timeout: 30
vod:
host_address: "https://vod.play.t-aaron.com/"
ecsRegionId: "cn-shanghai"
cateId: 1000468341

View File

@ -0,0 +1,10 @@
access_key: "LTAI5tSJ62TLMUb4SZuf285A"
access_secret: "MWYynm30filZ7x0HqSHlU3pdLVNeI7"
oss:
endpoint: "http://oss-cn-shanghai.aliyuncs.com"
bucket: "ta-tech-image"
connect_timeout: 30
vod:
host_address: "https://vod.play.t-aaron.com/"
ecsRegionId: "cn-shanghai"
cateId: 1000468340

View File

@ -0,0 +1,11 @@
access_key: "LTAI5tFmaJHU7ywvBH2j12Gp"
access_secret: "mX6rS1xYTgZgFAgpOrQHyc6jLXv0AV"
oss:
endpoint: "http://oss-cn-shanghai.aliyuncs.com"
bucket: "ta-tech-image"
connect_timeout: 30
vod:
host_address: "https://vod.play.t-aaron.com/"
ecsRegionId: "cn-shanghai"
cateId: 1000468338

View File

@ -0,0 +1,11 @@
access_key: "LTAI5tFmaJHU7ywvBH2j12Gp"
access_secret: "mX6rS1xYTgZgFAgpOrQHyc6jLXv0AV"
oss:
endpoint: "http://oss-cn-shanghai.aliyuncs.com"
bucket: "ta-tech-image"
connect_timeout: 30
vod:
host_address: "https://vod.play.t-aaron.com/"
ecsRegionId: "cn-shanghai"
cateId: 1000468338

View File

@ -0,0 +1,12 @@
orc:
APP_ID: 28173504
API_KEY: "kqrFE7VuygIaFer7z6cRxzoi"
SECRET_KEY: "yp7xBokyl4TItyGhay7skAN1cMwfvEXf"
vehicle:
APP_ID: 31096670
API_KEY: "Dam3O4tgPRN3qh4OYE82dbg7"
SECRET_KEY: "1PGZ9LAXRR5zcT5MN9rHcW8kLBIS5DAa"
person:
APP_ID: 31096755
API_KEY: "CiWrt4iyxOly36n3kR7utiAG"
SECRET_KEY: "K7y6V3XTGdyXvgtCNCwTGUEooxxDuX9v"

View File

@ -0,0 +1,12 @@
orc:
APP_ID: 28173504
API_KEY: "kqrFE7VuygIaFer7z6cRxzoi"
SECRET_KEY: "yp7xBokyl4TItyGhay7skAN1cMwfvEXf"
vehicle:
APP_ID: 31096670
API_KEY: "Dam3O4tgPRN3qh4OYE82dbg7"
SECRET_KEY: "1PGZ9LAXRR5zcT5MN9rHcW8kLBIS5DAa"
person:
APP_ID: 31096755
API_KEY: "CiWrt4iyxOly36n3kR7utiAG"
SECRET_KEY: "K7y6V3XTGdyXvgtCNCwTGUEooxxDuX9v"

View File

@ -0,0 +1,12 @@
orc:
APP_ID: 28173504
API_KEY: "kqrFE7VuygIaFer7z6cRxzoi"
SECRET_KEY: "yp7xBokyl4TItyGhay7skAN1cMwfvEXf"
vehicle:
APP_ID: 31096670
API_KEY: "Dam3O4tgPRN3qh4OYE82dbg7"
SECRET_KEY: "1PGZ9LAXRR5zcT5MN9rHcW8kLBIS5DAa"
person:
APP_ID: 31096755
API_KEY: "CiWrt4iyxOly36n3kR7utiAG"
SECRET_KEY: "K7y6V3XTGdyXvgtCNCwTGUEooxxDuX9v"

View File

@ -0,0 +1,25 @@
bootstrap_servers: ["192.168.11.13:9092"]
topic:
dsp-alg-online-tasks-topic: "dsp-alg-online-tasks"
dsp-alg-offline-tasks-topic: "dsp-alg-offline-tasks"
dsp-alg-image-tasks-topic: "dsp-alg-image-tasks"
dsp-alg-results-topic: "dsp-alg-task-results"
dsp-recording-task-topic: "dsp-recording-task"
dsp-recording-result-topic: "dsp-recording-result"
dsp-push-stream-task-topic: "dsp-push-stream-task"
dsp-push-stream-result-topic: "dsp-push-stream-result"
producer:
acks: -1
retries: 3
linger_ms: 50
retry_backoff_ms: 1000
max_in_flight_requests_per_connection: 5
consumer:
client_id: "dsp_ai_server"
group_id: "dsp-ai-dev"
auto_offset_reset: "latest"
enable_auto_commit: false
max_poll_records: 1

View File

@ -0,0 +1,22 @@
bootstrap_servers: ["101.132.127.1:19094"]
topic:
dsp-alg-online-tasks-topic: "dsp-alg-online-tasks"
dsp-alg-offline-tasks-topic: "dsp-alg-offline-tasks"
dsp-alg-image-tasks-topic: "dsp-alg-image-tasks"
dsp-alg-results-topic: "dsp-alg-task-results"
dsp-recording-task-topic: "dsp-recording-task"
dsp-recording-result-topic: "dsp-recording-result"
dsp-push-stream-task-topic: "dsp-push-stream-task"
dsp-push-stream-result-topic: "dsp-push-stream-result"
producer:
acks: -1
retries: 3
linger_ms: 50
retry_backoff_ms: 1000
max_in_flight_requests_per_connection: 5
consumer:
client_id: "dsp_ai_server"
group_id: "dsp-ai-prod"
auto_offset_reset: "latest"
enable_auto_commit: false
max_poll_records: 1

View File

@ -0,0 +1,34 @@
bootstrap_servers: ["106.14.96.218:19092"]
topicGPU: "server-status"
topicPort:
dsp-alg-online-tasks-topic: "dsp-alg-online-tasks"
dsp-alg-offline-tasks-topic: "dsp-alg-offline-tasks"
dsp-alg-image-tasks-topic: "dsp-alg-image-tasks"
dsp-alg-results-topic: "dsp-alg-task-results"
dsp-recording-task-topic: "dsp-recording-task"
dsp-recording-result-topic: "dsp-recording-result"
dsp-push-stream-task-topic: "dsp-push-stream-task"
dsp-push-stream-result-topic: "dsp-push-stream-result"
topic:
dsp-alg-online-tasks-topic: "dsp-alg-online-tasks-192.168.11.7"
dsp-alg-offline-tasks-topic: "dsp-alg-offline-tasks-192.168.11.7"
dsp-alg-image-tasks-topic: "dsp-alg-image-tasks-192.168.11.7"
dsp-alg-results-topic: "dsp-alg-task-results"
dsp-recording-task-topic: "dsp-recording-task-192.168.11.7"
dsp-recording-result-topic: "dsp-recording-result"
dsp-push-stream-task-topic: "dsp-push-stream-task-192.168.11.7"
dsp-push-stream-result-topic: "dsp-push-stream-result"
producer:
acks: -1
retries: 3
linger_ms: 50
retry_backoff_ms: 1000
max_in_flight_requests_per_connection: 5
consumer:
client_id: "dsp_ai_server"
group_id: "dsp-ai-test"
auto_offset_reset: "latest"
enable_auto_commit: false
max_poll_records: 1

View File

@ -0,0 +1,10 @@
enable_file_log: true
enable_stderr: true
base_path: "../dsp/logs"
log_name: "dsp.log"
log_fmt: "{time:YYYY-MM-DD HH:mm:ss.SSS} [{level}][{process.name}-{process.id}-{thread.name}-{thread.id}][{line}] {module}-{function} - {message}"
level: "INFO"
rotation: "00:00"
retention: "1 days"
encoding: "utf8"

View File

@ -0,0 +1,10 @@
enable_file_log: true
enable_stderr: false
base_path: "../dsp/logs"
log_name: "dsp.log"
log_fmt: "{time:YYYY-MM-DD HH:mm:ss.SSS} [{level}][{process.name}-{process.id}-{thread.name}-{thread.id}][{line}] {module}-{function} - {message}"
level: "INFO"
rotation: "00:00"
retention: "15 days"
encoding: "utf8"

View File

@ -0,0 +1,10 @@
enable_file_log: true
enable_stderr: false
base_path: "../dsp/logs"
log_name: "dsp.log"
log_fmt: "{time:YYYY-MM-DD HH:mm:ss.SSS} [{level}][{process.name}-{process.id}-{thread.name}-{thread.id}][{line}] {module}-{function} - {message}"
level: "INFO"
rotation: "00:00"
retention: "7 days"
encoding: "utf8"

View File

@ -0,0 +1,7 @@
endpoint: 'minio.t-aaron.com:9000'
domain: 'https://minio.t-aaron.com'
access_key: 'IKf3A0ZSXsR1m0oalMjV'
secret_key: 'yoC6qRo2hlyZu8Pdbt6eh9TVaTV4gD7KRudromrk'
secure: false
image_bucket: 'image'
video_bucket: 'video'

View File

@ -0,0 +1,8 @@
endpoint: 'minio-jndsj.t-aaron.com:2443'
domain: 'https://minio-jndsj.t-aaron.com:2443'
access_key: 'PJM0c2qlauoXv5TMEHm2'
secret_key: 'Wr69Dm3ZH39M3GCSeyB3eFLynLPuGCKYfphixZuI'
secure: true
image_bucket: 'image'
video_bucket: 'video'

View File

@ -0,0 +1,10 @@
mqtt_flag: true
broker : "58.213.148.44"
port : 1883
username: "admin"
password: "admin##123"
#topic: "/topic/v1/airportFly/%s/aiDroneData"
topic: "/topic/v1/airportDrone/THJSQ03B2309TPCTD5QV/realTime/data"
# 存储多少条消息到list里
length: 10

View File

@ -0,0 +1,30 @@
video:
# 视频本地保存地址
file_path: "../dsp/video/"
# 是否添加水印
video_add_water: false
service:
filter:
# 图片得分多少分以上返回图片
frame_score: 0.4
# 图片相似度过滤
picture_similarity: true
similarity: 0.65
frame_step: 160
timeout: 21600
cv2_pull_stream_timeout: 1000
cv2_read_stream_timeout: 1000
recording_pull_stream_timeout: 600
model:
# 使用哪种识别方式
# 1 普通方式
# 2 模型追踪
model_type: 1
limit: 3
task:
# 任务限制5个
limit: 5
image:
limit: 20

View File

@ -0,0 +1,29 @@
video:
# 视频本地保存地址
file_path: "../dsp/video/"
# 是否添加水印
video_add_water: false
service:
filter:
# 图片得分多少分以上返回图片
frame_score: 0.4
# 图片相似度过滤
picture_similarity: true
similarity: 0.65
frame_step: 160
timeout: 21600
cv2_pull_stream_timeout: 1000
cv2_read_stream_timeout: 1000
recording_pull_stream_timeout: 600
model:
# 使用哪种识别方式
# 1 普通方式
# 2 模型追踪
model_type: 1
limit: 3
task:
# 任务限制5个
limit: 5
image:
limit: 20

View File

@ -0,0 +1,39 @@
video:
# 视频本地保存地址
file_path: "../dsp/video/"
# 是否添加水印
video_add_water: false
#0-slave,1--master
role : 1
#gpu信息上报间隔
GPUpollInterval: 2
service:
filter:
# 图片得分多少分以上返回图片
frame_score: 0.4
# 图片相似度过滤
picture_similarity: true
similarity: 0.65
frame_step: 160
timeout: 21600
cv2_pull_stream_timeout: 1000
cv2_read_stream_timeout: 1000
recording_pull_stream_timeout: 600
model:
# 使用哪种识别方式
# 1 普通方式
# 2 模型追踪
model_type: 1
limit: 3
task:
# 任务限制5个
limit: 5
image:
limit: 20
#storage source,0--aliyun,1--minio
storage_source: 0
#是否启用mqtt0--不用1--启用
mqtt_flag: 0
#是否启用alg控制功能
algSwitch: False

26
dsp_master.py Normal file
View File

@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
from os.path import dirname, realpath
from sys import argv
from loguru import logger
from torch import multiprocessing
from service.Dispatcher import DispatcherService
from util.LogUtils import init_log
'''
dsp主程序入口
'''
if __name__ == '__main__':
multiprocessing.set_start_method('spawn')
base_dir = dirname(realpath(__file__))
arg = argv
print("脚本启动参数: ", arg)
envs = ('dev', 'test', 'prod')
env = envs[0]
active = [env for env in envs if env in arg]
if len(active) != 0:
env = active[0]
init_log(base_dir, env)
logger.info("(♥◠‿◠)ノ゙ DSP【算法调度服务】开始启动 ლ(´ڡ`ლ)゙")
DispatcherService(base_dir, env)

55
entity/FeedBack.py Normal file
View File

@ -0,0 +1,55 @@
from json import dumps
from util.TimeUtils import now_date_to_str
def message_feedback(requestId, status, analyse_type, error_code="", error_msg="", progress="", original_url="",
sign_url="", modelCode="", detectTargetCode="", analyse_results="", video_url="", ai_video_url="",longitude="",latitude=""):
if len(analyse_results) > 0:
analyse_results = dumps(analyse_results)
taskbar = {
"request_id": requestId,
"status": status,
"type": analyse_type,
"video_url": video_url,
"ai_video_url": ai_video_url,
"error_code": error_code,
"error_msg": error_msg,
"progress": progress,
"results": [
{
"original_url": original_url,
"sign_url": sign_url,
"analyse_results": analyse_results,
"model_code": modelCode,
"detect_targets_code": detectTargetCode,
"analyse_time": now_date_to_str(),
"longitude":str(longitude),
"latitude":str(latitude),
}
]
}
return {"feedback": taskbar}
def recording_feedback(requestId, status, error_code="", error_msg="", progress="", video_url=""):
rdf = {
"request_id": requestId,
"status": status,
"error_code": error_code,
"error_msg": error_msg,
"progress": progress,
"video_url": video_url
}
return {"recording": rdf}
def pull_stream_feedback(requestId, status, error_code="", error_msg="", videoInfo=[]):
return {"pull_stream": {
"request_id": requestId,
"video_info_list": videoInfo,
"push_stream_status": status,
"error_code": error_code,
"error_msg": error_msg,
"current_time": now_date_to_str()
}}

14
entity/PullStreamDto.py Normal file
View File

@ -0,0 +1,14 @@
class PullStreamDto:
__slots__ = ('msg', 'context', 'pullQueue', 'fbQueue', 'hbQueue', 'imageQueue', 'analyse_type')
def __init__(self, msg, context, pullQueue, fbQueue, hbQueue, imageQueue, analyse_type):
self.msg = msg
self.context = context
self.pullQueue = pullQueue
self.fbQueue = fbQueue
self.hbQueue = hbQueue
self.imageQueue = imageQueue
self.analyse_type = analyse_type

0
entity/__init__.py Normal file
View File

View File

@ -0,0 +1,21 @@
from enum import Enum, unique
# 分析状态枚举
@unique
class AnalysisStatus(Enum):
# 等待
WAITING = "waiting"
# 分析中
RUNNING = "running"
# 分析完成
SUCCESS = "success"
# 超时
TIMEOUT = "timeout"
# 失败
FAILED = "failed"

25
enums/AnalysisTypeEnum.py Normal file
View File

@ -0,0 +1,25 @@
from enum import Enum, unique
# 分析类型枚举
@unique
class AnalysisType(Enum):
# 在线
ONLINE = "1"
# 离线
OFFLINE = "2"
# 图片
IMAGE = "3"
# 录屏
RECORDING = "9999"
# 转推流
PULLTOPUSH = "10000"

188
enums/BaiduSdkEnum.py Normal file
View File

@ -0,0 +1,188 @@
from enum import Enum, unique
'''
ocr官方文档: https://ai.baidu.com/ai-doc/OCR/zkibizyhz
官方文档: https://ai.baidu.com/ai-doc/VEHICLE/rk3inf9tj
参数1: 异常编号
参数2: 异常英文描述
参数3: 异常中文描述
参数4: 0-异常信息统一输出为内部异常
1-异常信息可以输出
2-输出空的异常信息
参数5: 指定异常重试的次数
'''
# 异常枚举
@unique
class BaiduSdkErrorEnum(Enum):
UNKNOWN_ERROR = (1, "Unknown error", "未知错误", 0, 0)
SERVICE_TEMPORARILY_UNAVAILABLE = (2, "Service temporarily unavailable", "服务暂不可用,请再次请求", 0, 3)
UNSUPPORTED_OPENAPI_METHOD = (3, "Unsupported openapi method", "调用的API不存在", 0, 0)
API_REQUEST_LIMIT_REACHED = (4, "Open api request limit reached", "请求量限制, 请稍后再试!", 1, 5)
NO_PERMISSION_TO_ACCESS_DATA = (6, "No permission to access data", "无权限访问该用户数据", 1, 0)
GET_SERVICE_TOKEN_FAILED = (13, "Get service token failed", "获取token失败", 0, 2)
IAM_CERTIFICATION_FAILED = (14, "IAM Certification failed", "IAM 鉴权失败", 0, 1)
APP_NOT_EXSITS_OR_CREATE_FAILED = (15, "app not exsits or create failed", "应用不存在或者创建失败", 0, 0)
API_DAILY_REQUEST_LIMIT_REACHED = (17, "Open api daily request limit reached", "每天请求量超限额!", 1, 2)
API_QPS_REQUEST_LIMIT_REACHED = (18, "Open api qps request limit reached", "QPS超限额!", 1, 10)
API_TOTAL_REQUEST_LIMIT_REACHED = (19, "Open api total request limit reached", "请求总量超限额!", 1, 2)
INVALID_TOKEN = (100, "Invalid parameter", "无效的access_token参数token拉取失败", 0, 1)
ACCESS_TOKEN_INVALID_OR_NO_LONGER_VALID = (110, "Access token invalid or no longer valid", "access_token无效token有效期为30天", 0, 1)
ACCESS_TOKEN_EXPIRED = (111, "Access token expired", "access token过期token有效期为30天", 0, 1)
INTERNAL_ERROR = (282000, "internal error", "服务器内部错误", 0, 1)
INVALID_PARAM = (216100, "invalid param", "请求中包含非法参数!", 0, 1)
NOT_ENOUGH_PARAM = (216101, "not enough param", "缺少必须的参数!", 0, 0)
SERVICE_NOT_SUPPORT = (216102, "service not support", "请求了不支持的服务请检查调用的url", 0, 0)
PARAM_TOO_LONG = (216103, "param too long", "请求中某些参数过长!", 1, 0)
APPID_NOT_EXIST = (216110, "appid not exist", "appid不存在", 0, 0)
EMPTY_IMAGE = (216200, "empty image", "图片为空!", 1, 0)
IMAGE_FORMAT_ERROR = (216201, "image format error", "上传的图片格式错误现阶段我们支持的图片格式为PNG、JPG、JPEG、BMP", 1, 0)
IMAGE_SIZE_ERROR = (216202, "image size error", "上传的图片大小错误分辨率不高于4096*4096", 1, 0)
IMAGE_SIZE_BASE_ERROR = (216203, "image size error", "上传的图片编码有误", 1, 0)
RECOGNIZE_ERROR = (216630, "recognize error", "识别错误", 2, 2)
DETECT_ERROR = (216634, "detect error", "检测错误", 2, 2)
MISSING_PARAMETERS = (282003, "missing parameters: {参数名}", "请求参数缺失", 0, 0)
BATCH_ROCESSING_ERROR = (282005, "batch processing error", "处理批量任务时发生部分或全部错误", 0, 5)
BATCH_TASK_LIMIT_REACHED = (282006, "batch task limit reached", "批量任务处理数量超出限制请将任务数量减少到10或10以下", 1, 5)
IMAGE_TRANSCODE_ERROR = (282100, "image transcode error", "图片压缩转码错误", 0, 1)
IMAGE_SPLIT_LIMIT_REACHED = (282101, "image split limit reached", "长图片切分数量超限!", 1, 1)
TARGET_DETECT_ERROR = (282102, "target detect error", "未检测到图片中识别目标!", 2, 1)
TARGET_RECOGNIZE_ERROR = (282103, "target recognize error", "图片目标识别错误!", 2, 1)
URLS_NOT_EXIT = (282110, "urls not exit", "URL参数不存在请核对URL后再次提交!", 1, 0)
URL_FORMAT_ILLEGAL = (282111, "url format illegal", "URL格式非法!", 1, 0)
URL_DOWNLOAD_TIMEOUT = (282112, "url download timeout", "URL格式非法!", 1, 0)
URL_RESPONSE_INVALID = (282113, "url response invalid", "URL返回无效参数!", 1, 0)
URL_SIZE_ERROR = (282114, "url size error", "URL长度超过1024字节或为0!", 1, 0)
REQUEST_ID_NOT_EXIST = (282808, "request id: xxxxx not exist", "request id xxxxx 不存在", 0, 0)
RESULT_TYPE_ERROR = (282809, "result type error", "返回结果请求错误不属于excel或json", 0, 0)
IMAGE_RECOGNIZE_ERROR = (282810, "image recognize error", "图像识别错误", 2, 1)
INVALID_ARGUMENT = (283300, "Invalid argument", "入参格式有误,可检查下图片编码、代码格式是否有误", 1, 0)
INTERNAL_ERROR_2 = (336000, "Internal error", "服务器内部错误", 0, 0)
INVALID_ARGUMENT_2 = (336001, "Invalid Argument", "入参格式有误,比如缺少必要参数、图片编码错误等等,可检查下图片编码、代码格式是否有误", 0, 0)
SDK_IMAGE_SIZE_ERROR = ('SDK100', "image size error", "图片大小超限最短边至少50px最长边最大4096px 建议长宽比31以内图片请求格式支持PNG、JPG、BMP", 1, 0)
SDK_IMAGE_LENGTH_ERROR = ('SDK101', "image length error", "图片边长不符合要求最短边至少50px最长边最大4096px 建议长宽比31以内", 1, 0)
SDK_READ_IMAGE_FILE_ERROR = ('SDK102', "read image file error", "读取图片文件错误", 0, 1)
SDK_CONNECTION_OR_READ_DATA_TIME_OUT = ('SDK108', "connection or read data time out", "连接超时或读取数据超时,请检查本地网络设置、文件读取设置", 0, 3)
SDK_UNSUPPORTED_IMAGE_FORMAT = ('SDK109', "unsupported image format", "不支持的图片格式当前支持以下几类图片PNG、JPG、BMP", 1, 0)
BAIDUERRORDATA = {
BaiduSdkErrorEnum.UNKNOWN_ERROR.value[0]: BaiduSdkErrorEnum.UNKNOWN_ERROR,
BaiduSdkErrorEnum.SERVICE_TEMPORARILY_UNAVAILABLE.value[0]: BaiduSdkErrorEnum.SERVICE_TEMPORARILY_UNAVAILABLE,
BaiduSdkErrorEnum.UNSUPPORTED_OPENAPI_METHOD.value[0]: BaiduSdkErrorEnum.UNSUPPORTED_OPENAPI_METHOD,
BaiduSdkErrorEnum.API_REQUEST_LIMIT_REACHED.value[0]: BaiduSdkErrorEnum.API_REQUEST_LIMIT_REACHED,
BaiduSdkErrorEnum.NO_PERMISSION_TO_ACCESS_DATA.value[0]: BaiduSdkErrorEnum.NO_PERMISSION_TO_ACCESS_DATA,
BaiduSdkErrorEnum.GET_SERVICE_TOKEN_FAILED.value[0]: BaiduSdkErrorEnum.GET_SERVICE_TOKEN_FAILED,
BaiduSdkErrorEnum.IAM_CERTIFICATION_FAILED.value[0]: BaiduSdkErrorEnum.IAM_CERTIFICATION_FAILED,
BaiduSdkErrorEnum.APP_NOT_EXSITS_OR_CREATE_FAILED.value[0]: BaiduSdkErrorEnum.APP_NOT_EXSITS_OR_CREATE_FAILED,
BaiduSdkErrorEnum.API_DAILY_REQUEST_LIMIT_REACHED.value[0]: BaiduSdkErrorEnum.API_DAILY_REQUEST_LIMIT_REACHED,
BaiduSdkErrorEnum.API_QPS_REQUEST_LIMIT_REACHED.value[0]: BaiduSdkErrorEnum.API_QPS_REQUEST_LIMIT_REACHED,
BaiduSdkErrorEnum.API_TOTAL_REQUEST_LIMIT_REACHED.value[0]: BaiduSdkErrorEnum.API_TOTAL_REQUEST_LIMIT_REACHED,
BaiduSdkErrorEnum.INVALID_TOKEN.value[0]: BaiduSdkErrorEnum.INVALID_TOKEN,
BaiduSdkErrorEnum.ACCESS_TOKEN_INVALID_OR_NO_LONGER_VALID.value[0]: BaiduSdkErrorEnum.ACCESS_TOKEN_INVALID_OR_NO_LONGER_VALID,
BaiduSdkErrorEnum.ACCESS_TOKEN_EXPIRED.value[0]: BaiduSdkErrorEnum.ACCESS_TOKEN_EXPIRED,
BaiduSdkErrorEnum.INTERNAL_ERROR.value[0]: BaiduSdkErrorEnum.INTERNAL_ERROR,
BaiduSdkErrorEnum.INVALID_PARAM.value[0]: BaiduSdkErrorEnum.INVALID_PARAM,
BaiduSdkErrorEnum.NOT_ENOUGH_PARAM.value[0]: BaiduSdkErrorEnum.NOT_ENOUGH_PARAM,
BaiduSdkErrorEnum.SERVICE_NOT_SUPPORT.value[0]: BaiduSdkErrorEnum.SERVICE_NOT_SUPPORT,
BaiduSdkErrorEnum.PARAM_TOO_LONG.value[0]: BaiduSdkErrorEnum.PARAM_TOO_LONG,
BaiduSdkErrorEnum.APPID_NOT_EXIST.value[0]: BaiduSdkErrorEnum.APPID_NOT_EXIST,
BaiduSdkErrorEnum.EMPTY_IMAGE.value[0]: BaiduSdkErrorEnum.EMPTY_IMAGE,
BaiduSdkErrorEnum.IMAGE_FORMAT_ERROR.value[0]: BaiduSdkErrorEnum.IMAGE_FORMAT_ERROR,
BaiduSdkErrorEnum.IMAGE_SIZE_ERROR.value[0]: BaiduSdkErrorEnum.IMAGE_SIZE_ERROR,
BaiduSdkErrorEnum.IMAGE_SIZE_BASE_ERROR.value[0]: BaiduSdkErrorEnum.IMAGE_SIZE_BASE_ERROR,
BaiduSdkErrorEnum.RECOGNIZE_ERROR.value[0]: BaiduSdkErrorEnum.RECOGNIZE_ERROR,
BaiduSdkErrorEnum.DETECT_ERROR.value[0]: BaiduSdkErrorEnum.DETECT_ERROR,
BaiduSdkErrorEnum.MISSING_PARAMETERS.value[0]: BaiduSdkErrorEnum.MISSING_PARAMETERS,
BaiduSdkErrorEnum.BATCH_ROCESSING_ERROR.value[0]: BaiduSdkErrorEnum.BATCH_ROCESSING_ERROR,
BaiduSdkErrorEnum.BATCH_TASK_LIMIT_REACHED.value[0]: BaiduSdkErrorEnum.BATCH_TASK_LIMIT_REACHED,
BaiduSdkErrorEnum.IMAGE_TRANSCODE_ERROR.value[0]: BaiduSdkErrorEnum.IMAGE_TRANSCODE_ERROR,
BaiduSdkErrorEnum.IMAGE_SPLIT_LIMIT_REACHED.value[0]: BaiduSdkErrorEnum.IMAGE_SPLIT_LIMIT_REACHED,
BaiduSdkErrorEnum.TARGET_DETECT_ERROR.value[0]: BaiduSdkErrorEnum.TARGET_DETECT_ERROR,
BaiduSdkErrorEnum.TARGET_RECOGNIZE_ERROR.value[0]: BaiduSdkErrorEnum.TARGET_RECOGNIZE_ERROR,
BaiduSdkErrorEnum.URL_SIZE_ERROR.value[0]: BaiduSdkErrorEnum.URL_SIZE_ERROR,
BaiduSdkErrorEnum.REQUEST_ID_NOT_EXIST.value[0]: BaiduSdkErrorEnum.REQUEST_ID_NOT_EXIST,
BaiduSdkErrorEnum.RESULT_TYPE_ERROR.value[0]: BaiduSdkErrorEnum.RESULT_TYPE_ERROR,
BaiduSdkErrorEnum.IMAGE_RECOGNIZE_ERROR.value[0]: BaiduSdkErrorEnum.IMAGE_RECOGNIZE_ERROR,
BaiduSdkErrorEnum.INVALID_ARGUMENT.value[0]: BaiduSdkErrorEnum.INVALID_ARGUMENT,
BaiduSdkErrorEnum.INTERNAL_ERROR_2.value[0]: BaiduSdkErrorEnum.INTERNAL_ERROR_2,
BaiduSdkErrorEnum.INVALID_ARGUMENT_2.value[0]: BaiduSdkErrorEnum.INVALID_ARGUMENT_2,
BaiduSdkErrorEnum.SDK_IMAGE_SIZE_ERROR.value[0]: BaiduSdkErrorEnum.SDK_IMAGE_SIZE_ERROR,
BaiduSdkErrorEnum.SDK_IMAGE_LENGTH_ERROR.value[0]: BaiduSdkErrorEnum.SDK_IMAGE_LENGTH_ERROR,
BaiduSdkErrorEnum.SDK_READ_IMAGE_FILE_ERROR.value[0]: BaiduSdkErrorEnum.SDK_READ_IMAGE_FILE_ERROR,
BaiduSdkErrorEnum.SDK_CONNECTION_OR_READ_DATA_TIME_OUT.value[0]: BaiduSdkErrorEnum.SDK_CONNECTION_OR_READ_DATA_TIME_OUT,
BaiduSdkErrorEnum.SDK_UNSUPPORTED_IMAGE_FORMAT.value[0]: BaiduSdkErrorEnum.SDK_UNSUPPORTED_IMAGE_FORMAT,
BaiduSdkErrorEnum.URLS_NOT_EXIT.value[0]: BaiduSdkErrorEnum.URLS_NOT_EXIT,
BaiduSdkErrorEnum.URL_FORMAT_ILLEGAL.value[0]: BaiduSdkErrorEnum.URL_FORMAT_ILLEGAL,
BaiduSdkErrorEnum.URL_DOWNLOAD_TIMEOUT.value[0]: BaiduSdkErrorEnum.URL_DOWNLOAD_TIMEOUT,
BaiduSdkErrorEnum.URL_RESPONSE_INVALID.value[0]: BaiduSdkErrorEnum.URL_RESPONSE_INVALID
}
@unique
class VehicleEnum(Enum):
CAR = ("car", "小汽车", 0)
TRICYCLE = ("tricycle", "三轮车", 1)
MOTORBIKE = ("motorbike", "摩托车", 2)
CARPLATE = ("carplate", "车牌", 3)
TRUCK = ("truck", "卡车", 4)
BUS = ("bus", "巴士", 5)
VehicleEnumVALUE={
VehicleEnum.CAR.value[0]: VehicleEnum.CAR,
VehicleEnum.TRICYCLE.value[0]: VehicleEnum.TRICYCLE,
VehicleEnum.MOTORBIKE.value[0]: VehicleEnum.MOTORBIKE,
VehicleEnum.CARPLATE.value[0]: VehicleEnum.CARPLATE,
VehicleEnum.TRUCK.value[0]: VehicleEnum.TRUCK,
VehicleEnum.BUS.value[0]: VehicleEnum.BUS
}

86
enums/ExceptionEnum.py Normal file
View File

@ -0,0 +1,86 @@
from enum import Enum, unique
# 异常枚举
@unique
class ExceptionType(Enum):
OR_VIDEO_ADDRESS_EXCEPTION = ("SP000", "未拉取到视频流, 请检查拉流地址是否有视频流!")
ANALYSE_TIMEOUT_EXCEPTION = ("SP001", "AI分析超时!")
PULLSTREAM_TIMEOUT_EXCEPTION = ("SP002", "原视频拉流超时!")
READSTREAM_TIMEOUT_EXCEPTION = ("SP003", "原视频读取视频流超时!")
GET_VIDEO_URL_EXCEPTION = ("SP004", "获取视频播放地址失败!")
GET_VIDEO_URL_TIMEOUT_EXCEPTION = ("SP005", "获取原视频播放地址超时!")
PULL_STREAM_URL_EXCEPTION = ("SP006", "拉流地址不能为空!")
PUSH_STREAM_URL_EXCEPTION = ("SP007", "推流地址不能为空!")
PUSH_STREAM_TIME_EXCEPTION = ("SP008", "未生成本地视频地址!")
AI_MODEL_MATCH_EXCEPTION = ("SP009", "未匹配到对应的AI模型!")
ILLEGAL_PARAMETER_FORMAT = ("SP010", "非法参数格式!")
PUSH_STREAMING_CHANNEL_IS_OCCUPIED = ("SP011", "推流通道可能被占用, 请稍后再试!")
VIDEO_RESOLUTION_EXCEPTION = ("SP012", "不支持该分辨率类型的视频,请切换分辨率再试!")
READ_IAMGE_URL_EXCEPTION = ("SP013", "未能解析图片地址!")
DETECTION_TARGET_TYPES_ARE_NOT_SUPPORTED = ("SP014", "不支持该类型的检测目标!")
WRITE_STREAM_EXCEPTION = ("SP015", "写流异常!")
OR_VIDEO_DO_NOT_EXEIST_EXCEPTION = ("SP016", "原视频不存在!")
MODEL_LOADING_EXCEPTION = ("SP017", "模型加载异常!")
MODEL_ANALYSE_EXCEPTION = ("SP018", "算法模型分析异常!")
AI_MODEL_CONFIG_EXCEPTION = ("SP019", "模型配置不能为空!")
AI_MODEL_GET_CONFIG_EXCEPTION = ("SP020", "获取模型配置异常, 请检查模型配置是否正确!")
MODEL_GROUP_LIMIT_EXCEPTION = ("SP021", "模型组合个数超过限制!")
MODEL_NOT_SUPPORT_VIDEO_EXCEPTION = ("SP022", "%s不支持视频识别!")
MODEL_NOT_SUPPORT_IMAGE_EXCEPTION = ("SP023", "%s不支持图片识别!")
THE_DETECTION_TARGET_CANNOT_BE_EMPTY = ("SP024", "检测目标不能为空!")
URL_ADDRESS_ACCESS_FAILED = ("SP025", "URL地址访问失败, 请检测URL地址是否正确!")
UNIVERSAL_TEXT_RECOGNITION_FAILED = ("SP026", "识别失败!")
COORDINATE_ACQUISITION_FAILED = ("SP027", "飞行坐标识别异常!")
PUSH_STREAM_EXCEPTION = ("SP028", "推流异常!")
MODEL_DUPLICATE_EXCEPTION = ("SP029", "存在重复模型配置!")
DETECTION_TARGET_NOT_SUPPORT = ("SP031", "存在不支持的检测目标!")
TASK_EXCUTE_TIMEOUT = ("SP032", "任务执行超时!")
PUSH_STREAM_URL_IS_NULL = ("SP033", "拉流、推流地址不能为空!")
PULL_STREAM_NUM_LIMIT_EXCEPTION = ("SP034", "转推流数量超过限制!")
NOT_REQUESTID_TASK_EXCEPTION = ("SP993", "未查询到该任务,无法停止任务!")
NO_RESOURCES = ("SP995", "服务器暂无资源可以使用请稍后30秒后再试!")
NO_CPU_RESOURCES = ("SP996", "暂无CPU资源可以使用请稍后再试!")
SERVICE_COMMON_EXCEPTION = ("SP997", "公共服务异常!")
NO_GPU_RESOURCES = ("SP998", "暂无GPU资源可以使用请稍后再试!")
SERVICE_INNER_EXCEPTION = ("SP999", "系统内部异常!")

768
enums/ModelTypeEnum-jcq.py Normal file
View File

@ -0,0 +1,768 @@
import sys
from enum import Enum, unique
from common.Constant import COLOR
sys.path.extend(['..', '../AIlib2'])
from DMPR import DMPRModel
from DMPRUtils.jointUtil import dmpr_yolo
from segutils.segmodel import SegModel
from utilsK.queRiver import riverDetSegMixProcess
from utilsK.crowdGather import gather_post_process
from segutils.trafficUtils import tracfficAccidentMixFunction
from utilsK.drownUtils import mixDrowing_water_postprocess
from utilsK.noParkingUtils import mixNoParking_road_postprocess
from utilsK.illParkingUtils import illParking_postprocess
from stdc import stdcModel
from yolov5 import yolov5Model
from DMPRUtils.jointUtil import dmpr_yolo_stdc
from AI import default_mix
from ocr import ocrModel
from utilsK.channel2postUtils import channel2_post_process
'''
参数说明
1. 编号
2. 模型编号
3. 模型名称
4. 选用的模型名称
5. 模型配置
6. 模型引用配置[Detweights文件, Segweights文件, 引用计数]
'''
@unique
class ModelType(Enum):
WATER_SURFACE_MODEL = ("1", "001", "河道模型", 'river', lambda device, gpuName: {
'device': device,
'labelnames': ["排口", "水生植被", "其它", "漂浮物", "污染排口", "菜地", "违建", "岸坡垃圾"],
'seg_nclass': 2,
'trtFlag_seg': True,
'trtFlag_det': True,
'segRegionCnt': 1,
'segPar': {
'modelSize': (640, 360),
'mean': (0.485, 0.456, 0.406),
'std': (0.229, 0.224, 0.225),
'numpy': False,
'RGB_convert_first': True,
'mixFunction': {
'function': riverDetSegMixProcess,
'pars': {
'slopeIndex': [5, 6, 7],
'riverIou': 0.1
}
}
},
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'Detweights': "../AIlib2/weights/river/yolov5_%s_fp16.engine" % gpuName,
'Segweights': '../AIlib2/weights/river/stdc_360X640_%s_fp16.engine' % gpuName
})
# FOREST_FARM_MODEL = ("2", "002", "森林模型", 'forest2', lambda device, gpuName: {
# 'device': device,
# 'gpu_name': gpuName,
# 'labelnames': ["林斑", "病死树", "行人", "火焰", "烟雾","云朵"],
# 'trtFlag_det': True,
# 'trtFlag_seg': False,
# 'Detweights': "../AIlib2/weights/forest2/yolov5_%s_fp16.engine" % gpuName,
# 'seg_nclass': 2,
# 'segRegionCnt': 0,
# 'slopeIndex': [],
# 'segPar': None,
# 'postFile': {
# "name": "post_process",
# "conf_thres": 0.25,
# "iou_thres": 0.45,
# "classes": 6,
# "rainbows": COLOR
# },
# 'Segweights': None
# })
FOREST_FARM_MODEL = ("2", "002", "森林模型", 'forest2', lambda device, gpuName: {
'labelnames': ["林斑", "病死树", "行人", "火焰", "烟雾","云朵"],
'postProcess':{'function':default_mix,'pars':{}},
'models':
[
{
'weight':"../AIlib2/weights/forest2/yolov5_%s_fp16.engine"%(gpuName),###检测模型路径
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,'device':'cuda:0' ,'conf_thres':0.25,'iou_thres':0.45,'allowedList':[0,1,2,3],'segRegionCnt':1, 'trtFlag_det':False,'trtFlag_seg':False, "score_byClass":{"0":0.25,"1":0.3,"2":0.3,"3":0.3 } },
}
],
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6,7,8,9] ],###控制哪些检测类别显示、输出
'segRegionCnt':2,###分割模型结果需要保留的等值线数目
"pixScale": 1.2,
})
TRAFFIC_FARM_MODEL = ("3", "003", "交通模型", 'highWay2', lambda device, gpuName: {
'device': str(device),
'labelnames': ["行人", "车辆", "纵向裂缝", "横向裂缝", "修补", "网状裂纹", "坑槽", "块状裂纹", "积水", "影子", "事故"],
'trtFlag_seg': True,
'trtFlag_det': True,
'seg_nclass': 3,
'segRegionCnt': 2,
'segPar': {
'modelSize': (640, 360),
'mean': (0.485, 0.456, 0.406),
'std': (0.229, 0.224, 0.225),
'predResize': True,
'numpy': False,
'RGB_convert_first': True,
'mixFunction': {
'function': tracfficAccidentMixFunction,
'pars': {
'modelSize': (640, 360),
#'modelSize': (1920,1080),
'RoadArea': 16000,
'roadVehicleAngle': 15,
'speedRoadVehicleAngleMax': 75,
'roundness': 1.0,
'cls': 9,
'vehicleFactor': 0.1,
'confThres': 0.25,
'roadIou': 0.6,
'radius': 50,
'vehicleFlag': False,
'distanceFlag': False
}
}
},
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.25,
"classes": 10,
"rainbows": COLOR
},
'Detweights': "../AIlib2/weights/highWay2/yolov5_%s_fp16.engine" % gpuName,
'Segweights': '../AIlib2/weights/highWay2/stdc_360X640_%s_fp16.engine' % gpuName
})
EPIDEMIC_PREVENTION_MODEL = ("4", "004", "防疫模型", None, None)
PLATE_MODEL = ("5", "005", "车牌模型", None, None)
VEHICLE_MODEL = ("6", "006", "车辆模型", 'vehicle', lambda device, gpuName: {
'device': device,
'gpu_name': gpuName,
'labelnames': ["车辆"],
'seg_nclass': 2,
'segRegionCnt': 0,
'slopeIndex': [],
'trtFlag_det': True,
'trtFlag_seg': False,
'Detweights': "../AIlib2/weights/vehicle/yolov5_%s_fp16.engine" % gpuName,
'segPar': None,
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'Segweights': None
})
PEDESTRIAN_MODEL = ("7", "007", "行人模型", 'pedestrian', lambda device, gpuName: {
'device': device,
'gpu_name': gpuName,
'labelnames': ["行人"],
'seg_nclass': 2,
'segRegionCnt': 0,
'trtFlag_det': True,
'trtFlag_seg': False,
'Detweights': "../AIlib2/weights/pedestrian/yolov5_%s_fp16.engine" % gpuName,
'slopeIndex': [],
'segPar': None,
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'Segweights': None
})
SMOGFIRE_MODEL = ("8", "008", "烟火模型", 'smogfire', lambda device, gpuName: {
'device': device,
'gpu_name': gpuName,
'labelnames': ["火焰", "烟雾"],
'seg_nclass': 2, # 分割模型类别数目默认2类
'segRegionCnt': 0,
'trtFlag_det': True,
'trtFlag_seg': False,
'Detweights': "../AIlib2/weights/smogfire/yolov5_%s_fp16.engine" % gpuName,
'slopeIndex': [],
'segPar': None,
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'Segweights': None
})
ANGLERSWIMMER_MODEL = ("9", "009", "钓鱼游泳模型", 'AnglerSwimmer', lambda device, gpuName: {
'device': device,
'gpu_name': gpuName,
'labelnames': ["钓鱼", "游泳"],
'seg_nclass': 2, # 分割模型类别数目默认2类
'segRegionCnt': 0,
'slopeIndex': [],
'trtFlag_det': True,
'trtFlag_seg': False,
'Detweights': "../AIlib2/weights/AnglerSwimmer/yolov5_%s_fp16.engine" % gpuName,
'segPar': None,
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'Segweights': None
})
COUNTRYROAD_MODEL = ("10", "010", "乡村模型", 'countryRoad', lambda device, gpuName: {
'device': device,
'gpu_name': gpuName,
'labelnames': ["违法种植"],
'seg_nclass': 2, # 分割模型类别数目默认2类
'segRegionCnt': 0,
'slopeIndex': [],
'trtFlag_det': True,
'trtFlag_seg': False,
'Detweights': "../AIlib2/weights/countryRoad/yolov5_%s_fp16.engine" % gpuName,
'segPar': None,
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'Segweights': None
})
SHIP_MODEL = ("11", "011", "船只模型", 'ship2', lambda device, gpuName: {
'model_size': (608, 608),
'K': 100,
'conf_thresh': 0.18,
'device': 'cuda:%s' % device,
'down_ratio': 4,
'num_classes': 15,
'weights': '../AIlib2/weights/ship2/obb_608X608_%s_fp16.engine' % gpuName,
'dataset': 'dota',
'half': False,
'mean': (0.5, 0.5, 0.5),
'std': (1, 1, 1),
'heads': {'hm': None, 'wh': 10, 'reg': 2, 'cls_theta': 1},
'decoder': None,
'test_flag': True,
"rainbows": COLOR,
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'drawBox': False,
'label_array': None,
'labelnames': ("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "船只"),
})
BAIDU_MODEL = ("12", "012", "百度AI图片识别模型", None, None)
CHANNEL_EMERGENCY_MODEL = ("13", "013", "航道模型", 'channelEmergency', lambda device, gpuName: {
'device': device,
'gpu_name': gpuName,
'labelnames': [""],
'seg_nclass': 2, # 分割模型类别数目默认2类
'segRegionCnt': 0,
'slopeIndex': [],
'trtFlag_det': True,
'trtFlag_seg': False,
'Detweights': "../AIlib2/weights/channelEmergency/yolov5_%s_fp16.engine" % gpuName,
'segPar': None,
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'Segweights': None
})
RIVER2_MODEL = ("15", "015", "河道检测模型", 'river2', lambda device, gpuName: {
'device': device,
'labelnames': ["漂浮物", "岸坡垃圾", "排口", "违建", "菜地", "水生植物", "河湖人员", "钓鱼人员", "船只",
"蓝藻"],
'trtFlag_seg': True,
'trtFlag_det': True,
'seg_nclass': 2,
'segRegionCnt': 1,
'segPar': {
'modelSize': (640, 360),
'mean': (0.485, 0.456, 0.406),
'std': (0.229, 0.224, 0.225),
'numpy': False,
'RGB_convert_first': True,
'mixFunction': {
'function': riverDetSegMixProcess,
'pars': {
'slopeIndex': [1, 3, 4, 7],
'riverIou': 0.1
}
}
},
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.3,
"ovlap_thres_crossCategory": 0.65,
"classes": 5,
"rainbows": COLOR
},
# "../AIlib2/weights/conf/%s/yolov5.pt" % modeType.value[3]
'Detweights': "../AIlib2/weights/river2/yolov5_%s_fp16.engine" % gpuName,
# '../AIlib2/weights/conf/%s/stdc_360X640.pth' % modeType.value[3]
'Segweights': '../AIlib2/weights/river2/stdc_360X640_%s_fp16.engine' % gpuName
})
CITY_MANGEMENT_MODEL = ("16", "016", "城管模型", 'cityMangement2', lambda device, gpuName: {
'labelnames': ["车辆", "垃圾", "商贩", "违停"],
'postProcess':{
'function':dmpr_yolo_stdc,
'pars':{'carCls':0 ,'illCls':3,'scaleRatio':0.5,'border':80,'rubCls': 1, 'Rubfilter': 150}
},
'models':[
{
#'weight':'../AIlib2/weights/conf/cityMangement3/yolov5.pt',
'weight':'../AIlib2/weights/cityMangement3/yolov5_%s_fp16.engine'%(gpuName),
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,'device':'cuda:0' ,'conf_thres':0.25,'iou_thres':0.5,'allowedList':[0,1,2,3],'segRegionCnt':1, 'trtFlag_det':False,'trtFlag_seg':False, "score_byClass":{"0":0.8,"1":0.4,"2":0.5,"3":0.5 } }
},
{
'weight':'../AIlib2/weights/conf/cityMangement3/dmpr.pth',
'par':{
'depth_factor':32,'NUM_FEATURE_MAP_CHANNEL':6,'dmpr_thresh':0.1, 'dmprimg_size':640,
'name':'dmpr'
},
'model':DMPRModel,
'name':'dmpr'
},
{
'weight':'../AIlib2/weights/conf/cityMangement3/stdc_360X640.pth',
'par':{
'modelSize':(640,360),'mean':(0.485, 0.456, 0.406),'std' :(0.229, 0.224, 0.225),'predResize':True,'numpy':False, 'RGB_convert_first':True,'seg_nclass':2},###分割模型预处理参数
'model':stdcModel,
'name':'stdc'
}
],
'postFile': {
"name": "post_process",
"conf_thres": 0.5,
"iou_thres": 0.5,
"classes": 5,
"rainbows": COLOR
},
'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,5,6,7,8,9] ],###控制哪些检测类别显示、输出
'segRegionCnt':2,###分割模型结果需要保留的等值线数目
"pixScale": 1.2,
})
DROWING_MODEL = ("17", "017", "人员落水模型", 'drowning', lambda device, gpuName: {
'device': device,
'labelnames': ["人头", "", "船只"],
'trtFlag_seg': True,
'trtFlag_det': True,
'seg_nclass': 2,
'segRegionCnt': 2,
'segPar': {
'modelSize': (640, 360),
'mean': (0.485, 0.456, 0.406),
'std': (0.229, 0.224, 0.225),
'predResize': True,
'numpy': False,
'RGB_convert_first': True,
'mixFunction': {
'function': mixDrowing_water_postprocess,
'pars': {
'modelSize': (640, 360)
}
}
},
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.25,
"classes": 9,
"rainbows": COLOR
},
# "../AIlib2/weights/conf/%s/yolov5.pt" % modeType.value[3]
'Detweights': "../AIlib2/weights/drowning/yolov5_%s_fp16.engine" % gpuName,
# '../AIlib2/weights/conf/%s/stdc_360X640.pth' % modeType.value[3]
'Segweights': '../AIlib2/weights/drowning/stdc_360X640_%s_fp16.engine' % gpuName
})
NOPARKING_MODEL = (
"18", "018", "城市违章模型", 'noParking', lambda device, gpuName: {
'device': device,
'labelnames': ["车辆", "违停"],
'trtFlag_seg': True,
'trtFlag_det': True,
'seg_nclass': 4,
'segRegionCnt': 2,
'segPar': {
'modelSize': (640, 360),
'mean': (0.485, 0.456, 0.406),
'std': (0.229, 0.224, 0.225),
'predResize': True,
'numpy': False,
'RGB_convert_first': True, ###分割模型预处理参数
'mixFunction': {
'function': mixNoParking_road_postprocess,
'pars': {
'modelSize': (640, 360),
'roundness': 0.3,
'cls': 9,
'laneArea': 10,
'laneAngleCha': 5,
'RoadArea': 16000,
'fitOrder':2
}
}
},
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.25,
"classes": 9,
"rainbows": COLOR
},
'Detweights': "../AIlib2/weights/noParking/yolov5_%s_fp16.engine" % gpuName,
'Segweights': '../AIlib2/weights/noParking/stdc_360X640_%s_fp16.engine' % gpuName
})
ILLPARKING_MODEL = ("19", "019", "车辆违停模型", 'illParking', lambda device, gpuName: {
'device': device,
'labelnames': ["", "T角点", "L角点", "违停"],
'trtFlag_seg': False,
'trtFlag_det': True,
'seg_nclass': 4,
'segRegionCnt': 2,
'segPar': {
'mixFunction': {
'function': illParking_postprocess,
'pars': {}
}
},
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.25,
"classes": 9,
"rainbows": COLOR
},
'Detweights': "../AIlib2/weights/illParking/yolov5_%s_fp16.engine" % gpuName,
'Segweights': None
})
CITYROAD_MODEL = ("20", "020", "城市公路模型", 'cityRoad', lambda device, gpuName: {
'device': device,
'labelnames': ["护栏", "交通标志", "非交通标志", "施工", "施工"],
'trtFlag_seg': False,
'trtFlag_det': True,
'slopeIndex': [],
'seg_nclass': 2,
'segRegionCnt': 0,
'segPar': None,
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.5,
"classes": 5,
"rainbows": COLOR
},
'Detweights': "../AIlib2/weights/cityRoad/yolov5_%s_fp16.engine" % gpuName,
'Segweights': None
})
POTHOLE_MODEL = ("23", "023", "坑槽检测模型", 'pothole', lambda device, gpuName: {
'device': device,
'gpu_name': gpuName,
'labelnames': ["坑槽"],
'seg_nclass': 2, # 分割模型类别数目默认2类
'segRegionCnt': 0,
'slopeIndex': [],
'trtFlag_det': True,
'trtFlag_seg': False,
'Detweights': "../AIlib2/weights/pothole/yolov5_%s_fp16.engine" % gpuName,
'segPar': None,
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'Segweights': None,
})
CHANNEL2_MODEL = ("24", "024", "船只综合检测模型", 'channel2', lambda device, gpuName: {
'device': device,
'gpu_name': gpuName,
'labelnames': ["国旗", "浮标", "船名", "船只","未挂国旗船只","未封仓"], # 保持原来的标签顺序不变,方便后面业务端增加
'segRegionCnt': 0,
'postProcess':{'function':channel2_post_process,'name':'channel2','pars':{
'objs':[2],
'wRation':1/6.0,
'hRation':1/6.0,
'smallId':0, #旗帜
'bigId':3, #船只
'newId':4, #未挂国旗船只
'uncoverId':5, #未封仓标签
'recScale':1.2,
'target_cls':3.0, #目标种类
'filter_cls':4.0 #被过滤的种类
}},
'models':[
{
#'weight':'../AIlib2/weights/conf/channel2/yolov5.pt',
# 'weight':'../AIlib2/weights/channel2/yolov5_%s_fp16.engine'%(gpuName),
'weight':'/home/thsw2/jcq/test/AIlib2/weights/channel2/best.pt', # yolov5 原来模型基础上增加了未封仓
# 'weight':'../AIlib2/weights/channel2/yolov5_%s_fp16.engine'%(gpuName),
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,'device':'cuda:0' ,'conf_thres':0.1,'iou_thres':0.45,'allowedList':list(range(20)),'segRegionCnt':1, 'trtFlag_det':False,'trtFlag_seg':False, "score_byClass":{"0":0.7,"1":0.7,"2":0.8,"3":0.6} }
},
{
# 'weight' : '../AIlib2/weights/ocr2/crnn_ch_4090_fp16_192X32.engine',
'weight' : '../AIlib2/weights/conf/ocr2/crnn_ch.pth',
'name':'ocr',
'model':ocrModel,
'par':{
'char_file':'../AIlib2/weights/conf/ocr2/benchmark.txt',
'mode':'ch',
'nc':3,
'imgH':32,
'imgW':192,
'hidden':256,
'mean':[0.5,0.5,0.5],
'std':[0.5,0.5,0.5],
'dynamic':False,
},
} ,
# {
# 'weight':'/home/thsw2/jcq/test/AIlib2/weights1/conf/channel2/yolov5_04.pt', # yolov5_04 添加了uncover 0 4 ;标签 yolov5_jcq
# 'name':'yolov5',
# 'model':yolov5Model,
# 'par':{ 'half':True,'device':'cuda:0' ,'conf_thres':0.15,'iou_thres':0.25,'allowedList':list(range(20)),'segRegionCnt':1, 'trtFlag_det':False,'trtFlag_seg':False, "score_byClass":{"0":0.7,"1":0.7,"2":0.8,"3":0.6} }
# }
],
'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3]],
'segPar': None,
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'Segweights': None,
})
RIVERT_MODEL = ("25", "025", "河道检测模型(T)", 'riverT', lambda device, gpuName: {
'device': device,
'labelnames': ["漂浮物", "岸坡垃圾", "排口", "违建", "菜地", "水生植物", "河湖人员", "钓鱼人员", "船只",
"蓝藻"],
'trtFlag_seg': True,
'trtFlag_det': True,
'seg_nclass': 2,
'segRegionCnt': 1,
'segPar': {
'modelSize': (640, 360),
'mean': (0.485, 0.456, 0.406),
'std': (0.229, 0.224, 0.225),
'numpy': False,
'RGB_convert_first': True,
'mixFunction': {
'function': riverDetSegMixProcess,
'pars': {
'slopeIndex': [1, 3, 4, 7],
'riverIou': 0.1
}
}
},
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.3,
"ovlap_thres_crossCategory": 0.65,
"classes": 5,
"rainbows": COLOR
},
# "../AIlib2/weights/conf/%s/yolov5.pt" % modeType.value[3]
'Detweights': "../AIlib2/weights/riverT/yolov5_%s_fp16.engine" % gpuName,
# '../AIlib2/weights/conf/%s/stdc_360X640.pth' % modeType.value[3]
'Segweights': '../AIlib2/weights/riverT/stdc_360X640_%s_fp16.engine' % gpuName
})
FORESTCROWD_FARM_MODEL = ("2", "026", "森林人群模型", 'forestCrowd', lambda device, gpuName: {
'labelnames': ["林斑", "病死树", "行人", "火焰", "烟雾","人群"],
'postProcess':{'function':gather_post_process,'pars':{'pedestrianId':2,'crowdThreshold':4,'gatherId':5,'distancePersonScale':2.0}},
'models':
[
{
'weight':"../AIlib2/weights/forestCrowd/yolov5_%s_fp16.engine"%(gpuName),###检测模型路径
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,'device':'cuda:0' ,'conf_thres':0.25,'iou_thres':0.5,'allowedList':[0,1,2,3],'segRegionCnt':1, 'trtFlag_det':False,'trtFlag_seg':False, "score_byClass":{ "0":0.25,"1":0.25,"2":0.6,"3":0.6,'4':0.6 ,'5':0.6 } },
}
],
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6,7,8,9] ],###控制哪些检测类别显示、输出
'segRegionCnt':2,###分割模型结果需要保留的等值线数目
"pixScale": 1.2,
})
TRAFFICFORDSJ_FARM_MODEL = ("27", "027", "交通模型-大数据局", 'highWay2T', lambda device, gpuName: {
'device': str(device),
'labelnames': ["行人", "车辆", "纵向裂缝", "横向裂缝", "修补", "网状裂纹", "坑槽", "块状裂纹", "积水", "影子", "事故", "桥梁外观","设施破损缺失","龙门架","防抛网","标识牌损坏","护栏损坏","钢筋裸露" ],
'trtFlag_seg': True,
'trtFlag_det': True,
'seg_nclass': 3,
'segRegionCnt': 2,
'segPar': {
'modelSize': (640, 360),
'mean': (0.485, 0.456, 0.406),
'std': (0.229, 0.224, 0.225),
'predResize': True,
'numpy': False,
'RGB_convert_first': True,
'mixFunction': {
'function': tracfficAccidentMixFunction,
'pars': {
'modelSize': (640, 360),
#'modelSize': (1920,1080),
'RoadArea': 16000,
'roadVehicleAngle': 15,
'speedRoadVehicleAngleMax': 75,
'roundness': 1.0,
'cls': 9,
'vehicleFactor': 0.1,
'confThres': 0.25,
'roadIou': 0.6,
'radius': 50,
'vehicleFlag': False,
'distanceFlag': False
}
}
},
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.25,
"classes": 10,
"rainbows": COLOR
},
'Detweights': "../AIlib2/weights/highWay2/yolov5_%s_fp16.engine" % gpuName,
'Segweights': '../AIlib2/weights/highWay2/stdc_360X640_%s_fp16.engine' % gpuName
})
@staticmethod
def checkCode(code):
for model in ModelType:
if model.value[1] == code:
return True
return False
'''
参数1: 检测目标名称
参数2: 检测目标
参数3: 初始化百度检测客户端
'''
@unique
class BaiduModelTarget(Enum):
VEHICLE_DETECTION = (
"车辆检测", 0, lambda client0, client1, url, request_id: client0.vehicleDetectUrl(url, request_id))
HUMAN_DETECTION = (
"人体检测与属性识别", 1, lambda client0, client1, url, request_id: client1.bodyAttr(url, request_id))
PEOPLE_COUNTING = ("人流量统计", 2, lambda client0, client1, url, request_id: client1.bodyNum(url, request_id))
BAIDU_MODEL_TARGET_CONFIG = {
BaiduModelTarget.VEHICLE_DETECTION.value[1]: BaiduModelTarget.VEHICLE_DETECTION,
BaiduModelTarget.HUMAN_DETECTION.value[1]: BaiduModelTarget.HUMAN_DETECTION,
BaiduModelTarget.PEOPLE_COUNTING.value[1]: BaiduModelTarget.PEOPLE_COUNTING
}
EPIDEMIC_PREVENTION_CONFIG = {1: "行程码", 2: "健康码"}
# 模型分析方式
@unique
class ModelMethodTypeEnum(Enum):
# 方式一: 正常识别方式
NORMAL = 1
# 方式二: 追踪识别方式
TRACE = 2

807
enums/ModelTypeEnum-raw.py Normal file
View File

@ -0,0 +1,807 @@
import sys
from enum import Enum, unique
from common.Constant import COLOR
sys.path.extend(['..', '../AIlib2'])
from DMPR import DMPRModel
from DMPRUtils.jointUtil import dmpr_yolo
from segutils.segmodel import SegModel
from utilsK.queRiver import riverDetSegMixProcess
from utilsK.crowdGather import gather_post_process
from segutils.trafficUtils import tracfficAccidentMixFunction
from utilsK.drownUtils import mixDrowing_water_postprocess
from utilsK.noParkingUtils import mixNoParking_road_postprocess
from utilsK.illParkingUtils import illParking_postprocess
from stdc import stdcModel
from yolov5 import yolov5Model
from DMPRUtils.jointUtil import dmpr_yolo_stdc
from AI import default_mix
from ocr import ocrModel
from utilsK.channel2postUtils import channel2_post_process
'''
参数说明
1. 编号
2. 模型编号
3. 模型名称
4. 选用的模型名称
5. 模型配置
6. 模型引用配置[Detweights文件, Segweights文件, 引用计数]
'''
@unique
class ModelType(Enum):
WATER_SURFACE_MODEL = ("1", "001", "河道模型", 'river', lambda device, gpuName: {
'device': device,
'labelnames': ["排口", "水生植被", "其它", "漂浮物", "污染排口", "菜地", "违建", "岸坡垃圾"],
'seg_nclass': 2,
'trtFlag_seg': True,
'trtFlag_det': True,
'segRegionCnt': 1,
'segPar': {
'modelSize': (640, 360),
'mean': (0.485, 0.456, 0.406),
'std': (0.229, 0.224, 0.225),
'numpy': False,
'RGB_convert_first': True,
'mixFunction': {
'function': riverDetSegMixProcess,
'pars': {
'slopeIndex': [5, 6, 7],
'riverIou': 0.1
}
}
},
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'Detweights': "../AIlib2/weights/river/yolov5_%s_fp16.engine" % gpuName,
'Segweights': '../AIlib2/weights/river/stdc_360X640_%s_fp16.engine' % gpuName
})
# FOREST_FARM_MODEL = ("2", "002", "森林模型", 'forest2', lambda device, gpuName: {
# 'device': device,
# 'gpu_name': gpuName,
# 'labelnames': ["林斑", "病死树", "行人", "火焰", "烟雾","云朵"],
# 'trtFlag_det': True,
# 'trtFlag_seg': False,
# 'Detweights': "../AIlib2/weights/forest2/yolov5_%s_fp16.engine" % gpuName,
# 'seg_nclass': 2,
# 'segRegionCnt': 0,
# 'slopeIndex': [],
# 'segPar': None,
# 'postFile': {
# "name": "post_process",
# "conf_thres": 0.25,
# "iou_thres": 0.45,
# "classes": 6,
# "rainbows": COLOR
# },
# 'Segweights': None
# })
FOREST_FARM_MODEL = ("2", "002", "森林模型", 'forest2', lambda device, gpuName: {
'labelnames': ["林斑", "病死树", "行人", "火焰", "烟雾","云朵"],
'postProcess':{'function':default_mix,'pars':{}},
'models':
[
{
'weight':"../AIlib2/weights/forest2/yolov5_%s_fp16.engine"%(gpuName),###检测模型路径
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,'device':'cuda:0' ,'conf_thres':0.25,'iou_thres':0.45,'allowedList':[0,1,2,3],'segRegionCnt':1, 'trtFlag_det':False,'trtFlag_seg':False, "score_byClass":{"0":0.25,"1":0.3,"2":0.3,"3":0.3 } },
}
],
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6,7,8,9] ],###控制哪些检测类别显示、输出
'segRegionCnt':2,###分割模型结果需要保留的等值线数目
"pixScale": 1.2,
})
TRAFFIC_FARM_MODEL = ("3", "003", "交通模型", 'highWay2', lambda device, gpuName: {
'device': str(device),
'labelnames': ["行人", "车辆", "纵向裂缝", "横向裂缝", "修补", "网状裂纹", "坑槽", "块状裂纹", "积水", "影子", "事故"],
'trtFlag_seg': True,
'trtFlag_det': True,
'seg_nclass': 3,
'segRegionCnt': 2,
'segPar': {
#'modelSize': (640, 360),
'modelSize': (1920, 1080),
'mean': (0.485, 0.456, 0.406),
'std': (0.229, 0.224, 0.225),
'predResize': True,
'numpy': False,
'RGB_convert_first': True,
'mixFunction': {
'function': tracfficAccidentMixFunction,
'pars': {
#'modelSize': (640, 360),
'modelSize': (1920,1080),
'RoadArea': 16000,
'roadVehicleAngle': 15,
'speedRoadVehicleAngleMax': 75,
'roundness': 1.0,
'cls': 10,
'vehicleFactor': 0.1,
'confThres': 0.25,
'roadIou': 0.6,
'radius': 50,
'vehicleFlag': False,
'distanceFlag': False
}
}
},
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.25,
"classes": 10,
"rainbows": COLOR
},
'Detweights': "../AIlib2/weights/highWay2/yolov5_%s_fp16.engine" % gpuName,
'Segweights': '../AIlib2/weights/highWay2/stdc_360X640_%s_fp16.engine' % gpuName
})
EPIDEMIC_PREVENTION_MODEL = ("4", "004", "防疫模型", None, None)
PLATE_MODEL = ("5", "005", "车牌模型", None, None)
VEHICLE_MODEL = ("6", "006", "车辆模型", 'vehicle', lambda device, gpuName: {
'device': device,
'gpu_name': gpuName,
'labelnames': ["车辆"],
'seg_nclass': 2,
'segRegionCnt': 0,
'slopeIndex': [],
'trtFlag_det': True,
'trtFlag_seg': False,
'Detweights': "../AIlib2/weights/vehicle/yolov5_%s_fp16.engine" % gpuName,
'segPar': None,
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'Segweights': None
})
PEDESTRIAN_MODEL = ("7", "007", "行人模型", 'pedestrian', lambda device, gpuName: {
'device': device,
'gpu_name': gpuName,
'labelnames': ["行人"],
'seg_nclass': 2,
'segRegionCnt': 0,
'trtFlag_det': True,
'trtFlag_seg': False,
'Detweights': "../AIlib2/weights/pedestrian/yolov5_%s_fp16.engine" % gpuName,
'slopeIndex': [],
'segPar': None,
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'Segweights': None
})
SMOGFIRE_MODEL = ("8", "008", "烟火模型", 'smogfire', lambda device, gpuName: {
'device': device,
'gpu_name': gpuName,
'labelnames': ["火焰", "烟雾"],
'seg_nclass': 2, # 分割模型类别数目默认2类
'segRegionCnt': 0,
'trtFlag_det': True,
'trtFlag_seg': False,
'Detweights': "../AIlib2/weights/smogfire/yolov5_%s_fp16.engine" % gpuName,
'slopeIndex': [],
'segPar': None,
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'Segweights': None
})
ANGLERSWIMMER_MODEL = ("9", "009", "钓鱼游泳模型", 'AnglerSwimmer', lambda device, gpuName: {
'device': device,
'gpu_name': gpuName,
'labelnames': ["钓鱼", "游泳"],
'seg_nclass': 2, # 分割模型类别数目默认2类
'segRegionCnt': 0,
'slopeIndex': [],
'trtFlag_det': True,
'trtFlag_seg': False,
'Detweights': "../AIlib2/weights/AnglerSwimmer/yolov5_%s_fp16.engine" % gpuName,
'segPar': None,
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'Segweights': None
})
COUNTRYROAD_MODEL = ("10", "010", "乡村模型", 'countryRoad', lambda device, gpuName: {
'device': device,
'gpu_name': gpuName,
'labelnames': ["违法种植"],
'seg_nclass': 2, # 分割模型类别数目默认2类
'segRegionCnt': 0,
'slopeIndex': [],
'trtFlag_det': True,
'trtFlag_seg': False,
'Detweights': "../AIlib2/weights/countryRoad/yolov5_%s_fp16.engine" % gpuName,
'segPar': None,
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'Segweights': None
})
SHIP_MODEL = ("11", "011", "船只模型", 'ship2', lambda device, gpuName: {
'model_size': (608, 608),
'K': 100,
'conf_thresh': 0.18,
'device': 'cuda:%s' % device,
'down_ratio': 4,
'num_classes': 15,
'weights': '../AIlib2/weights/ship2/obb_608X608_%s_fp16.engine' % gpuName,
'dataset': 'dota',
'half': False,
'mean': (0.5, 0.5, 0.5),
'std': (1, 1, 1),
'heads': {'hm': None, 'wh': 10, 'reg': 2, 'cls_theta': 1},
'decoder': None,
'test_flag': True,
"rainbows": COLOR,
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'drawBox': False,
'label_array': None,
'labelnames': ("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "船只"),
})
BAIDU_MODEL = ("12", "012", "百度AI图片识别模型", None, None)
CHANNEL_EMERGENCY_MODEL = ("13", "013", "航道模型", 'channelEmergency', lambda device, gpuName: {
'device': device,
'gpu_name': gpuName,
'labelnames': [""],
'seg_nclass': 2, # 分割模型类别数目默认2类
'segRegionCnt': 0,
'slopeIndex': [],
'trtFlag_det': True,
'trtFlag_seg': False,
'Detweights': "../AIlib2/weights/channelEmergency/yolov5_%s_fp16.engine" % gpuName,
'segPar': None,
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'Segweights': None
})
RIVER2_MODEL = ("15", "015", "河道检测模型", 'river2', lambda device, gpuName: {
'device': device,
'labelnames': ["漂浮物", "岸坡垃圾", "排口", "违建", "菜地", "水生植物", "河湖人员", "钓鱼人员", "船只",
"蓝藻"],
'trtFlag_seg': True,
'trtFlag_det': True,
'seg_nclass': 2,
'segRegionCnt': 1,
'segPar': {
'modelSize': (640, 360),
'mean': (0.485, 0.456, 0.406),
'std': (0.229, 0.224, 0.225),
'numpy': False,
'RGB_convert_first': True,
'mixFunction': {
'function': riverDetSegMixProcess,
'pars': {
'slopeIndex': [1, 3, 4, 7],
'riverIou': 0.1
}
}
},
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.3,
"ovlap_thres_crossCategory": 0.65,
"classes": 5,
"rainbows": COLOR
},
# "../AIlib2/weights/conf/%s/yolov5.pt" % modeType.value[3]
'Detweights': "../AIlib2/weights/river2/yolov5_%s_fp16.engine" % gpuName,
# '../AIlib2/weights/conf/%s/stdc_360X640.pth' % modeType.value[3]
'Segweights': '../AIlib2/weights/river2/stdc_360X640_%s_fp16.engine' % gpuName
})
CITY_MANGEMENT_MODEL = ("16", "016", "城管模型", 'cityMangement2', lambda device, gpuName: {
'labelnames': ["车辆", "垃圾", "商贩", "裸土","占道经营","违停"],
'postProcess':{
'function':dmpr_yolo_stdc,
'pars':{'carCls':0 ,'illCls':5,'scaleRatio':0.5,'border':80}
},
'models':[
{
#'weight':'../AIlib2/weights/conf/cityMangement3/yolov5.pt',
'weight':'../AIlib2/weights/cityMangement3/yolov5_%s_fp16.engine'%(gpuName),
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,'device':'cuda:0' ,'conf_thres':0.25,'iou_thres':0.45,'allowedList':[0,1,2,3,4,5],'segRegionCnt':1, 'trtFlag_det':False,'trtFlag_seg':False, "score_byClass":{"0":0.8,"1":0.4,"2":0.5,"3":0.5,"4":0.4,"5":0.5 } }
},
{
'weight':'../AIlib2/weights/conf/cityMangement3/dmpr.pth',
'par':{
'depth_factor':32,'NUM_FEATURE_MAP_CHANNEL':6,'dmpr_thresh':0.1, 'dmprimg_size':640,
'name':'dmpr'
},
'model':DMPRModel,
'name':'dmpr'
},
{
'weight':'../AIlib2/weights/conf/cityMangement3/stdc_360X640.pth',
'par':{
'modelSize':(640,360),'mean':(0.485, 0.456, 0.406),'std' :(0.229, 0.224, 0.225),'predResize':True,'numpy':False, 'RGB_convert_first':True,'seg_nclass':2},###分割模型预处理参数
'model':stdcModel,
'name':'stdc'
}
],
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,5,6,7,8,9] ],###控制哪些检测类别显示、输出
'segRegionCnt':2,###分割模型结果需要保留的等值线数目
"pixScale": 1.2,
})
DROWING_MODEL = ("17", "017", "人员落水模型", 'drowning', lambda device, gpuName: {
'device': device,
'labelnames': ["人头", "", "船只"],
'trtFlag_seg': True,
'trtFlag_det': True,
'seg_nclass': 2,
'segRegionCnt': 2,
'segPar': {
'modelSize': (640, 360),
'mean': (0.485, 0.456, 0.406),
'std': (0.229, 0.224, 0.225),
'predResize': True,
'numpy': False,
'RGB_convert_first': True,
'mixFunction': {
'function': mixDrowing_water_postprocess,
'pars': {
'modelSize': (640, 360)
}
}
},
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.25,
"classes": 9,
"rainbows": COLOR
},
# "../AIlib2/weights/conf/%s/yolov5.pt" % modeType.value[3]
'Detweights': "../AIlib2/weights/drowning/yolov5_%s_fp16.engine" % gpuName,
# '../AIlib2/weights/conf/%s/stdc_360X640.pth' % modeType.value[3]
'Segweights': '../AIlib2/weights/drowning/stdc_360X640_%s_fp16.engine' % gpuName
})
NOPARKING_MODEL = (
"18", "018", "城市违章模型", 'noParking', lambda device, gpuName: {
'device': device,
'labelnames': ["车辆", "违停"],
'trtFlag_seg': True,
'trtFlag_det': True,
'seg_nclass': 4,
'segRegionCnt': 2,
'segPar': {
'modelSize': (640, 360),
'mean': (0.485, 0.456, 0.406),
'std': (0.229, 0.224, 0.225),
'predResize': True,
'numpy': False,
'RGB_convert_first': True, ###分割模型预处理参数
'mixFunction': {
'function': mixNoParking_road_postprocess,
'pars': {
'modelSize': (640, 360),
'roundness': 0.3,
'cls': 9,
'laneArea': 10,
'laneAngleCha': 5,
'RoadArea': 16000,
'fitOrder':2
}
}
},
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.25,
"classes": 9,
"rainbows": COLOR
},
'Detweights': "../AIlib2/weights/noParking/yolov5_%s_fp16.engine" % gpuName,
'Segweights': '../AIlib2/weights/noParking/stdc_360X640_%s_fp16.engine' % gpuName
})
ILLPARKING_MODEL = ("19", "019", "车辆违停模型", 'illParking', lambda device, gpuName: {
'device': device,
'labelnames': ["", "T角点", "L角点", "违停"],
'trtFlag_seg': False,
'trtFlag_det': True,
'seg_nclass': 4,
'segRegionCnt': 2,
'segPar': {
'mixFunction': {
'function': illParking_postprocess,
'pars': {}
}
},
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.25,
"classes": 9,
"rainbows": COLOR
},
'Detweights': "../AIlib2/weights/illParking/yolov5_%s_fp16.engine" % gpuName,
'Segweights': None
})
CITYROAD_MODEL = ("20", "020", "城市公路模型", 'cityRoad', lambda device, gpuName: {
'device': device,
'labelnames': ["护栏", "交通标志", "非交通标志", "施工", "施工"],
'trtFlag_seg': False,
'trtFlag_det': True,
'slopeIndex': [],
'seg_nclass': 2,
'segRegionCnt': 0,
'segPar': None,
'postFile': {
"name": "post_process",
"conf_thres": 0.8,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'Detweights': "../AIlib2/weights/cityRoad/yolov5_%s_fp16.engine" % gpuName,
'Segweights': None
})
POTHOLE_MODEL = ("23", "023", "坑槽检测模型", 'pothole', lambda device, gpuName: {
'device': device,
'gpu_name': gpuName,
'labelnames': ["坑槽"],
'seg_nclass': 2, # 分割模型类别数目默认2类
'segRegionCnt': 0,
'slopeIndex': [],
'trtFlag_det': True,
'trtFlag_seg': False,
'Detweights': "../AIlib2/weights/pothole/yolov5_%s_fp16.engine" % gpuName,
'segPar': None,
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'Segweights': None,
})
CHANNEL2_MODEL = ("24", "024", "船只综合检测模型", 'channel2', lambda device, gpuName: {
'device': device,
'gpu_name': gpuName,
'labelnames': ["国旗", "浮标", "船名", "船只","未挂国旗船只"],
'segRegionCnt': 0,
'postProcess':{'function':channel2_post_process,'name':'channel2','pars':{
'objs':[2],
'wRation':1/6.0,
'hRation':1/6.0,
'smallId':0,
'bigId':3,
'newId':4,
'recScale':1.2}},
'models':[
{
#'weight':'../AIlib2/weights/conf/channel2/yolov5.pt',
'weight':'../AIlib2/weights/channel2/yolov5_%s_fp16.engine'%(gpuName),
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,'device':'cuda:0' ,'conf_thres':0.1,'iou_thres':0.45,'allowedList':list(range(20)),'segRegionCnt':1, 'trtFlag_det':False,'trtFlag_seg':False, "score_byClass":{"0":0.7,"1":0.7,"2":0.8,"3":0.6} }
},
{
# 'weight' : '../AIlib2/weights/ocr2/crnn_ch_4090_fp16_192X32.engine',
'weight' : '../AIlib2/weights/conf/ocr2/crnn_ch.pth',
'name':'ocr',
'model':ocrModel,
'par':{
'char_file':'../AIlib2/weights/conf/ocr2/benchmark.txt',
'mode':'ch',
'nc':3,
'imgH':32,
'imgW':192,
'hidden':256,
'mean':[0.5,0.5,0.5],
'std':[0.5,0.5,0.5],
'dynamic':False,
},
}
],
'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3]],
'segPar': None,
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'Segweights': None,
})
RIVERT_MODEL = ("25", "025", "河道检测模型(T)", 'riverT', lambda device, gpuName: {
'device': device,
'labelnames': ["漂浮物", "岸坡垃圾", "排口", "违建", "菜地", "水生植物", "河湖人员", "钓鱼人员", "船只",
"蓝藻"],
'trtFlag_seg': True,
'trtFlag_det': True,
'seg_nclass': 2,
'segRegionCnt': 1,
'segPar': {
'modelSize': (640, 360),
'mean': (0.485, 0.456, 0.406),
'std': (0.229, 0.224, 0.225),
'numpy': False,
'RGB_convert_first': True,
'mixFunction': {
'function': riverDetSegMixProcess,
'pars': {
'slopeIndex': [1, 3, 4, 7],
'riverIou': 0.1
}
}
},
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.3,
"ovlap_thres_crossCategory": 0.65,
"classes": 5,
"rainbows": COLOR
},
# "../AIlib2/weights/conf/%s/yolov5.pt" % modeType.value[3]
'Detweights': "../AIlib2/weights/riverT/yolov5_%s_fp16.engine" % gpuName,
# '../AIlib2/weights/conf/%s/stdc_360X640.pth' % modeType.value[3]
'Segweights': '../AIlib2/weights/riverT/stdc_360X640_%s_fp16.engine' % gpuName
})
FORESTCROWD_FARM_MODEL = ("26", "026", "森林人群模型", 'forestCrowd', lambda device, gpuName: {
'labelnames': ["林斑", "病死树", "行人", "火焰", "烟雾","人群"],
'postProcess':{'function':gather_post_process,'pars':{'pedestrianId':2,'crowdThreshold':4,'gatherId':5,'distancePersonScale':2.0}},
'models':
[
{
'weight':"../AIlib2/weights/forestCrowd/yolov5_%s_fp16.engine"%(gpuName),###检测模型路径
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,'device':'cuda:0' ,'conf_thres':0.25,'iou_thres':0.45,'allowedList':[0,1,2,3],'segRegionCnt':1, 'trtFlag_det':False,'trtFlag_seg':False, "score_byClass":{ "0":0.25,"1":0.25,"2":0.6,"3":0.6,'4':0.6 ,'5':0.6 } },
}
],
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6,7,8,9] ],###控制哪些检测类别显示、输出
'segRegionCnt':2,###分割模型结果需要保留的等值线数目
"pixScale": 1.2,
})
TRAFFICFORDSJ_FARM_MODEL = ("27", "027", "交通模型-大数据局", 'highWay2T', lambda device, gpuName: {
'device': str(device),
'labelnames': ["行人", "车辆", "纵向裂缝", "横向裂缝", "修补", "网状裂纹", "坑槽", "块状裂纹", "积水", "影子", "事故", "桥梁外观","设施破损缺失","龙门架","防抛网","标识牌损坏","护栏损坏","钢筋裸露" ],
'trtFlag_seg': True,
'trtFlag_det': True,
'seg_nclass': 3,
'segRegionCnt': 2,
'segPar': {
'modelSize': (640, 360),
'mean': (0.485, 0.456, 0.406),
'std': (0.229, 0.224, 0.225),
'predResize': True,
'numpy': False,
'RGB_convert_first': True,
'mixFunction': {
'function': tracfficAccidentMixFunction,
'pars': {
'modelSize': (640, 360),
#'modelSize': (1920,1080),
'RoadArea': 16000,
'roadVehicleAngle': 15,
'speedRoadVehicleAngleMax': 75,
'roundness': 1.0,
'cls': 9,
'vehicleFactor': 0.1,
'confThres': 0.25,
'roadIou': 0.6,
'radius': 50,
'vehicleFlag': False,
'distanceFlag': False
}
}
},
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.25,
"classes": 10,
"rainbows": COLOR
},
'Detweights': "../AIlib2/weights/highWay2/yolov5_%s_fp16.engine" % gpuName,
'Segweights': '../AIlib2/weights/highWay2/stdc_360X640_%s_fp16.engine' % gpuName
})
SMARTSITE_MODEL = ("28", "028", "智慧工地模型", 'smartSite', lambda device, gpuName: {
'labelnames': [ "工人","塔式起重机","悬臂","起重机","压路机","推土机","挖掘机","卡车","装载机","泵车","混凝土搅拌车","打桩","其他车辆" ],
'postProcess':{'function':default_mix,'pars':{}},
'models':
[
{
'weight':"../AIlib2/weights/smartSite/yolov5_%s_fp16.engine"%(gpuName),###检测模型路径
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,'device':'cuda:0' ,'conf_thres':0.25,'iou_thres':0.45,'allowedList':list(range(20)),'segRegionCnt':1, 'trtFlag_det':True,'trtFlag_seg':False, "score_byClass":{"0":0.25,"1":0.3,"2":0.3,"3":0.3 } },
}
],
'postFile': {
"rainbows": COLOR
},
})
RUBBISH_MODEL = ("29", "029", "垃圾模型", 'rubbish', lambda device, gpuName: {
'labelnames': [ "建筑垃圾","白色垃圾","其他垃圾"],
'postProcess':{'function':default_mix,'pars':{}},
'models':
[
{
'weight':"../AIlib2/weights/rubbish/yolov5_%s_fp16.engine"%(gpuName),###检测模型路径
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,'device':'cuda:0' ,'conf_thres':0.25,'iou_thres':0.45,'allowedList':list(range(20)),'segRegionCnt':1, 'trtFlag_det':True,'trtFlag_seg':False, "score_byClass":{"0":0.25,"1":0.3,"2":0.3,"3":0.3 } },
}
],
'postFile': {
"rainbows": COLOR
},
})
FIREWORK_MODEL = ("30", "030", "烟花模型", 'firework', lambda device, gpuName: {
'labelnames': [ "烟花"],
'postProcess':{'function':default_mix,'pars':{}},
'models':
[
{
'weight':"../AIlib2/weights/firework/yolov5_%s_fp16.engine"%(gpuName),###检测模型路径
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,'device':'cuda:0' ,'conf_thres':0.25,'iou_thres':0.45,'allowedList':list(range(20)),'segRegionCnt':1, 'trtFlag_det':True,'trtFlag_seg':False, "score_byClass":{"0":0.25,"1":0.3,"2":0.3,"3":0.3 } },
}
],
'postFile': {
"rainbows": COLOR
},
})
@staticmethod
def checkCode(code):
for model in ModelType:
if model.value[1] == code:
return True
return False
'''
参数1: 检测目标名称
参数2: 检测目标
参数3: 初始化百度检测客户端
'''
@unique
class BaiduModelTarget(Enum):
VEHICLE_DETECTION = (
"车辆检测", 0, lambda client0, client1, url, request_id: client0.vehicleDetectUrl(url, request_id))
HUMAN_DETECTION = (
"人体检测与属性识别", 1, lambda client0, client1, url, request_id: client1.bodyAttr(url, request_id))
PEOPLE_COUNTING = ("人流量统计", 2, lambda client0, client1, url, request_id: client1.bodyNum(url, request_id))
BAIDU_MODEL_TARGET_CONFIG = {
BaiduModelTarget.VEHICLE_DETECTION.value[1]: BaiduModelTarget.VEHICLE_DETECTION,
BaiduModelTarget.HUMAN_DETECTION.value[1]: BaiduModelTarget.HUMAN_DETECTION,
BaiduModelTarget.PEOPLE_COUNTING.value[1]: BaiduModelTarget.PEOPLE_COUNTING
}
EPIDEMIC_PREVENTION_CONFIG = {1: "行程码", 2: "健康码"}
# 模型分析方式
@unique
class ModelMethodTypeEnum(Enum):
# 方式一: 正常识别方式
NORMAL = 1
# 方式二: 追踪识别方式
TRACE = 2

1087
enums/ModelTypeEnum.py Normal file

File diff suppressed because it is too large Load Diff

762
enums/ModelTypeEnum2.py Normal file
View File

@ -0,0 +1,762 @@
import sys
from enum import Enum, unique
from common.Constant import COLOR
sys.path.extend(['..', '../AIlib2'])
from segutils.segmodel import SegModel
from utilsK.queRiver import riverDetSegMixProcess_N
from segutils.trafficUtils import tracfficAccidentMixFunction_N
from utilsK.drownUtils import mixDrowing_water_postprocess_N
from utilsK.noParkingUtils import mixNoParking_road_postprocess_N
from utilsK.illParkingUtils import illParking_postprocess
from DMPR import DMPRModel
from DMPRUtils.jointUtil import dmpr_yolo
from yolov5 import yolov5Model
from stdc import stdcModel
from AI import default_mix
from DMPRUtils.jointUtil import dmpr_yolo_stdc
'''
参数说明
1. 编号
2. 模型编号
3. 模型名称
4. 选用的模型名称
'''
@unique
class ModelType2(Enum):
WATER_SURFACE_MODEL = ("1", "001", "河道模型", 'river', lambda device, gpuName: {
'device': device,
'labelnames': ["排口", "水生植被", "其它", "漂浮物", "污染排口", "菜地", "违建", "岸坡垃圾"],
'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6,7] ],###控制哪些检测类别显示、输出
'trackPar': {
'sort_max_age': 2, # 跟踪链断裂时允许目标消失最大的次数。超过之后,会认为是新的目标。
'sort_min_hits': 3, # 每隔目标连续出现的次数,超过这个次数才认为是一个目标。
'sort_iou_thresh': 0.2, # 检测最小的置信度。
'det_cnt': 10, # 每隔几次做一个跟踪和检测默认10。
'windowsize': 29, # 轨迹平滑长度一定是奇数表示每隔几帧做一平滑默认29。一个目标在多个帧中出现每一帧中都有一个位置这些位置的连线交轨迹。
'patchCnt': 100, # 每次送入图像的数量不宜少于100帧。
},
'postProcess':{'function':riverDetSegMixProcess_N,'pars':{'slopeIndex':[1,3,4,7], 'riverIou':0.1}}, #分割和检测混合处理的函数
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'txtFontSize': 80,
'digitFont': {
'line_thickness': 2,
'boxLine_thickness': 1,
'fontSize': 1.0,
'segLineShow': False,
'waterLineColor': (0, 255, 255),
'waterLineWidth': 3
},
'models':
[
{
'weight':"../AIlib2/weights/river/yolov5_%s_fp16.engine"% gpuName,###检测模型路径
'name':'yolov5',
'model':yolov5Model,
'par':{
'half':True,
'device':'cuda:0' ,
'conf_thres':0.25,
'iou_thres':0.45,
'allowedList':[0,1,2,3],
'segRegionCnt':1,
'trtFlag_det':False,
'trtFlag_seg':False,
"score_byClass":{"0":0.25,"1":0.3,"2":0.3,"3":0.3 } },
},
{
'weight':'../AIlib2/weights/conf/river/stdc_360X640.pth',
'par':{
'modelSize':(640,360),
'mean':(0.485, 0.456, 0.406),
'std' :(0.229, 0.224, 0.225),
'numpy':False,
'RGB_convert_first':True,
'seg_nclass':2},###分割模型预处理参数
'model':stdcModel,
'name':'stdc'
}
],
})
FOREST_FARM_MODEL = ("2", "002", "森林模型", 'forest2', lambda device, gpuName: {
'device': device,
'labelnames': ["林斑", "病死树", "行人", "火焰", "烟雾"],
'models':
[
{
'weight':"../AIlib2/weights/forest2/yolov5_%s_fp16.engine"% gpuName,###检测模型路径
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,
'device':'cuda:0' ,
'conf_thres':0.25,
'iou_thres':0.45,
'allowedList':[0,1,2,3],
'segRegionCnt':1,
'trtFlag_det':False,
'trtFlag_seg':False,
"score_byClass":{"0":0.25,"1":0.3,"2":0.3,"3":0.3 }
},
}
],
'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100},
'postProcess':{'function':default_mix,'pars':{ }},
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'txtFontSize': 80,
'digitFont': {
'line_thickness': 2,
'boxLine_thickness': 1,
'fontSize': 1.0,
'segLineShow': False,
'waterLineColor': (0, 255, 255),
'waterLineWidth': 3
}
})
TRAFFIC_FARM_MODEL = ("3", "003", "交通模型", 'highWay2', lambda device, gpuName: {
'device': device,
'labelnames': ["行人", "车辆", "纵向裂缝", "横向裂缝", "修补", "网状裂纹", "坑槽", "块状裂纹", "积水", "事故"],
'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':5,'windowsize':29,'patchCnt':100},
'postProcess':{
'function':tracfficAccidentMixFunction_N,
'pars':{
'RoadArea': 16000,
'vehicleArea': 10,
'roadVehicleAngle': 15,
'speedRoadVehicleAngleMax': 75,
'radius': 50 ,
'roundness': 1.0,
'cls': 9,
'vehicleFactor': 0.1,
'cls':9,
'confThres':0.25,
'roadIou':0.6,
'vehicleFlag':False,
'distanceFlag': False,
'modelSize':(640,360),
}
},
'models':
[
{
'weight':"../AIlib2/weights/highWay2/yolov5_%s_fp16.engine"% gpuName,###检测模型路径
'name':'yolov5',
'model':yolov5Model,
'par':{
'half':True,
'device':'cuda:0' ,
'conf_thres':0.25,
'iou_thres':0.45,
'allowedList':[0,1,2,3],
'segRegionCnt':1,
'trtFlag_det':False,
'trtFlag_seg':False,
"score_byClass":{"0":0.25,"1":0.3,"2":0.3,"3":0.3 } },
},
{
'weight':'../AIlib2/weights/conf/highWay2/stdc_360X640.pth',
'par':{
'modelSize':(640,360),
'mean':(0.485, 0.456, 0.406),
'std' :(0.229, 0.224, 0.225),
'predResize':True,
'numpy':False,
'RGB_convert_first':True,
'seg_nclass':3},###分割模型预处理参数
'model':stdcModel,
'name':'stdc'
}
],
'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,5,6,7,8,9] ],###控制哪些检测类别显示、输出
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.25,
"classes": 9,
"rainbows": COLOR
},
'txtFontSize': 20,
'digitFont': {
'line_thickness': 2,
'boxLine_thickness': 1,
'fontSize': 1.0,
'waterLineColor': (0, 255, 255),
'segLineShow': False,
'waterLineWidth': 2
}
})
EPIDEMIC_PREVENTION_MODEL = ("4", "004", "防疫模型", None, None)
PLATE_MODEL = ("5", "005", "车牌模型", None, None)
VEHICLE_MODEL = ("6", "006", "车辆模型", 'vehicle', lambda device, gpuName: {
'device': device,
'labelnames': ["车辆"],
'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100},
'postProcess':{'function':default_mix,'pars':{ }},
'models':
[
{
'weight':"../AIlib2/weights/vehicle/yolov5_%s_fp16.engine"% gpuName,###检测模型路径
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,
'device':'cuda:0' ,
'conf_thres':0.25,
'iou_thres':0.45,
'allowedList':[0,1,2,3],
'segRegionCnt':1,
'trtFlag_det':False,
'trtFlag_seg':False,
"score_byClass":{"0":0.25,"1":0.3,"2":0.3,"3":0.3 } },
}
],
'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'txtFontSize': 40,
'digitFont': {
'line_thickness': 2,
'boxLine_thickness': 1,
'fontSize': 1.0,
'waterLineColor': (0, 255, 255),
'segLineShow': False,
'waterLineWidth': 3
}
})
PEDESTRIAN_MODEL = ("7", "007", "行人模型", 'pedestrian', lambda device, gpuName: {
'device': device,
'labelnames': ["行人"],
'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100},
'postProcess':{'function':default_mix,'pars':{ }},
'models':
[
{
'weight':"../AIlib2/weights/pedestrian/yolov5_%s_fp16.engine"% gpuName,###检测模型路径
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,'device':'cuda:0' ,'conf_thres':0.25,'iou_thres':0.45,'allowedList':[0,1,2,3],'segRegionCnt':1, 'trtFlag_det':False,'trtFlag_seg':False, "score_byClass":{"0":0.25,"1":0.3,"2":0.3,"3":0.3 } },
}
],
'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'digitFont': {
'line_thickness': 2,
'boxLine_thickness': 1,
'fontSize': 1.0,
'segLineShow': False,
'waterLineColor': (0, 255, 255),
'waterLineWidth': 3
}
})
SMOGFIRE_MODEL = ("8", "008", "烟火模型", 'smogfire', lambda device, gpuName: {
'device': device,
'labelnames': ["烟雾", "火焰"],
'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100},
'postProcess':{'function':default_mix,'pars':{ }},
'models':
[
{
'weight':"../AIlib2/weights/smogfire/yolov5_%s_fp16.engine"% gpuName,###检测模型路径
#'weight':'../AIlib2/weights/conf/%s/yolov5.pt'%(opt['business'] ),
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,'device':'cuda:0' ,'conf_thres':0.25,'iou_thres':0.45,'allowedList':[0,1,2,3],'segRegionCnt':1, 'trtFlag_det':False,'trtFlag_seg':False, "score_byClass":{"0":0.25,"1":0.3,"2":0.3,"3":0.3 } },
}
],
'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'txtFontSize': 40,
'digitFont': {
'line_thickness': 2,
'boxLine_thickness': 1,
'fontSize': 1.0,
'segLineShow': False,
'waterLineColor': (0, 255, 255),
'waterLineWidth': 3
}
})
ANGLERSWIMMER_MODEL = ("9", "009", "钓鱼游泳模型", 'AnglerSwimmer', lambda device, gpuName: {
'device': device,
'labelnames': ["钓鱼", "游泳"],
'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100},
'postProcess':{'function':default_mix,'pars':{ }},
'models':
[
{
'weight':"../AIlib2/weights/AnglerSwimmer/yolov5_%s_fp16.engine"% gpuName,###检测模型路径
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,'device':'cuda:0' ,'conf_thres':0.25,'iou_thres':0.45,'allowedList':[0,1,2,3],'segRegionCnt':1, 'trtFlag_det':False,'trtFlag_seg':False, "score_byClass":{"0":0.25,"1":0.3,"2":0.3,"3":0.3 } },
}
],
'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'txtFontSize': 40,
'digitFont': {
'line_thickness': 2,
'boxLine_thickness': 1,
'fontSize': 1.0,
'segLineShow': False,
'waterLineColor': (0, 255, 255),
'waterLineWidth': 3
},
})
COUNTRYROAD_MODEL = ("10", "010", "乡村模型", 'countryRoad', lambda device, gpuName: {
'device': device,
'labelnames': ["违法种植"],
'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100},
'postProcess':{'function':default_mix,'pars':{ }},
'models':
[
{
'weight':"../AIlib2/weights/countryRoad/yolov5_%s_fp16.engine"% gpuName,###检测模型路径
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,'device':'cuda:0' ,'conf_thres':0.25,'iou_thres':0.45,'allowedList':[0,1,2,3],'segRegionCnt':1, 'trtFlag_det':False,'trtFlag_seg':False, "score_byClass":{"0":0.25,"1":0.3,"2":0.3,"3":0.3 } },
}
],
'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'txtFontSize': 40,
'digitFont': {
'line_thickness': 2,
'boxLine_thickness': 1,
'fontSize': 1.0,
'segLineShow': False,
'waterLineColor': (0, 255, 255),
'waterLineWidth': 3
}
})
SHIP_MODEL = ("11", "011", "船只模型", 'ship2', lambda device, gpuName: {
'obbModelPar': {
'labelnames': ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "船只"],
'model_size': (608, 608),
'K': 100,
'conf_thresh': 0.3,
'down_ratio': 4,
'num_classes': 15,
'dataset': 'dota',
'heads': {
'hm': None,
'wh': 10,
'reg': 2,
'cls_theta': 1
},
'mean': (0.5, 0.5, 0.5),
'std': (1, 1, 1),
'half': False,
'test_flag': True,
'decoder': None,
'weights': '../AIlib2/weights/ship2/obb_608X608_%s_fp16.engine' % gpuName
},
'trackPar': {
'sort_max_age': 2, # 跟踪链断裂时允许目标消失最大的次数。超过之后,会认为是新的目标。
'sort_min_hits': 3, # 每隔目标连续出现的次数,超过这个次数才认为是一个目标。
'sort_iou_thresh': 0.2, # 检测最小的置信度。
'det_cnt': 10, # 每隔几次做一个跟踪和检测默认10。
'windowsize': 29, # 轨迹平滑长度一定是奇数表示每隔几帧做一平滑默认29。一个目标在多个帧中出现每一帧中都有一个位置这些位置的连线交轨迹。
'patchCnt': 100, # 每次送入图像的数量不宜少于100帧。
},
'device': "cuda:%s" % device,
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'drawBox': False,
'drawPar': {
"rainbows": COLOR,
'digitWordFont': {
'line_thickness': 2,
'boxLine_thickness': 1,
'wordSize': 40,
'fontSize': 1.0,
'label_location': 'leftTop'
}
},
'labelnames': ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "船只"]
})
BAIDU_MODEL = ("12", "012", "百度AI图片识别模型", None, None)
CHANNEL_EMERGENCY_MODEL = ("13", "013", "航道模型", 'channelEmergency', lambda device, gpuName: {
'device': device,
'labelnames': [""],
'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100},
'postProcess':{'function':default_mix,'pars':{ }},
'models':
[
{
'weight':"../AIlib2/weights/channelEmergency/yolov5_%s_fp16.engine"% gpuName,###检测模型路径
#'weight':'../AIlib2/weights/conf/%s/yolov5.pt'%(opt['business'] ),
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,'device':'cuda:0' ,'conf_thres':0.25,'iou_thres':0.45,'allowedList':[0,1,2,3],'segRegionCnt':1, 'trtFlag_det':False,'trtFlag_seg':False, "score_byClass":{"0":0.25,"1":0.3,"2":0.3,"3":0.3 } },
}
],
'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [] ],###控制哪些检测类别显示、输出
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'txtFontSize': 40,
'digitFont': {
'line_thickness': 2,
'boxLine_thickness': 1,
'fontSize': 1.0,
'segLineShow': False,
'waterLineColor': (0, 255, 255),
'waterLineWidth': 3
}
})
RIVER2_MODEL = ("15", "015", "河道检测模型", 'river2', lambda device, gpuName: {
'device': device,
'labelnames': ["漂浮物", "岸坡垃圾", "排口", "违建", "菜地", "水生植物", "河湖人员", "钓鱼人员", "船只",
"蓝藻"],
'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100},
'postProcess':{'function':riverDetSegMixProcess_N,'pars':{'slopeIndex':[1,3,4,7], 'riverIou':0.1}}, #分割和检测混合处理的函数
'models':
[
{
'weight':"../AIlib2/weights/river2/yolov5_%s_fp16.engine"% gpuName,###检测模型路径
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,'device':'cuda:0' ,'conf_thres':0.25,'iou_thres':0.45,'allowedList':[0,1,2,3],'segRegionCnt':1, 'trtFlag_det':False,'trtFlag_seg':False, "score_byClass":{"0":0.25,"1":0.3,"2":0.3,"3":0.3 } },
},
{
'weight':'../AIlib2/weights/conf/river2/stdc_360X640.pth',
'par':{
'modelSize':(640,360),'mean':(0.485, 0.456, 0.406),'std' :(0.229, 0.224, 0.225),'numpy':False, 'RGB_convert_first':True,'seg_nclass':2},###分割模型预处理参数
'model':stdcModel,
'name':'stdc'
}
],
'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.3,
"ovlap_thres_crossCategory": 0.65,
"classes": 5,
"rainbows": COLOR
},
'txtFontSize': 80,
'digitFont': {
'line_thickness': 2,
'boxLine_thickness': 1,
'fontSize': 1.0,
'segLineShow': False,
'waterLineColor': (0, 255, 255),
'waterLineWidth': 3
}
})
CITY_MANGEMENT_MODEL = ("16", "016", "城管模型", 'cityMangement2', lambda device, gpuName: {
'device': device,
'labelnames': ["车辆", "垃圾", "商贩", "违停"],
'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':5,'windowsize':29,'patchCnt':100},
'postProcess':{
'function':dmpr_yolo_stdc,
'pars':{'carCls':0 ,'illCls':3,'scaleRatio':0.5,'border':80}
},
'models':[
{
'weight':"../AIlib2/weights/cityMangement3/yolov5_%s_fp16.engine"% gpuName,###检测模型路径
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,'device':'cuda:0' ,'conf_thres':0.25,'iou_thres':0.45,'allowedList':[0,1,2,3],'segRegionCnt':1, 'trtFlag_det':False,'trtFlag_seg':False, "score_byClass":{"0":0.8,"1":0.5,"2":0.5,"3":0.5 } }
},
{
'weight':"../AIlib2/weights/cityMangement3/dmpr_%s.engine"% gpuName,###DMPR模型路径
'par':{
'depth_factor':32,'NUM_FEATURE_MAP_CHANNEL':6,'dmpr_thresh':0.3, 'dmprimg_size':640,
'name':'dmpr'
},
'model':DMPRModel,
'name':'dmpr'
},
{
'weight':"../AIlib2/weights/cityMangement3/stdc_360X640_%s_fp16.engine"% gpuName,###分割模型路径
'par':{
'modelSize':(640,360),'mean':(0.485, 0.456, 0.406),'std' :(0.229, 0.224, 0.225),'predResize':True,'numpy':False, 'RGB_convert_first':True,'seg_nclass':2},###分割模型预处理参数
'model':stdcModel,
'name':'stdc'
}
],
'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,5,6,7,8,9] ],###控制哪些检测类别显示、输出
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'txtFontSize': 20,
'digitFont': {
'line_thickness': 2,
'boxLine_thickness': 1,
'fontSize': 1.0,
'segLineShow': False,
'waterLineColor': (0, 255, 255),
'waterLineWidth': 2
}
})
DROWING_MODEL = ("17", "017", "人员落水模型", 'drowning', lambda device, gpuName: {
'device': device,
'labelnames': ["人头", "", "船只"],
'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100},
'postProcess':{'function':mixDrowing_water_postprocess_N,
'pars':{ }},
'models':
[
{
'weight':"../AIlib2/weights/drowning/yolov5_%s_fp16.engine"% gpuName,###检测模型路径
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,'device':'cuda:0' ,'conf_thres':0.25,'iou_thres':0.45,'allowedList':[0,1,2,3],'segRegionCnt':1, 'trtFlag_det':False,'trtFlag_seg':False, "score_byClass":{"0":0.25,"1":0.3,"2":0.3,"3":0.3 } },
},
{
'weight':'../AIlib2/weights/conf/drowning/stdc_360X640.pth',
'par':{
'modelSize':(640,360),'mean':(0.485, 0.456, 0.406),'std' :(0.229, 0.224, 0.225),'predResize':True,'numpy':False, 'RGB_convert_first':True,'seg_nclass':2},###分割模型预处理参数
'model':stdcModel,
'name':'stdc'
}
],
'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,5,6,7,8,9] ],###控制哪些检测类别显示、输出
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.25,
"classes": 9,
"rainbows": COLOR
},
'txtFontSize': 20,
'digitFont': {
'line_thickness': 2,
'boxLine_thickness': 1,
'fontSize': 1.0,
'waterLineColor': (0, 255, 255),
'segLineShow': False,
'waterLineWidth': 2
}
})
NOPARKING_MODEL = (
"18", "018", "城市违章模型", 'noParking', lambda device, gpuName: {
'device': device,
'labelnames': ["车辆", "违停"],
'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100},
'postProcess':{'function':mixNoParking_road_postprocess_N,
'pars': { 'roundness': 0.3, 'cls': 9, 'laneArea': 10, 'laneAngleCha': 5 ,'RoadArea': 16000,'fitOrder':2, 'modelSize':(640,360)}
} ,
'models':
[
{
'weight':"../AIlib2/weights/noParking/yolov5_%s_fp16.engine"% gpuName,###检测模型路径
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,'device':'cuda:0' ,'conf_thres':0.25,'iou_thres':0.45,'allowedList':[0,1,2,3],'segRegionCnt':1, 'trtFlag_det':False,'trtFlag_seg':False, "score_byClass":{"0":0.25,"1":0.3,"2":0.3,"3":0.3 } },
},
{
'weight':'../AIlib2/weights/conf/noParking/stdc_360X640.pth',
'par':{
'modelSize':(640,360),'mean':(0.485, 0.456, 0.406),'std' :(0.229, 0.224, 0.225),'predResize':True,'numpy':False, 'RGB_convert_first':True,'seg_nclass':4},###分割模型预处理参数
'model':stdcModel,
'name':'stdc'
}
],
'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,5,6,7,8,9] ],###控制哪些检测类别显示、输出
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.25,
"classes": 9,
"rainbows": COLOR
},
'txtFontSize': 20,
'digitFont': {
'line_thickness': 2,
'boxLine_thickness': 1,
'fontSize': 1.0,
'waterLineColor': (0, 255, 255),
'segLineShow': False,
'waterLineWidth': 2
}
}
)
CITYROAD_MODEL = ("20", "020", "城市公路模型", 'cityRoad', lambda device, gpuName: {
'device': device,
'labelnames': ["护栏", "交通标志", "非交通标志", "施工", "施工"],
'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100},
'postProcess':{'function':default_mix,'pars':{ }},
'models':
[
{
'weight':"../AIlib2/weights/cityRoad/yolov5_%s_fp16.engine"% gpuName,###检测模型路径
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,'device':'cuda:0' ,'conf_thres':0.8,'iou_thres':0.45,'allowedList':[0,1,2,3],'segRegionCnt':1, 'trtFlag_det':False,'trtFlag_seg':False, "score_byClass":{"0":0.25,"1":0.3,"2":0.3,"3":0.3 } },
}
],
'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出
'postFile': {
"name": "post_process",
"conf_thres": 0.8,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'txtFontSize': 40,
'digitFont': {
'line_thickness': 2,
'boxLine_thickness': 1,
'fontSize': 1.0,
'segLineShow': False,
'waterLineColor': (0, 255, 255),
'waterLineWidth': 3
}
})
POTHOLE_MODEL = ("23", "023", "坑槽检测模型", 'pothole', lambda device, gpuName: { # 目前集成到另外的模型中去了 不单独使用
'device': device,
'labelnames': ["坑槽"],
'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':3,'windowsize':29,'patchCnt':100},
'postProcess':{'function':default_mix,'pars':{ }},
'models':
[
{
'weight':"../AIlib2/weights/pothole/yolov5_%s_fp16.engine"% gpuName,###检测模型路径
'name':'yolov5',
'model':yolov5Model,
'par':{ 'half':True,'device':'cuda:0' ,'conf_thres':0.25,'iou_thres':0.45,'allowedList':[0,1,2,3],'segRegionCnt':1, 'trtFlag_det':False,'trtFlag_seg':False, "score_byClass":{"0":0.25,"1":0.3,"2":0.3,"3":0.3}},
}
],
'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0]],###控制哪些检测类别显示、输出
'postFile': {
"name": "post_process",
"conf_thres": 0.25,
"iou_thres": 0.45,
"classes": 5,
"rainbows": COLOR
},
'txtFontSize': 40,
'digitFont': {
'line_thickness': 2,
'boxLine_thickness': 1,
'fontSize': 1.0,
'segLineShow': False,
'waterLineColor': (0, 255, 255),
'waterLineWidth': 3
},
})
@staticmethod
def checkCode(code):
for model in ModelType2:
if model.value[1] == code:
return True
return False
'''
参数1: 检测目标名称
参数2: 检测目标
参数3: 初始化百度检测客户端
'''
@unique
class BaiduModelTarget2(Enum):
VEHICLE_DETECTION = (
"车辆检测", 0, lambda client0, client1, url, request_id: client0.vehicleDetectUrl(url, request_id))
HUMAN_DETECTION = (
"人体检测与属性识别", 1, lambda client0, client1, url, request_id: client1.bodyAttr(url, request_id))
PEOPLE_COUNTING = ("人流量统计", 2, lambda client0, client1, url, request_id: client1.bodyNum(url, request_id))
BAIDU_MODEL_TARGET_CONFIG2 = {
BaiduModelTarget2.VEHICLE_DETECTION.value[1]: BaiduModelTarget2.VEHICLE_DETECTION,
BaiduModelTarget2.HUMAN_DETECTION.value[1]: BaiduModelTarget2.HUMAN_DETECTION,
BaiduModelTarget2.PEOPLE_COUNTING.value[1]: BaiduModelTarget2.PEOPLE_COUNTING
}
EPIDEMIC_PREVENTION_CONFIG = {1: "行程码", 2: "健康码"}
# 模型分析方式
@unique
class ModelMethodTypeEnum2(Enum):
# 方式一: 正常识别方式
NORMAL = 1
# 方式二: 追踪识别方式
TRACE = 2

View File

@ -0,0 +1,18 @@
from enum import Enum, unique
# 录屏状态枚举
@unique
class RecordingStatus(Enum):
RECORDING_WAITING = ("5", "待录制")
RECORDING_RETRYING = ("10", "重试中")
RECORDING_RUNNING = ("15", "录制中")
RECORDING_SUCCESS = ("20", "录制完成")
RECORDING_TIMEOUT = ("25", "录制超时")
RECORDING_FAILED = ("30", "录制失败")

33
enums/StatusEnum.py Normal file
View File

@ -0,0 +1,33 @@
from enum import Enum, unique
@unique
class PushStreamStatus(Enum):
WAITING = (5, "待推流")
RETRYING = (10, "重试中")
RUNNING = (15, "推流中")
STOPPING = (20, "停止中")
SUCCESS = (25, "完成")
TIMEOUT = (30, "超时")
FAILED = (35, "失败")
@unique
class ExecuteStatus(Enum):
WAITING = (5, "待执行")
RUNNING = (10, "执行中")
STOPPING = (15, "停止中")
SUCCESS = (20, "执行完成")
TIMEOUT = (25, "超时")
FAILED = (30, "失败")

0
enums/__init__.py Normal file
View File

View File

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
from loguru import logger
"""
自定义异常
"""
class ServiceException(Exception): # 继承异常类
def __init__(self, code, msg, desc=None):
self.code = code
if desc is None:
self.msg = msg
else:
self.msg = msg % desc
def __str__(self):
logger.error("异常编码:{}, 异常描述:{}", self.code, self.msg)

0
exception/__init__.py Normal file
View File

0
font/__init__.py Normal file
View File

BIN
font/simsun.ttc Normal file

Binary file not shown.

BIN
image/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

118
requirements.txt Normal file
View File

@ -0,0 +1,118 @@
Package Version
-------------------------- ------------
aiohttp 3.8.4
aiosignal 1.3.1
alibabacloud-credentials 0.3.2
alibabacloud-endpoint-util 0.0.3
alibabacloud-gateway-spi 0.0.1
alibabacloud-openapi-util 0.2.1
alibabacloud-tea 0.3.1
alibabacloud-tea-openapi 0.3.7
alibabacloud-tea-util 0.3.8
alibabacloud-tea-xml 0.0.2
alibabacloud-vod20170321 2.16.16
aliyun-python-sdk-core 2.13.36
aliyun-python-sdk-core-v3 2.13.33
aliyun-python-sdk-kms 2.16.0
aliyun-python-sdk-live 3.9.35
aliyun-python-sdk-vod 2.16.16
argon2-cffi 23.1.0
argon2-cffi-bindings 21.2.0
async-timeout 4.0.2
attrs 23.1.0
baidu-aip 4.16.10
Cerberus 1.3.4
certifi 2022.12.7
cffi 1.15.1
chardet 5.1.0
charset-normalizer 3.1.0
click 8.1.3
coloredlogs 15.0.1
contourpy 1.0.7
crcmod 1.7
cryptography 40.0.2
cycler 0.11.0
Cython 0.29.34
dotadevkit 1.3.0
easydict 1.10
ffmpeg-python 0.2.0
ffprobe 0.5
filelock 3.9.0
filetype 1.2.0
filterpy 1.4.5
flatbuffers 23.3.3
fonttools 4.39.3
frozenlist 1.3.3
future 0.18.3
gmpy2 2.1.2
GPUtil 1.4.0
humanfriendly 10.0
idna 3.4
imageio 2.31.1
importlib-resources 5.12.0
Jinja2 3.1.2
jmespath 0.10.0
kafka-python 2.0.2
kiwisolver 1.4.4
lazy_loader 0.3
loguru 0.7.0
MarkupSafe 2.1.1
matplotlib 3.7.1
meson 1.1.0
minio 7.2.7
mkl-fft 1.3.1
mkl-random 1.2.2
mkl-service 2.4.0
mpmath 1.3.0
multidict 6.0.4
networkx 2.8.4
numpy 1.24.3
nvidia-cublas-cu11 11.11.3.6
nvidia-cuda-runtime-cu11 11.8.89
nvidia-cudnn-cu11 8.9.0.131
onnx 1.14.0
onnxruntime 1.14.1
opencv-contrib-python 4.7.0.72
opencv-python 4.7.0.72
opencv-python-headless 4.7.0.72
oss2 2.17.0
packaging 23.1
paho-mqtt 2.1.0
pandas 2.0.1
Pillow 9.5.0
pip 23.0.1
protobuf 4.22.4
psutil 5.9.5
pycparser 2.21
pycryptodome 3.17
pyparsing 3.0.9
python-dateutil 2.8.2
python-vlc 3.0.18122
pytz 2023.3
PyWavelets 1.4.1
PyYAML 6.0
requests 2.30.0
ruamel.yaml 0.17.22
ruamel.yaml.clib 0.2.7
scikit-image 0.21.0
scipy 1.10.1
seaborn 0.12.2
setuptools 66.0.0
shapely 2.0.1
six 1.16.0
sympy 1.11.1
tensorrt 8.5.1.7
tifffile 2023.7.4
torch 1.9.1+cu111
torchaudio 2.0.0
torchvision 0.10.1+cu111
tqdm 4.65.0
triton 2.0.0
ttkbootstrap 1.10.1
typing_extensions 4.5.0
tzdata 2023.3
urllib3 2.0.2
voduploadsdk 1.0.2
wheel 0.38.4
yarl 1.9.2
zipp 3.15.0

5
scpCode.sh Normal file
View File

@ -0,0 +1,5 @@
scp -r common concurrency dsp_master.py entity enums exception font image __init__.py output __pycache__ readme.md service test util vodsdk thsw2@192.168.10.66:/home/thsw2/WJ/test/tuoheng_algN
scp -r common concurrency dsp_master.py entity enums exception font image __init__.py output __pycache__ readme.md service test util vodsdk thsw@192.168.10.11:/home/thsw/WJ/test/tuoheng_algN

602
service/Dispatcher.py Normal file
View File

@ -0,0 +1,602 @@
# -*- coding: utf-8 -*-
import time,os
from os.path import join
from traceback import format_exc
import json
from cerberus import Validator
from common.Constant import ONLINE_START_SCHEMA, ONLINE_STOP_SCHEMA, OFFLINE_START_SCHEMA, OFFLINE_STOP_SCHEMA, \
IMAGE_SCHEMA, RECORDING_START_SCHEMA, RECORDING_STOP_SCHEMA, PULL2PUSH_START_SCHEMA, PULL2PUSH_STOP_SCHEMA
from common.YmlConstant import service_yml_path, kafka_yml_path
from concurrency.FeedbackThread import FeedbackThread
from concurrency.uploadGPU import uploadGPUinfos
from concurrency.IntelligentRecognitionProcess2 import OnlineIntelligentRecognitionProcess2, \
OfflineIntelligentRecognitionProcess2, PhotosIntelligentRecognitionProcess2
from concurrency.Pull2PushStreamProcess import PushStreamProcess
from entity.FeedBack import message_feedback, recording_feedback, pull_stream_feedback
from enums.AnalysisStatusEnum import AnalysisStatus
from enums.AnalysisTypeEnum import AnalysisType
from enums.ExceptionEnum import ExceptionType
from enums.ModelTypeEnum import ModelMethodTypeEnum, ModelType
from enums.RecordingStatusEnum import RecordingStatus
from enums.StatusEnum import PushStreamStatus, ExecuteStatus
from exception.CustomerException import ServiceException
from loguru import logger
from multiprocessing import Queue
from concurrency.IntelligentRecognitionProcess import OnlineIntelligentRecognitionProcess, \
OfflineIntelligentRecognitionProcess, PhotosIntelligentRecognitionProcess, ScreenRecordingProcess
from util.CpuUtils import print_cpu_ex_status
from util.FileUtils import create_dir_not_exist
from util.GPUtils import get_first_gpu_name, print_gpu_ex_status, check_cude_is_available,select_best_server
from util.KafkaUtils import CustomerKafkaConsumer
from util.QueUtil import put_queue
from util.RWUtils import getConfigs
from kafka import KafkaProducer, KafkaConsumer
'''
分发服务
'''
class DispatcherService:
__slots__ = ('__context', '__feedbackThread', '__listeningProcesses', '__fbQueue', '__topics','__taskType', '__task_type',
'__kafka_config', '__recordingProcesses', '__pull2PushProcesses','__topicsPort','__gpuTopic','__role','__uploadGPUThread','__gpuDics','__producer')
def __init__(self, base_dir, env):
# 检测cuda是否活动
check_cude_is_available()
# 获取全局上下文配置
self.__context = getConfigs(join(base_dir, service_yml_path % env))
# 创建任务执行, 视频保存路径
create_dir_not_exist(join(base_dir, self.__context["video"]["file_path"]))
# 将根路径和环境设置到上下文中
self.__context["base_dir"], self.__context["env"] = base_dir, env
# 问题反馈线程
self.__feedbackThread,self.__uploadGPUThread, self.__fbQueue = None,None, Queue()
# 实时、离线、图片任务进程字典
self.__listeningProcesses = {}
# 录屏任务进程字典
self.__recordingProcesses = {}
# 转推流任务进程字典
self.__pull2PushProcesses = {}
self.__kafka_config = getConfigs(join(base_dir, kafka_yml_path % env))
self.__producer = KafkaProducer(
bootstrap_servers=self.__kafka_config['bootstrap_servers'],#tencent yun
value_serializer=lambda v: v.encode('utf-8'))
self.__gpuDics = { }#用于存储gpu信息的字典
self.__role = self.__context["role"]
self.__topics = [
self.__kafka_config["topic"]["dsp-alg-online-tasks-topic"], # 实时监听topic
self.__kafka_config["topic"]["dsp-alg-offline-tasks-topic"], # 离线监听topic
self.__kafka_config["topic"]["dsp-alg-image-tasks-topic"], # 图片监听topic
self.__kafka_config["topic"]["dsp-recording-task-topic"], # 录屏监听topic
self.__kafka_config["topic"]["dsp-push-stream-task-topic"] # 推流监听topic
]
self.__topicsPort = [
self.__kafka_config["topicPort"]["dsp-alg-online-tasks-topic"], # 实时监听topic
self.__kafka_config["topicPort"]["dsp-alg-offline-tasks-topic"], # 离线监听topic
self.__kafka_config["topicPort"]["dsp-alg-image-tasks-topic"], # 图片监听topic
self.__kafka_config["topicPort"]["dsp-recording-task-topic"], # 录屏监听topic
self.__kafka_config["topicPort"]["dsp-push-stream-task-topic"] # 推流监听topic
]
self.__gpuTopic = [self.__kafka_config["topicGPU"]]
if self.__role==1:
self.__topics = self.__topics + self.__topicsPort + self.__gpuTopic
# 对应topic的各个lambda表达式
self.__task_type = {
self.__topics[0]: (AnalysisType.ONLINE.value, lambda x, y: self.online(x, y),
lambda x, y, z: self.identify_method(x, y, z)),
self.__topics[1]: (AnalysisType.OFFLINE.value, lambda x, y: self.offline(x, y),
lambda x, y, z: self.identify_method(x, y, z)),
self.__topics[2]: (AnalysisType.IMAGE.value, lambda x, y: self.image(x, y),
lambda x, y, z: self.identify_method(x, y, z)),
self.__topics[3]: (AnalysisType.RECORDING.value, lambda x, y: self.recording(x, y),
lambda x, y, z: self.recording_method(x, y, z)),
self.__topics[4]: (AnalysisType.PULLTOPUSH.value, lambda x, y: self.pullStream(x, y),
lambda x, y, z: self.push_stream_method(x, y, z))
}
self.__taskType={
self.__kafka_config["topic"]["dsp-alg-online-tasks-topic"]:0, # 实时监听topic
self.__kafka_config["topic"]["dsp-alg-offline-tasks-topic"]:1, # 离线监听topic
self.__kafka_config["topic"]["dsp-alg-image-tasks-topic"]:2, # 图片监听topic
self.__kafka_config["topic"]["dsp-recording-task-topic"]:3, # 录屏监听topic
self.__kafka_config["topic"]["dsp-push-stream-task-topic"]:4 # 推流监听topic
}
gpu_name_array = get_first_gpu_name()
gpu_array = [g for g in ('3090', '2080', '4090', 'A10') if g in gpu_name_array]
gpu_name = '2080Ti'
if len(gpu_array) > 0:
if gpu_array[0] != '2080':
gpu_name = gpu_array[0]
else:
raise Exception("GPU资源不在提供的模型所支持的范围内请先提供对应的GPU模型")
logger.info("当前服务环境为: {}, 服务器GPU使用型号: {}", env, gpu_name)
self.__context["gpu_name"] = gpu_name
self.start_service()
# 服务调用启动方法
def start_service(self):
# 初始化kafka监听者
customerKafkaConsumer = CustomerKafkaConsumer(self.__kafka_config, topics=self.__topics)
####增加一个线程用于试试监控和发送gpu状态####
####
logger.info("(♥◠‿◠)ノ゙ DSP【算法调度服务】启动成功 服务器IP:{}".format(self.__kafka_config['bootstrap_servers'] ))
while True:
try:
# 检查任务进程运行情况,去除结束的任务
self.check_process_task()
# 启动反馈线程
self.start_feedback_thread()
self.start_uploadGPU_thread()
msg = customerKafkaConsumer.poll()
if msg is not None and len(msg) > 0:
for k, v in msg.items():
for m in v:
message = m.value
#如果收到的信息是gpu状态的话收到信息后更新自己的gpu服务器状态下面不再执行
if m.topic in self.__gpuTopic:
customerKafkaConsumer.commit_offset(m,'x'*16,False)
#更新机器资源现状
ip = message['System']['Local IP Address']
self.__gpuDics[ip]=message
continue
#如果收到的信息是门户消息收到信息后要根据Gpu状态转发到对应的机器。
elif m.topic in self.__topicsPort:
customerKafkaConsumer.commit_offset(m, 'y'*16)
#状态分析
#recondGpu={'hostname':'thsw2','IP':'192.168.10.66','gpuId':0}
recondGpu= select_best_server(self.__gpuDics)
if recondGpu is None:
print( 'recondGpu',recondGpu, ' self.__gpuDics: ',self.__gpuDics,' topic:',m.topic, ' message:',message )
continue
#转发消息
message['transmit_topic'] = m.topic + '-' + recondGpu['IP']
transmitMsg={'transmit':message}
msg_json = json.dumps( message )
future = self.__producer.send( message['transmit_topic'] ,msg_json)
try:
future.get(timeout=2)
logger.info( "转发消息成功消息topic:{},消息内容:{}",message['transmit_topic'],message )
except kafka_errors as e:
print('------transmitted error:',e)
logger.info("转发消息失败")
traceback.format_exc()
else:
requestId = message.get("request_id")
if requestId is None:
logger.error("请求参数格式错误, 请检查请求体格式是否正确message:%s"%(message))
continue
customerKafkaConsumer.commit_offset(m, requestId)
logger.info("当前拉取到的消息, topic:{}, offset:{}, partition: {}, body: {}, requestId:{}",
m.topic, m.offset, m.partition, message, requestId)
message['taskType']=self.__taskType[m.topic]
topic_method = self.__task_type[m.topic]
topic_method[2](topic_method[1], message, topic_method[0])
else:
print_gpu_ex_status()
print_cpu_ex_status(self.__context["base_dir"])
time.sleep(1)
except Exception:
logger.error("主线程异常:{}", format_exc())
def identify_method(self, handle_method, message, analysisType):
try:
check_cude_is_available()
handle_method(message, analysisType)
except ServiceException as s:
logger.error("消息监听异常:{}, requestId: {}", s.msg, message["request_id"])
put_queue(self.__fbQueue, message_feedback(message["request_id"], AnalysisStatus.FAILED.value, analysisType,
s.code, s.msg), timeout=1)
except Exception:
logger.error("消息监听异常:{}, requestId: {}", format_exc(), message["request_id"])
put_queue(self.__fbQueue, message_feedback(message["request_id"], AnalysisStatus.FAILED.value, analysisType,
ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
ExceptionType.SERVICE_INNER_EXCEPTION.value[1]), timeout=1)
finally:
del message
def push_stream_method(self, handle_method, message, analysisType):
try:
check_cude_is_available()
handle_method(message, analysisType)
except ServiceException as s:
logger.error("消息监听异常:{}, requestId: {}", s.msg, message['request_id'])
videoInfo = [{"id": url.get("id"), "status": PushStreamStatus.FAILED.value[0]} for url in
message.get("video_urls", []) if url.get("id") is not None]
put_queue(self.__fbQueue, pull_stream_feedback(message['request_id'], ExecuteStatus.FAILED.value[0],
s.code, s.msg, videoInfo), timeout=1)
except Exception:
logger.error("消息监听异常:{}, requestId: {}", format_exc(), message['request_id'])
videoInfo = [{"id": url.get("id"), "status": PushStreamStatus.FAILED.value[0]} for url in
message.get("video_urls", []) if url.get("id") is not None]
put_queue(self.__fbQueue, pull_stream_feedback(message.get("request_id"), ExecuteStatus.FAILED.value[0],
ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
ExceptionType.SERVICE_INNER_EXCEPTION.value[1], videoInfo),
timeout=1)
finally:
del message
def recording_method(self, handle_method, message, analysisType):
try:
check_cude_is_available()
handle_method(message, analysisType)
except ServiceException as s:
logger.error("消息监听异常:{}, requestId: {}", s.msg, message["request_id"])
put_queue(self.__fbQueue,
recording_feedback(message["request_id"], RecordingStatus.RECORDING_FAILED.value[0],
error_code=s.code, error_msg=s.msg), timeout=1)
except Exception:
logger.error("消息监听异常:{}, requestId: {}", format_exc(), message["request_id"])
put_queue(self.__fbQueue,
recording_feedback(message["request_id"], RecordingStatus.RECORDING_FAILED.value[0],
ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
ExceptionType.SERVICE_INNER_EXCEPTION.value[1]), timeout=1)
finally:
del message
# 开启实时进程
def startOnlineProcess(self, msg, analysisType):
#0521:
default_enabled = str(msg.get("defaultEnabled", "True")).lower() == "true"
if default_enabled:
print("执行默认程序defaultEnabled=True")
self.__context['service']['algSwitch'] = True
# 这里放默认逻辑的代码
else:
print("执行替代程序defaultEnabled=False")
# 这里放非默认逻辑的代码
self.__context['service']['algSwitch'] = False
print("---line264-Dispatcher.py---",self.__context)
if self.__listeningProcesses.get(msg["request_id"]):
logger.warning("实时重复任务请稍后再试requestId:{}", msg["request_id"])
return
model_type = self.__context["service"]["model"]["model_type"]
codes = [model.get("code") for model in msg["models"] if model.get("code")]
if ModelMethodTypeEnum.NORMAL.value == model_type or ModelType.ILLPARKING_MODEL.value[1] in codes:
coir = OnlineIntelligentRecognitionProcess(self.__fbQueue, msg, analysisType, self.__context)
else:
coir = OnlineIntelligentRecognitionProcess2(self.__fbQueue, msg, analysisType, self.__context)
coir.start()
logger.info("开始实时进程requestId:{},pid:{}, ppid:{}", msg["request_id"],os.getpid(),os.getppid())
self.__listeningProcesses[msg["request_id"]] = coir
# 结束实时进程
def stopOnlineProcess(self, msg):
ps = self.__listeningProcesses.get(msg["request_id"])
if ps is None:
logger.warning("未查询到该任务无法停止任务requestId:{}", msg["request_id"])
return
ps.sendEvent({"command": "stop"})
# 新增该函数用于向子任务发送命令algStartalgStop
def sendCmdToChildProcess(self, msg,cmd="algStart"):
ps = self.__listeningProcesses.get(msg["request_id"])
if ps is None:
logger.warning("未查询到该任务无法停止任务requestId:{}", msg["request_id"])
return
ps.sendEvent({"command": cmd})
@staticmethod
def check_process(listeningProcess):
for requestId in list(listeningProcess.keys()):
if not listeningProcess[requestId].is_alive():
del listeningProcess[requestId]
def check_process_task(self):
self.check_process(self.__listeningProcesses)
self.check_process(self.__recordingProcesses)
self.check_process(self.__pull2PushProcesses)
# 开启离线进程
def startOfflineProcess(self, msg, analysisType):
if self.__listeningProcesses.get(msg["request_id"]):
logger.warning("离线重复任务请稍后再试requestId:{}", msg["request_id"])
return
model_type = self.__context["service"]["model"]["model_type"]
codes = [model.get("code") for model in msg["models"] if model.get("code")]
if ModelMethodTypeEnum.NORMAL.value == model_type:
first = OfflineIntelligentRecognitionProcess(self.__fbQueue, msg, analysisType, self.__context)
else:
first = OfflineIntelligentRecognitionProcess2(self.__fbQueue, msg, analysisType, self.__context)
first.start()
self.__listeningProcesses[msg["request_id"]] = first
# 结束离线进程
def stopOfflineProcess(self, msg):
ps = self.__listeningProcesses.get(msg["request_id"])
if ps is None:
logger.warning("未查询到该任务无法停止任务requestId:{}", msg["request_id"])
return
ps.sendEvent({"command": "stop"})
# 开启图片分析进程
def startImageProcess(self, msg, analysisType):
pp = self.__listeningProcesses.get(msg["request_id"])
if pp is not None:
logger.warning("重复任务请稍后再试requestId:{}", msg["request_id"])
return
model_type = self.__context["service"]["model"]["model_type"]
codes = [model.get("code") for model in msg["models"] if model.get("code")]
if ModelMethodTypeEnum.NORMAL.value == model_type or ModelType.ILLPARKING_MODEL.value[1] in codes:
imaged = PhotosIntelligentRecognitionProcess(self.__fbQueue, msg, analysisType, self.__context)
else:
imaged = PhotosIntelligentRecognitionProcess2(self.__fbQueue, msg, analysisType, self.__context)
# 创建在线识别进程并启动
imaged.start()
self.__listeningProcesses[msg["request_id"]] = imaged
'''
校验kafka消息
'''
@staticmethod
def check_msg(msg, schema):
# #0521
# # 检查 defaultEnabled 是否为 True兼容字符串和布尔值
# default_enabled = str(msg1.get("defaultEnabled", "True")).lower() == "true"
# # 如果不是 True强制设置 command 为 'algStop'
# if not default_enabled and msg1["command"] == "algStart" :
# msg1["command"] = "algStop"
# msg = msg1
try:
v = Validator(schema, allow_unknown=True)
result = v.validate(msg)
if not result:
logger.error("参数校验异常: {}, requestId: {}", v.errors, msg["request_id"])
raise ServiceException(ExceptionType.ILLEGAL_PARAMETER_FORMAT.value[0],
ExceptionType.ILLEGAL_PARAMETER_FORMAT.value[1])
except ServiceException as s:
raise s
except Exception:
logger.error("参数校验异常: {}, requestId: {}", format_exc(), msg["request_id"])
raise ServiceException(ExceptionType.ILLEGAL_PARAMETER_FORMAT.value[0],
ExceptionType.ILLEGAL_PARAMETER_FORMAT.value[1])
'''
开启反馈线程用于发送消息
'''
def start_feedback_thread(self):
if self.__feedbackThread is None:
self.__feedbackThread = FeedbackThread(self.__fbQueue, self.__kafka_config)
self.__feedbackThread.setDaemon(True)
self.__feedbackThread.start()
time.sleep(1)
if self.__feedbackThread and not self.__feedbackThread.is_alive():
logger.error("反馈线程异常停止, 开始重新启动反馈线程!!!!!")
self.__feedbackThread = FeedbackThread(self.__fbQueue, self.__kafka_config)
self.__feedbackThread.setDaemon(True)
self.__feedbackThread.start()
time.sleep(1)
def start_uploadGPU_thread(self):
if self.__uploadGPUThread is None:
self.__uploadGPUThread = uploadGPUinfos(self.__context, self.__kafka_config)
self.__uploadGPUThread.setDaemon(True)
self.__uploadGPUThread.start()
time.sleep(1)
if self.__uploadGPUThread and not self.__uploadGPUThread.is_alive():
logger.error("反馈线程异常停止, 开始重新启动反馈线程!!!!!")
self.__uploadGPUThread = uploadGPUinfos(self.__context, self.__kafka_config)
self.__uploadGPUThread.setDaemon(True)
self.__uploadGPUThread.start()
time.sleep(1)
'''
在线分析逻辑
'''
#0520主要是在线分析 -- "algStart","algStop" 外部多增加一层逻辑
# def online(self, message, analysisType):
# if "start" == message.get("command"):
# self.check_msg(message, ONLINE_START_SCHEMA)
# if len(self.__listeningProcesses) >= int(self.__context['service']["task"]["limit"]):
# raise ServiceException(ExceptionType.NO_RESOURCES.value[0],
# ExceptionType.NO_RESOURCES.value[1])
# self.startOnlineProcess(message, analysisType)
# elif message.get("command") in ["algStart","algStop"]:
# self.sendCmdToChildProcess(message,cmd=message.get("command"))
# elif "stop" == message.get("command"):
# self.check_msg(message, ONLINE_STOP_SCHEMA)
# self.stopOnlineProcess(message)
# else:
# raise ServiceException(ExceptionType.ILLEGAL_PARAMETER_FORMAT.value[0],
# ExceptionType.ILLEGAL_PARAMETER_FORMAT.value[1])
def online(self, message, analysisType):
# #0521
# # 检查 defaultEnabled 是否为 True兼容字符串和布尔值
# #逻辑还是有问题 - 肯定是先判断是否为 true
# default_enabled = str(message1.get("defaultEnabled", "True")).lower() == "True"
# # 如果不是 True强制设置 command 为 'algStop'
# if not default_enabled :
# message.get("command")
# message = message1
# message = message
# print("line429",message)
if "start" == message.get("command"):
self.check_msg(message, ONLINE_START_SCHEMA)
if len(self.__listeningProcesses) >= int(self.__context['service']["task"]["limit"]):
raise ServiceException(ExceptionType.NO_RESOURCES.value[0],
ExceptionType.NO_RESOURCES.value[1])
self.startOnlineProcess(message, analysisType)
# elif (message.get("command") in ["algStart","algStop"] ) and (message.get("defaultEnabled",True)):
# self.sendCmdToChildProcess(message,cmd=message.get("command"))
elif (
message is not None # 防止 message 为 None
and isinstance(message, dict) # 确保 message 是字典
and (command := message.get("command")) in ["algStart", "algStop"] # Python 3.8+ 海象运算符
and message.get("defaultEnabled", True) is not False # 显式排除 False
):
self.sendCmdToChildProcess(message, cmd=command)
elif "stop" == message.get("command"):
self.check_msg(message, ONLINE_STOP_SCHEMA)
self.stopOnlineProcess(message)
else:
raise ServiceException(ExceptionType.ILLEGAL_PARAMETER_FORMAT.value[0],
ExceptionType.ILLEGAL_PARAMETER_FORMAT.value[1])
def offline(self, message, analysisType):
# #0521
# # 检查 defaultEnabled 是否为 True兼容字符串和布尔值
# default_enabled = str(message.get("defaultEnabled", "True")).lower() == "true"
# # 如果不是 True强制设置 command 为 'algStop'
# if not default_enabled and message["command"] == "algStart" :
# message["command"] = "algStop"
# message = message
# print("line429",message)
if "start" == message.get("command"):
self.check_msg(message, OFFLINE_START_SCHEMA)
if len(self.__listeningProcesses) >= int(self.__context['service']["task"]["limit"]):
raise ServiceException(ExceptionType.NO_RESOURCES.value[0],
ExceptionType.NO_RESOURCES.value[1])
self.startOfflineProcess(message, analysisType)
elif message.get("command") in ["algStart","algStop"]:
self.sendCmdToChildProcess( message,cmd=message.get("command"))
elif "stop" == message.get("command"):
self.check_msg(message, OFFLINE_STOP_SCHEMA)
self.stopOfflineProcess(message)
else:
raise ServiceException(ExceptionType.ILLEGAL_PARAMETER_FORMAT.value[0],
ExceptionType.ILLEGAL_PARAMETER_FORMAT.value[1])
def image(self, message, analysisType):
if "start" == message.get("command"):
self.check_msg(message, IMAGE_SCHEMA)
if len(self.__listeningProcesses) >= int(self.__context['service']["task"]["image"]["limit"]):
raise ServiceException(ExceptionType.NO_RESOURCES.value[0],
ExceptionType.NO_RESOURCES.value[1])
self.startImageProcess(message, analysisType)
else:
raise ServiceException(ExceptionType.ILLEGAL_PARAMETER_FORMAT.value[0],
ExceptionType.ILLEGAL_PARAMETER_FORMAT.value[1])
def recording(self, message, analysisType):
if "start" == message.get("command"):
self.check_msg(message, RECORDING_START_SCHEMA)
if len(self.__recordingProcesses) >= int(self.__context['service']["task"]["limit"]):
raise ServiceException(ExceptionType.NO_RESOURCES.value[0],
ExceptionType.NO_RESOURCES.value[1])
self.startRecordingProcess(message, analysisType)
elif "stop" == message.get("command"):
self.check_msg(message, RECORDING_STOP_SCHEMA)
self.stopRecordingProcess(message)
else:
raise ServiceException(ExceptionType.ILLEGAL_PARAMETER_FORMAT.value[0],
ExceptionType.ILLEGAL_PARAMETER_FORMAT.value[1])
# 开启录屏进程
def startRecordingProcess(self, msg, analysisType):
if self.__listeningProcesses.get(msg["request_id"]):
logger.warning("重复任务请稍后再试requestId:{}", msg["request_id"])
return
srp = ScreenRecordingProcess(self.__fbQueue, self.__context, msg, analysisType)
srp.start()
self.__recordingProcesses[msg["request_id"]] = srp
# 结束录屏进程
def stopRecordingProcess(self, msg):
rdp = self.__recordingProcesses.get(msg["request_id"])
if rdp is None:
logger.warning("未查询到该任务无法停止任务requestId:{}", msg["request_id"])
return
rdp.sendEvent({"command": "stop"})
def pullStream(self, message, analysisType):
if "start" == message.get("command"):
self.check_msg(message, PULL2PUSH_START_SCHEMA)
if len(self.__pull2PushProcesses) >= int(self.__context['service']["task"]["limit"]):
raise ServiceException(ExceptionType.NO_RESOURCES.value[0],
ExceptionType.NO_RESOURCES.value[1])
self.startPushStreamProcess(message, analysisType)
elif "stop" == message.get("command"):
self.check_msg(message, PULL2PUSH_STOP_SCHEMA)
self.stopPushStreamProcess(message)
else:
raise ServiceException(ExceptionType.ILLEGAL_PARAMETER_FORMAT.value[0],
ExceptionType.ILLEGAL_PARAMETER_FORMAT.value[1])
def startPushStreamProcess(self, msg, analysisType):
if self.__pull2PushProcesses.get(msg["request_id"]):
logger.warning("重复任务请稍后再试requestId:{}", msg["request_id"])
return
srp = PushStreamProcess(self.__fbQueue, self.__context, msg, analysisType)
srp.start()
self.__pull2PushProcesses[msg["request_id"]] = srp
# 结束录屏进程
def stopPushStreamProcess(self, msg):
srp = self.__pull2PushProcesses.get(msg["request_id"])
if srp is None:
logger.warning("未查询到该任务无法停止任务requestId:{}", msg["request_id"])
return
srp.sendEvent({"command": "stop", "videoIds": msg.get("video_ids", [])})

0
service/__init__.py Normal file
View File

40
start.sh Normal file
View File

@ -0,0 +1,40 @@
#!/bin/bash
current_dir=$(cd "$(dirname "$0")"; pwd)
active=$(basename "$(dirname "$current_dir")")
conda_env="alg"
echo "当前程序所在目录: $current_dir, 当前程序启动环境: $active"
if [[ "a${active}" != "adev" && "a${active}" != "atest" && "a${active}" != "aprod" ]]; then
echo "###############################################################";
echo "启动失败, 当前环境只支持dev、test、prod";
echo "环境是根据程序所在目录自动匹配的, 请检测程序路径配置是否正确!";
echo "###############################################################";
exit 1
fi
cd $current_dir
pid=`ps x | grep "/home/th/anaconda3/envs/${conda_env}/bin/python3.8" | grep -v grep | awk '{print $1}'`
if [ -n "$pid" ]; then
echo "alg进程已存在, 进程id: $pid"
kill -9 ${pid};
echo "杀掉当前alg进程, 进程号:$pid"
sleep 1
pid_1=`ps x | grep "/home/th/anaconda3/envs/${conda_env}/bin/python3.8" | grep -v grep | awk '{print $1}'`
if [ -n "$pid_1" ]; then
echo "###############################################################";
echo "杀掉alg进程失败"
echo "###############################################################";
exit 1
else
echo "杀掉alg进程成功"
fi
fi
nohup /home/th/anaconda3/envs/${conda_env}/bin/python3.8 dsp_master.py ${active} > /dev/null 2>&1 &
sleep 1
pid_end=`ps x | grep "/home/th/anaconda3/envs/${conda_env}/bin/python3.8" | grep -v grep | awk '{print $1}'`
if [ -n "$pid_end" ]; then
echo "alg启动成功, $pid_end"
else
echo "###############################################################";
echo "alg启动失败!!!!!!!!!!!!!!!!!!!!!"
echo "###############################################################";
exit 1
fi

19
stop.sh Normal file
View File

@ -0,0 +1,19 @@
#!/bin/bash
conda_env="alg"
pid=`ps x | grep "/home/th/anaconda3/envs/${conda_env}/bin/python3.8" | grep -v grep | awk '{print $1}'`
if [ -n "$pid" ]; then
kill -9 ${pid};
echo "杀掉当前alg进程, 进程号:$pid"
fi
sleep 1
pid_end=`ps x | grep "/home/th/anaconda3/envs/${conda_env}/bin/python3.8" | grep -v grep | awk '{print $1}'`
if [ -n "$pid_end" ]; then
echo "###############################################################";
echo "alg停止失败, $pid_end"
echo "###############################################################";
exit 1
else
echo "###############################################################";
echo "alg停止成功!!!!!!!!!!!!!!!!!!!!!"
echo "###############################################################";
fi

3
test/__init__.py Normal file
View File

@ -0,0 +1,3 @@
dd = {}
print(dd.get('name', 'aaa'))

0
test/aliyun/__init__.py Normal file
View File

BIN
test/aliyun/aaa.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

119
test/aliyun/ossdemo.py Normal file
View File

@ -0,0 +1,119 @@
# -*- coding: utf-8 -*-
import datetime
import cv2
import oss2
import time
from loguru import logger
'''
图片上传使用OSS
1. 阿里云对象存储OSS官网地址https://help.aliyun.com/product/31815.html?spm=a2c4g.32006.0.0.8c546cf0BpkAQ2
2. 阿里云对象存储OSS SDK示例地址https://help.aliyun.com/document_detail/32006.html?spm=a2c4g.32006.0.0.66874b78q1pwLa
3. python安装SDK地址 https://help.aliyun.com/document_detail/85288.html?spm=a2c4g.32026.0.0.3f24417coCphWj
4. 安装SDK pip install oss2
5. 安装python-devel
安装python-devel
由于SDK需要crcmod库计算CRC校验码而crcmod依赖Python.h文件如果系统缺少这个头文件安装SDK不会失败但crcmod的C扩展模式安装会失败因此导致上传下载等操作效率非常低下
如果python-devel包不存在则首先要安装这个包
对于Windows系统和Mac OS X系统由于安装Python的时候会将Python依赖的头文件一并安装因此您无需安装python-devel
对于CentOSRHELFedora系统请执行以下命令安装python-devel
sudo yum install python-devel
对于DebianUbuntu系统请执行以下命令安装python-devel
sudo apt-get install python-dev
6图片域名地址https://image.t-aaron.com/
'''
class AliyunOssSdk:
def __init__(self):
self.__client = None
self.__access_key = 'LTAI5tMiefafZ6br4zmrQWv9'
self.__access_secret = 'JgzQjSCkwZ7lefZO6egOArw38YH1Tk'
self.__endpoint = 'http://oss-cn-shanghai.aliyuncs.com'
self.__bucket = 'ta-tech-image'
def get_oss_bucket(self):
if not self.__client:
auth = oss2.Auth(self.__access_key, self.__access_secret)
self.__client = oss2.Bucket(auth, self.__endpoint, self.__bucket, connect_timeout=30)
def upload_file(self, updatePath, fileByte):
logger.info("开始上传文件到oss!")
MAX_RETRIES = 3
retry_count = 0
while True:
try:
self.get_oss_bucket()
result = self.__client.put_object(updatePath, fileByte)
return result
logger.info("上传文件到oss成功!")
break
except Exception as e:
self.__client = None
retry_count += 1
time.sleep(1)
logger.info("上传文件到oss失败, 重试次数:{}", retry_count)
if retry_count > MAX_RETRIES:
logger.exception("上传文件到oss重试失败:{}", e)
raise e
YY_MM_DD_HH_MM_SS = "%Y-%m-%d %H:%M:%S"
YMDHMSF = "%Y%m%d%H%M%S%f"
def generate_timestamp():
"""根据当前时间获取时间戳,返回整数"""
return int(time.time())
def now_date_to_str(fmt=None):
if fmt is None:
fmt = YY_MM_DD_HH_MM_SS
return datetime.datetime.now().strftime(fmt)
if __name__ == "__main__":
# 初始化oss对象
ossClient = AliyunOssSdk()
# 读取本地图片
image_frame = cv2.imread('aaa.jpeg')
or_result, or_image = cv2.imencode(".jpg", image_frame)
# 图片名称命名规则
# 1、base_dir 基本文件夹名称,由拓恒公司传参
# 2、time_now 现在的时间
# 3、current_frame 当前视频的帧数
# 4、last_frame 如果有跳帧操作, 填写跳帧的步长如果没有和current_frame参数保持一致
# 5、random_num 随机时间字符串
# 6、mode_type 类型实时视频直播的方式用online 离线视频直播填写视频地址识别offline
# 7、requestId 请求id, 拓恒公司传参
# 8、image_type 原图用OR AI识别后的图片用AI
random_num = now_date_to_str(YMDHMSF)
time_now = now_date_to_str("%Y-%m-%d-%H-%M-%S")
image_format = "{base_dir}/{time_now}_frame-{current_frame}-{last_frame}_type_{random_num}-{mode_type}-{base_dir}" \
"-{requestId}_{image_type}.jpg"
image_name = image_format.format(
base_dir='PWL202304141639429276',
time_now=time_now,
current_frame='0',
last_frame='0',
random_num=random_num,
mode_type='offline',
requestId='111111111111111111',
image_type='OR')
result = ossClient.upload_file(image_name, or_image.tobytes())
# print('http status: {0}'.format(result.status))
# # 请求ID。请求ID是本次请求的唯一标识强烈建议在程序日志中添加此参数。
# print('request_id: {0}'.format(result.request_id))
# # ETag是put_object方法返回值特有的属性用于标识一个Object的内容。
# print('ETag: {0}'.format(result.etag))
# # HTTP响应头部。
# print('date: {0}'.format(result.headers['date']))
# print(result.__reduce__())
# 对于图片上传, 上传成功后直接将image_name给拓恒公司就可以了
# 如果测试查看图片是否上传成功
# 可以使用域名拼接
image_url = 'https://image.t-aaron.com/' + image_name
print(image_url)
# 拓恒公司只需要image_name

128
test/aliyun/vod.py Normal file
View File

@ -0,0 +1,128 @@
# -*- coding: UTF-8 -*-
import json
import traceback
from aliyunsdkcore.client import AcsClient
from aliyunsdkvod.request.v20170321 import CreateUploadVideoRequest
from aliyunsdkvod.request.v20170321 import GetPlayInfoRequest
from vodsdk.AliyunVodUtils import *
from vodsdk.AliyunVodUploader import AliyunVodUploader
from vodsdk.UploadVideoRequest import UploadVideoRequest
# # # 填入AccessKey信息
def init_vod_client(accessKeyId, accessKeySecret):
regionId = 'cn-shanghai' # 点播服务接入地域
connectTimeout = 3 # 连接超时,单位为秒
return AcsClient(accessKeyId, accessKeySecret, regionId, auto_retry=True, max_retry_time=3, timeout=connectTimeout)
def create_upload_video(clt):
request = CreateUploadVideoRequest.CreateUploadVideoRequest()
request.set_Title('dddddd')
request.set_FileName('/home/thsw/chenyukun/video/111111.mp4')
request.set_Description('Video Description')
# //CoverURL示例http://192.168.0.0/16/tps/TB1qnJ1PVXXXXXCXXXXXXXXXXXX-700-700.png
# request.set_CoverURL('<your Cover URL>')
# request.set_Tags('tag1,tag2')
# request.set_CateId(0)
# request.set_accept_format('JSON')
response = json.loads(clt.do_action_with_exception(request))
return response
try:
clt = init_vod_client('LTAI5tSJ62TLMUb4SZuf285A', 'MWYynm30filZ7x0HqSHlU3pdLVNeI7')
uploadInfo = create_upload_video(clt)
print(json.dumps(uploadInfo, ensure_ascii=False, indent=4))
except Exception as e:
print(e)
print(traceback.format_exc())
# 刷新音视频凭证
# from aliyunsdkvod.request.v20170321 import RefreshUploadVideoRequest
# def refresh_upload_video(clt, videoId):
# request = RefreshUploadVideoRequest.RefreshUploadVideoRequest()
# request.set_VideoId(videoId)
# request.set_accept_format('JSON')
# return json.loads(clt.do_action_with_exception(request))
#
# try:
# clt = init_vod_client('LTAI5tSJ62TLMUb4SZuf285A', 'MWYynm30filZ7x0HqSHlU3pdLVNeI7')
# uploadInfo = refresh_upload_video(clt, "d6c419c33da245758f71e362b5ee8b56")
# print(json.dumps(uploadInfo, ensure_ascii=False, indent=4))
#
# except Exception as e:
# print(e)
# print(traceback.format_exc())
#
#
# # 获取播放地址
# def init_vod_client(accessKeyId, accessKeySecret):
# regionId = 'cn-shanghai' # 点播服务接入地域
# connectTimeout = 3 # 连接超时,单位为秒
# return AcsClient(accessKeyId, accessKeySecret, regionId, auto_retry=True, max_retry_time=3, timeout=connectTimeout)
# def get_play_info(clt, videoId):
# request = GetPlayInfoRequest.GetPlayInfoRequest()
# request.set_accept_format('JSON')
# request.set_VideoId(videoId)
# request.set_AuthTimeout(3600*5)
# response = json.loads(clt.do_action_with_exception(request))
# return response
#
# try:
# clt = init_vod_client('LTAI5tSJ62TLMUb4SZuf285A', 'MWYynm30filZ7x0HqSHlU3pdLVNeI7')
# playInfo = get_play_info(clt, uploadInfo["VideoId"])
# print(json.dumps(playInfo, ensure_ascii=False, indent=4))
#
# except Exception as e:
# print(e)
# print(traceback.format_exc())
#
# # 获取视频播放凭证
# from aliyunsdkvod.request.v20170321 import GetVideoPlayAuthRequest
# def get_video_playauth(clt, videoId):
# request = GetVideoPlayAuthRequest.GetVideoPlayAuthRequest()
# request.set_accept_format('JSON')
# request.set_VideoId(videoId)
# request.set_AuthInfoTimeout(3000)
# response = json.loads(clt.do_action_with_exception(request))
# return response
#
# try:
# clt = init_vod_client('LTAI5tSJ62TLMUb4SZuf285A', 'MWYynm30filZ7x0HqSHlU3pdLVNeI7')
# playAuth = get_video_playauth(clt, uploadInfo["VideoId"])
# print(json.dumps(playAuth, ensure_ascii=False, indent=4))
#
# except Exception as e:
# print(e)
# print(traceback.format_exc())
# accessKeyId='LTAI5tSJ62TLMUb4SZuf285A'
# accessKeySecret='MWYynm30filZ7x0HqSHlU3pdLVNeI7'
# filePath="/home/thsw/chenyukun/video/111111.mp4"
# # 测试上传本地音视频
# def testUploadLocalVideo(accessKeyId, accessKeySecret, filePath, storageLocation=None):
# try:
# # 可以指定上传脚本部署的ECS区域。如果ECS区域和视频点播存储区域相同则自动使用内网上传上传更快且更省公网流量。
# # ecsRegionId ="cn-shanghai"
# # uploader = AliyunVodUploader(accessKeyId, accessKeySecret, ecsRegionId)
# # 不指定上传脚本部署的ECS区域。
# uploader = AliyunVodUploader(accessKeyId, accessKeySecret)
# uploadVideoRequest = UploadVideoRequest(filePath, 'aiOnLineVideo')
# # 可以设置视频封面如果是本地或网络图片可使用UploadImageRequest上传图片到视频点播获取到ImageURL
# #ImageURL示例https://example.com/sample-****.jpg
# #uploadVideoRequest.setCoverURL('<your Image URL>')
# # 标签
# # uploadVideoRequest.setTags('taa')
# if storageLocation:
# uploadVideoRequest.setStorageLocation(storageLocation)
# videoId = uploader.uploadLocalVideo(uploadVideoRequest)
# print("videoId: %s" % (videoId))
#
# except AliyunVodException as e:
# print(e)
# testUploadLocalVideo(accessKeyId, accessKeySecret, filePath)

164
test/aliyun/vodTest.py Normal file
View File

@ -0,0 +1,164 @@
# -*- coding: utf-8 -*-
# This file is auto-generated, don't edit it. Thanks.
import sys
from typing import List
from alibabacloud_vod20170321.client import Client as vod20170321Client
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_darabonba_env.client import Client as EnvClient
from alibabacloud_vod20170321 import models as vod_20170321_models
from alibabacloud_tea_console.client import Client as ConsoleClient
from alibabacloud_tea_util.client import Client as UtilClient
from vodsdk.AliyunVodUtils import *
from vodsdk.AliyunVodUploader import AliyunVodUploader
from vodsdk.UploadVideoRequest import UploadVideoRequest
class Sample:
def __init__(self):
pass
@staticmethod
def initialization(
region_id: str,
) -> vod20170321Client:
config = open_api_models.Config()
# 您的AccessKey ID
config.access_key_id = EnvClient.get_env('LTAI5tSJ62TLMUb4SZuf285A')
# 您的AccessKey Secret
config.access_key_secret = EnvClient.get_env('MWYynm30filZ7x0HqSHlU3pdLVNeI7')
# 您的可用区ID
config.region_id = region_id
return vod20170321Client(config)
@staticmethod
def get_play_info_sample(
client: vod20170321Client,
video_id: str,
) -> vod_20170321_models.GetPlayInfoResponse:
request = vod_20170321_models.GetPlayInfoRequest()
# 视频ID。
request.video_id = video_id
response = client.get_play_info(request)
return response
@staticmethod
async def get_play_info_sample_async(
client: vod20170321Client,
video_id: str,
) -> vod_20170321_models.GetPlayInfoResponse:
request = vod_20170321_models.GetPlayInfoRequest()
# 视频ID。
request.video_id = video_id
response = await client.get_play_info_async(request)
return response
@staticmethod
def main(
args: List[str],
) -> None:
try:
region_id = args[0]
video_id = args[1]
client = Sample.initialization(region_id)
response_get_play_info = Sample.get_play_info_sample(client, video_id)
ConsoleClient.log(UtilClient.to_jsonstring(UtilClient.to_map(response_get_play_info)))
except Exception as error:
ConsoleClient.log(error.message)
@staticmethod
async def main_async(
args: List[str],
) -> None:
try:
region_id = args[0]
video_id = args[1]
client = Sample.initialization(region_id)
response_get_play_info = await Sample.get_play_info_sample_async(client, video_id)
ConsoleClient.log(UtilClient.to_jsonstring(UtilClient.to_map(response_get_play_info)))
except Exception as error:
ConsoleClient.log(error.message)
accessKeyId='LTAI5tSJ62TLMUb4SZuf285A'
accessKeySecret='MWYynm30filZ7x0HqSHlU3pdLVNeI7'
filePath="/home/thsw/chenyukun/video/111111.mp4"
# 测试上传本地音视频
def testUploadLocalVideo(accessKeyId, accessKeySecret, filePath, storageLocation=None):
try:
# 可以指定上传脚本部署的ECS区域。如果ECS区域和视频点播存储区域相同则自动使用内网上传上传更快且更省公网流量。
# ecsRegionId ="cn-shanghai"
# uploader = AliyunVodUploader(accessKeyId, accessKeySecret, ecsRegionId)
# 不指定上传脚本部署的ECS区域。
uploader = AliyunVodUploader(accessKeyId, accessKeySecret)
uploadVideoRequest = UploadVideoRequest(filePath, 'aiOnLineVideo')
# 可以设置视频封面如果是本地或网络图片可使用UploadImageRequest上传图片到视频点播获取到ImageURL
#ImageURL示例https://example.com/sample-****.jpg
#uploadVideoRequest.setCoverURL('<your Image URL>')
# 标签
# uploadVideoRequest.setTags('taa')
if storageLocation:
uploadVideoRequest.setStorageLocation(storageLocation)
videoId = uploader.uploadLocalVideo(uploadVideoRequest)
print("videoId: %s" % (videoId))
except AliyunVodException as e:
print(e)
# testUploadLocalVideo(accessKeyId, accessKeySecret, filePath)
from alibabacloud_tea_util import models as util_models
import time
def get_video_url(video_id):
config = open_api_models.Config(access_key_id=accessKeyId, access_key_secret=accessKeySecret)
config.endpoint = f'vod.aliyuncs.com'
client = vod20170321Client(config)
get_play_info_request = vod_20170321_models.GetPlayInfoRequest(video_id=video_id)
runtime = util_models.RuntimeOptions()
start = time.time()
while True:
try:
# 复制代码运行请自行打印 API 的返回值
vod_20170321_models.GetPlayInfoResponse = client.get_play_info_with_options(get_play_info_request, runtime)
play_url = vod_20170321_models.GetPlayInfoResponse.body.play_info_list.play_info[0].play_url
return play_url
except Exception as error:
print("bbbbbbbbbbbbbb")
print(error)
time.sleep(5)
end = time.time()
result = int(end - start)
if result > 1200:
print("aaaaaaaa")
raise error
import json
import traceback
from aliyunsdkcore.client import AcsClient
from aliyunsdkvod.request.v20170321 import CreateUploadVideoRequest
from aliyunsdkvod.request.v20170321 import GetPlayInfoRequest
from vodsdk.AliyunVodUtils import *
from vodsdk.AliyunVodUploader import AliyunVodUploader
from vodsdk.UploadVideoRequest import UploadVideoRequest
# 获取播放地址
def init_vod_client(accessKeyId, accessKeySecret):
regionId = 'cn-shanghai' # 点播服务接入地域
connectTimeout = 3 # 连接超时,单位为秒
return AcsClient(accessKeyId, accessKeySecret, regionId, auto_retry=True, max_retry_time=3, timeout=connectTimeout)
def get_play_info(clt, videoId):
request = GetPlayInfoRequest.GetPlayInfoRequest()
request.set_accept_format('JSON')
request.set_VideoId(videoId)
request.set_AuthTimeout(3600*5)
response = json.loads(clt.do_action_with_exception(request))
return response
if __name__ == '__main__':
# testUploadLocalVideo(accessKeyId, accessKeySecret, "/home/thsw/chenyukun/video/百水河7.mp4")
# print(Sample.get_play_info_sample(Sample.initialization('cn-shanghai'), 'dfaf3d140f714d9889562bff10a6f69a'))
# print(get_video_url('3bb41d547bad44a7a9202017b8025838'))
try:
clt = init_vod_client('LTAI5tSJ62TLMUb4SZuf285A', 'MWYynm30filZ7x0HqSHlU3pdLVNeI7')
playInfo = get_play_info(clt, "43e00a1a9d334c30b743d1cd6138207a")
print(playInfo["PlayInfoList"]["PlayInfo"][0]["PlayURL"])
print(json.dumps(playInfo, ensure_ascii=False, indent=4))
except Exception as e:
print("HTTP Status: 403" not in str(e))

130
test/aliyun/voddemo.py Normal file
View File

@ -0,0 +1,130 @@
# -*- coding: utf-8 -*-
import time
import json
from aliyunsdkcore.client import AcsClient
from aliyunsdkvod.request.v20170321 import GetPlayInfoRequest
from vodsdk.AliyunVodUtils import *
from vodsdk.AliyunVodUploader import AliyunVodUploader
from vodsdk.UploadVideoRequest import UploadVideoRequest
'''
视频上传使用vod
1. 阿里云VOD文档地址https://help.aliyun.com/product/29932.html?spm=5176.8413026.J_3895079540.5.1b4a1029mXvncc
2. 阿里云对象存储OSS SDK示例地址https://help.aliyun.com/document_detail/64148.html?spm=a2c4g.64148.0.0.5ae54150jUecEU
4. 安装SDK
python -m pip install aliyun-python-sdk-core -i https://pypi.tuna.tsinghua.edu.cn/simple
python -m pip install aliyun-python-sdk-live -i https://pypi.tuna.tsinghua.edu.cn/simple
python -m pip install aliyun-python-sdk-core-v3 -i https://pypi.tuna.tsinghua.edu.cn/simple
python -m pip install aliyun-python-sdk-vod -i https://pypi.tuna.tsinghua.edu.cn/simple
python -m pip install alibabacloud_vod20170321 -i https://pypi.tuna.tsinghua.edu.cn/simple
python -m pip install oss2 -i https://pypi.tuna.tsinghua.edu.cn/simple
python -m pip install voduploadsdk -i https://pypi.tuna.tsinghua.edu.cn/simple
5. 视频域名地址https://vod.play.t-aaron.com/
'''
class AliyunVodSdk:
def __init__(self):
self.__client = None
self.__access_key = 'LTAI5tMiefafZ6br4zmrQWv9'
self.__access_secret = 'JgzQjSCkwZ7lefZO6egOArw38YH1Tk'
self.__regionId = "cn-shanghai"
self.__cateId = '1000468340'
def init_vod_client(self):
return AcsClient(self.__access_key, self.__access_secret, self.__regionId, auto_retry=True, max_retry_time=3,
timeout=5)
'''
根据videoId获取视频地址
'''
def get_play_info(self, videoId):
logger.info("开始获取视频地址videoId:{}", videoId)
start = time.time()
while True:
try:
clt = self.init_vod_client()
request = GetPlayInfoRequest.GetPlayInfoRequest()
request.set_accept_format('JSON')
request.set_VideoId(videoId)
request.set_AuthTimeout(3600 * 5)
response = json.loads(clt.do_action_with_exception(request))
play_url = response["PlayInfoList"]["PlayInfo"][0]["PlayURL"]
logger.info("获取视频地址成功,视频地址: {}", play_url)
return play_url
except Exception as e:
logger.error("获取视频地址失败5秒后重试, requestId: {}")
time.sleep(5)
current_time = time.time()
if "HTTP Status: 403" not in str(e):
logger.exception("获取视频地址失败: {}", e)
raise e
if "HTTP Status: 403" in str(e) and ("UploadFail" in str(e) or "TranscodeFail" in str(e)):
self.logger.exception("获取视频地址失败: {}", e)
raise e
diff_time = current_time - start
if diff_time > 60 * 60 * 2:
logger.exception("获取视频地址失败超时异常: {},超时时间:{}", e, diff_time)
raise e
def upload_local_video(self, filePath, file_title, storageLocation=None):
logger.info("开始执行vod视频上传, filePath: {}", filePath)
uploader = AliyunVodUploader(self.__access_key, self.__access_secret)
uploadVideoRequest = UploadVideoRequest(filePath, file_title)
uploadVideoRequest.setCateId(self.__cateId)
if storageLocation:
uploadVideoRequest.setStorageLocation(storageLocation)
MAX_RETRIES = 3
retry_count = 0
while True:
try:
result = uploader.uploadLocalVideo(uploadVideoRequest)
logger.info("vod视频上传成功, videoId:{}", result.get("VideoId"))
return result.get("VideoId")
except AliyunVodException as e:
retry_count += 1
time.sleep(3)
logger.error("vod视频上传失败重试次数{}", retry_count)
if retry_count >= MAX_RETRIES:
self.logger.exception("vod视频上传重试失败: {}", e)
raise e
YY_MM_DD_HH_MM_SS = "%Y-%m-%d %H:%M:%S"
YMDHMSF = "%Y%m%d%H%M%S%f"
def generate_timestamp():
"""根据当前时间获取时间戳,返回整数"""
return int(time.time())
def now_date_to_str(fmt=None):
if fmt is None:
fmt = YY_MM_DD_HH_MM_SS
return datetime.datetime.now().strftime(fmt)
if __name__ == "__main__":
# 本地原视频命名
random_time = now_date_to_str(YMDHMSF)
# # 如果是离线视频,将 _on_or_ 替换为 _off_or_
# orFilePath = "%s%s%s%s%s" % ('本地路径', random_time, "_on_or_", 'requestId', ".mp4")
# # 本地AI识别后的视频命名
# # 如果是离线视频,将 _on_ai_ 替换为 _off_ai_
# aiFilePath = "%s%s%s%s%s" % ('本地路径', random_time, "_on_ai_", 'requestId', ".mp4")
# filePath = "%s%s%s%s%s" % ('D:\\shipin\\', random_time, "_on_ai_", '11111111', ".mp4")
filePath = 'D:\\shipin\\777.mp4'
codClinet = AliyunVodSdk()
result = codClinet.upload_local_video(filePath, 'aiOnLineVideo1')
print(result)
url = codClinet.get_play_info(result)
print(url)

124
test/aliyun/vodtest1.py Normal file
View File

@ -0,0 +1,124 @@
# -*- coding: utf-8 -*-
# This file is auto-generated, don't edit it. Thanks.
import sys
from typing import List
from Tea.core import TeaCore
from alibabacloud_vod20170321.client import Client as Vod20170321Client
from alibabacloud_tea_openapi import models as open_api_models
from alibabacloud_darabonba_env.client import Client as EnvClient
from alibabacloud_vod20170321 import models as vod_20170321_models
from alibabacloud_tea_console.client import Client as ConsoleClient
from alibabacloud_tea_util.client import Client as UtilClient
class Sample:
"""
write your Darabonba code here...
"""
def __init__(self):
pass
@staticmethod
def init_vod_client(
access_key_id: str,
access_key_secret: str,
region_id: str,
) -> Vod20170321Client:
"""
使用AK&SK初始化账号Client
"""
config = open_api_models.Config()
config.access_key_id = access_key_id
config.access_key_secret = access_key_secret
config.region_id = region_id
return Vod20170321Client(config)
@staticmethod
def main(
args: List[str],
) -> None:
client = Sample.init_vod_client('LTAI5tSJ62TLMUb4SZuf285A', 'MWYynm30filZ7x0HqSHlU3pdLVNeI7', args[0])
# 1.获取视频上传地址和凭证,并生成视频信息
create_upload_video_request = vod_20170321_models.CreateUploadVideoRequest(
title=args[1],
file_name=args[2]
)
create_upload_video_response = client.create_upload_video(create_upload_video_request)
ConsoleClient.log(UtilClient.to_jsonstring(TeaCore.to_map(create_upload_video_response)))
# 媒体id
upload_video_id = create_upload_video_response.body.video_id
ConsoleClient.log(upload_video_id)
# 如果视频文件过大,上传超时后可以刷新视频凭证,然后继续上传
refresh_upload_video_request = vod_20170321_models.RefreshUploadVideoRequest(
video_id=upload_video_id
)
refresh_upload_video_reponse = client.refresh_upload_video(refresh_upload_video_request)
ConsoleClient.log(UtilClient.to_jsonstring(TeaCore.to_map(refresh_upload_video_reponse)))
# # 2.oss视频文件上传需要用户实现
# # 3.上传过程中,获取媒体上传详情
# get_upload_details_request = vod_20170321_models.GetUploadDetailsRequest(
# media_ids=upload_video_id
# )
# get_upload_details_reponse = client.get_upload_details(get_upload_details_request)
# ConsoleClient.log(UtilClient.to_jsonstring(TeaCore.to_map(get_upload_details_reponse)))
# # 4.媒体上传完成之后,可以获取媒体播放信息进行播放
# # 4.1 通过播放凭证播放
# get_play_info_request = vod_20170321_models.GetPlayInfoRequest(
# video_id=upload_video_id
# )
# get_play_info_reponse = client.get_play_info(get_play_info_request)
# ConsoleClient.log(UtilClient.to_jsonstring(TeaCore.to_map(get_play_info_reponse)))
# # 4.2 通过播放地址播放
# get_video_play_auth_request = vod_20170321_models.GetVideoPlayAuthRequest(
# video_id=upload_video_id
# )
# get_video_play_auth_reponse = client.get_video_play_auth(get_video_play_auth_request)
# ConsoleClient.log(UtilClient.to_jsonstring(TeaCore.to_map(get_video_play_auth_reponse)))
@staticmethod
async def main_async(
args: List[str],
) -> None:
client = Sample.init_vod_client(EnvClient.get_env('ACCESS_KEY_ID'), EnvClient.get_env('ACCESS_KEY_SECRET'), args[0])
# 1.获取视频上传地址和凭证,并生成视频信息
create_upload_video_request = vod_20170321_models.CreateUploadVideoRequest(
title=args[1],
file_name=args[2]
)
create_upload_video_response = await client.create_upload_video_async(create_upload_video_request)
ConsoleClient.log(UtilClient.to_jsonstring(TeaCore.to_map(create_upload_video_response)))
# 媒体id
upload_video_id = create_upload_video_response.body.video_id
ConsoleClient.log(upload_video_id)
# 如果视频文件过大,上传超时后可以刷新视频凭证,然后继续上传
refresh_upload_video_request = vod_20170321_models.RefreshUploadVideoRequest(
video_id=upload_video_id
)
refresh_upload_video_reponse = await client.refresh_upload_video_async(refresh_upload_video_request)
ConsoleClient.log(UtilClient.to_jsonstring(TeaCore.to_map(refresh_upload_video_reponse)))
# 2.oss视频文件上传需要用户实现
# 3.上传过程中,获取媒体上传详情
get_upload_details_request = vod_20170321_models.GetUploadDetailsRequest(
media_ids=upload_video_id
)
get_upload_details_reponse = await client.get_upload_details_async(get_upload_details_request)
ConsoleClient.log(UtilClient.to_jsonstring(TeaCore.to_map(get_upload_details_reponse)))
# 4.媒体上传完成之后,可以获取媒体播放信息进行播放
# 4.1 通过播放凭证播放
get_play_info_request = vod_20170321_models.GetPlayInfoRequest(
video_id=upload_video_id
)
get_play_info_reponse = await client.get_play_info_async(get_play_info_request)
ConsoleClient.log(UtilClient.to_jsonstring(TeaCore.to_map(get_play_info_reponse)))
# 4.2 通过播放地址播放
get_video_play_auth_request = vod_20170321_models.GetVideoPlayAuthRequest(
video_id=upload_video_id
)
get_video_play_auth_reponse = await client.get_video_play_auth_async(get_video_play_auth_request)
ConsoleClient.log(UtilClient.to_jsonstring(TeaCore.to_map(get_video_play_auth_reponse)))
if __name__ == '__main__':
Sample.main(['cn-shanghai', "/home/thsw/chenyukun/video/111111.mp4", "/home/thsw/chenyukun/video/111111.mp4"])

29
test/aliyun/vodtest2.py Normal file
View File

@ -0,0 +1,29 @@
import json
import traceback
from aliyunsdkcore.client import AcsClient
from aliyunsdkvod.request.v20170321 import CreateUploadVideoRequest
from aliyunsdkvod.request.v20170321 import GetPlayInfoRequest
from vodsdk.AliyunVodUtils import *
from vodsdk.AliyunVodUploader import AliyunVodUploader
from vodsdk.UploadVideoRequest import UploadVideoRequest
# 获取播放地址
def init_vod_client(accessKeyId, accessKeySecret):
regionId = 'cn-shanghai' # 点播服务接入地域
connectTimeout = 3 # 连接超时,单位为秒
return AcsClient(accessKeyId, accessKeySecret, regionId, auto_retry=True, max_retry_time=3, timeout=connectTimeout)
def get_play_info(clt, videoId):
request = GetPlayInfoRequest.GetPlayInfoRequest()
request.set_accept_format('JSON')
request.set_VideoId(videoId)
request.set_AuthTimeout(3600*5)
response = json.loads(clt.do_action_with_exception(request))
return response
try:
clt = init_vod_client('LTAI5tSJ62TLMUb4SZuf285A', 'MWYynm30filZ7x0HqSHlU3pdLVNeI7')
playInfo = get_play_info(clt, "f2bd66de44f742a5bb7d603c295dc47f")
print(json.dumps(playInfo, ensure_ascii=False, indent=4))
except Exception as e:
print(str(e))
print("403" in str(e))
# print(traceback.format_exc())

View File

@ -0,0 +1,55 @@
"""
1ChainMap是什么
ChainMap最基本的使用可以用来合并两个或者更多个字典当查询的时候从前往后依次查询
ChainMap将多个字典视为一个解锁Python超能力
ChainMap是由Python标准库提供的一种数据结构允许你将多个字典视为一个换句话说:ChainMap是一个基于多dict的可更新的视图它的行为就像一个普通的dict
ChainMap类用于快速链接多个映射以便将它们视为一个单元它通常比创建新字典和多次调用update()快得多
你以前可能从来没有听说过ChainMap你可能会认为ChainMap的使用情况是非常特定的坦率地说你是对的
我知道的用例包括
通过多个字典搜索
提供链缺省值
经常计算字典子集的性能关键的应用程序
2特性
1找到一个就不找了这个列表是按照第一次搜索到最后一次搜索的顺序组织的搜索查询底层映射直到一个键被找到
2更新原始映射不同的是更新和删除只操作第一个映射
3支持所有常用字典方法
简而言之ChainMap将多个字典视为一个解锁Python超能力
Python标准库中的集合模块包含许多为性能而设计的实用的数据结构著名的包括命名元组或计数器
今天通过实例我们来看看鲜为人知的ChainMap通过浏览具体的示例我希望给你一个提示关于在更高级的Python工作中使用ChainMap将如何从中受益
"""
from collections import ChainMap
baseline = {'music': 'bach', 'art': 'rembrandt'}
adjustments = {'art': 'van gogh', 'opera': 'carmen'}
test = ChainMap(adjustments, baseline)
print(test)
test1 = list(ChainMap(adjustments, baseline))
print(test1)
# 存在重复元素时,也不会去重
dcic1 = {'label1': '11', 'label2': '22'}
dcic2 = {'label2': '22', 'label3': '33'}
dcic3 = {'label4': '44', 'label5': '55'}
last = ChainMap(dcic1, dcic2, dcic3)
print(last)
print(last['label2'])
"""
new_child()方法
用法new_child(m=None)
返回一个新的ChainMap类包含了一个新映射(map)后面跟随当前实例的全部映射map
如果m被指定它就成为不同新的实例就是在所有映射前加上 m如果没有指定就加上一个空字典
这样的话一个 d.new_child() 调用等价于ChainMap({}, *d.maps) 这个方法用于创建子上下文不改变任何父映射的值
"""
aa = last.new_child(m={'key_new': 888})
print(aa)
"""
parents属性
属性返回一个新的ChainMap包含所有的当前实例的映射除了第一个
这样可以在搜索的时候跳过第一个映射使用的场景类似在 nested scopes 嵌套作用域中使用nonlocal关键词
用例也可以类比内建函数super() 一个d.parents 的引用等价于ChainMap(*d.maps[1:])
"""
print(aa.parents)

111
test/collections/Counter.py Normal file
View File

@ -0,0 +1,111 @@
import collections
import re
from collections import Counter
print(collections.__all__)
"""
['deque', 'defaultdict', 'namedtuple', 'UserDict', 'UserList',
'UserString', 'Counter', 'OrderedDict', 'ChainMap']
这个模块实现了特定目标的容器以提供Python标准内建容器dict , list , set , 和tuple 的替代选择
deque: 类似列表(list)的容器实现了在两端快速添加(append)和弹出(pop)
defaultdict: 字典的子类提供了一个工厂函数为字典查询提供一个默认值
namedtuple(): 创建命名元组子类的工厂函数生成可以使用名字来访问元素内容的tuple子类
UserDict: 封装了字典对象简化了字典子类化
UserList: 封装了列表对象简化了列表子类化
UserString: 封装了字符串对象简化了字符串子类化中文版翻译有误
Counter: 字典的子类提供了可哈希对象的计数功能
OrderedDict: 字典的子类保存了他们被添加的顺序有序字典
ChainMap: 类似字典(dict)的容器类将多个映射集合到一个视图里面
"""
text = 'remove an existing key one level down remove an existing key one level down'
# \w 匹配非特殊字符即a-z、A-Z、0-9、_、汉字
words = re.findall(r'\w+', text)
print(Counter(words).most_common(10))
#计算列表中单词的个数
cnt = Counter()
for word in ['red', 'blue', 'red', 'green', 'blue', 'blue']:
cnt[word] += 1
print(cnt)
# #上述这样计算有点嘛,下面的方法更简单,直接计算就行
L = ['red', 'blue', 'red', 'green', 'blue', 'blue']
print(Counter(L))
# 元素从一个iterable 被计数或从其他的mapping (or counter)初始化:
# 字符串计数
print(Counter('gallahad'))
# 字典计数
print(Counter({'red': 4, 'blue': 2}))
# 是个啥玩意计数
print(Counter(cats=4, dogs=8))
"""
1elements()
描述返回一个迭代器其中每个元素将重复出现计数值所指定次 元素会按首次出现的顺序返回 如果一个元素的计数值小于1elements() 将会忽略它
语法elements( )
参数
"""
c = Counter(a=4, b=2, c=0, d=-2)
print(c)
print(list(c.elements()))
print(sorted(c.elements()))
c = Counter(a=4, b=2, c=0, d=5)
print(list(c.elements()))
"""
2most_common()
返回一个列表其中包含n个最常见的元素及出现次数按常见程度由高到低排序
如果n被省略或为Nonemost_common() 将返回计数器中的所有元素
计数值相等的元素按首次出现的顺序排序经常用来计算top词频的词语
"""
print(Counter('abracadabra').most_common(3))
print(Counter('abracadabra').most_common(5))
"""
3subtract()
从迭代对象或映射对象减去元素像dict.update() 但是是减去而不是替换输入和输出都可以是0或者负数
"""
c = Counter(a=4, b=2, c=0, d=-2)
d = Counter(a=1, b=2, c=3, d=4)
c.subtract(d)
print(c)
#减去一个abcd
str0 = Counter('aabbccdde')
str0.subtract('abcd')
print(str0)
"""
4字典方法
通常字典方法都可用于Counter对象除了有两个方法工作方式与字典并不相同
fromkeys(iterable)
这个类方法没有在Counter中实现
update([iterable-or-mapping])
从迭代对象计数元素或者从另一个映射对象 (或计数器) 添加 dict.update() 但是是加上而不是替换
另外迭代对象应该是序列元素而不是一个 (key, value)
"""
c = Counter(a=4, b=2, c=0, d=-2)
print(sum(c.values()))
print(list(c))
print(set(c))
print(dict(c))
print(c.items())
print(+c) # 删除零计数和负计数
c.clear()
print(c)
"""
5数学操作
这个功能非常强大提供了几个数学操作可以结合 Counter 对象以生产 multisets (计数器中大于0的元素
加和减结合计数器通过加上或者减去元素的相应计数交集和并集返回相应计数的最小或最大值
每种操作都可以接受带符号的计数但是输出会忽略掉结果为零或者小于零的计数
"""
c = Counter(a=3, b=1)
d = Counter(a=1, b=2)
print(c+d)
print(c - d)
print(c & d)
print(c | d)

View File

@ -0,0 +1,35 @@
from collections import OrderedDict
"""
1popitem
语法popitem(last=True)
功能有序字典的 popitem() 方法移除并返回一个 (key, value) 键值对
如果 last 值为真则按 LIFO 后进先出的顺序返回键值对否则就按 FIFO 先进先出的顺序返回键值对
"""
d = OrderedDict.fromkeys('abcde')
print(d)
print(d.popitem())
# #last=False时弹出第一个
print(d.popitem(last=False))
print(d.popitem(last=True))
"""
2move_to_end
"""
d = OrderedDict.fromkeys('abcde')
d.move_to_end('b')
print(d)
d.move_to_end('b', last=False)
print(d)
"""
3reversed()
相对于通常的映射方法有序字典还另外提供了逆序迭代的支持通过reversed()
"""
d = OrderedDict.fromkeys('acbde')
print(d)
print(list(reversed(d)))
c = OrderedDict({'a': 1, 'c': 2, 'b': 3})
print(c)

View File

@ -0,0 +1,30 @@
# import collections
#
# print(collections.__all__)
# print(dir(collections))
#
# d = {}
# d.setdefault(2, []).append(23)
# d.setdefault(2, []).append(11)
# print(d)
# d.setdefault(2, []).append(23)
#
# # 定义一个curry风格函数
# x = lambda y: [
# print(y),
# print("..."),
# x
# ][-1]
# print(x(1)(2))
#
# import heapq
# print(heapq.nlargest(1, [
# {'S': 5, 'H': 3},
# {'S': 7, 'H': 1},
# {'S': 0, 'H': 2}
# ], key=lambda x: x['S']))
#
# s = [1, [2, [3, [4, [5, 6], 7], 8], (9, 0)]]
# f = lambda x: [y for _x in x for y in f(_x)] if isinstance(x, (list, tuple)) else [x]
#
# print(f(s)) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]

View File

@ -0,0 +1,66 @@
"""
默认字典-defaultdict
在Python字典中收集数据通常是很有用的
在字典中获取一个 key 有两种方法, 第一种 get , 第二种 通过 [] 获取.
使用dict时如果引用的Key不存在就会抛出KeyError如果希望key不存在时返回一个默认值就可以用defaultdict
当我使用普通的字典时用法一般是dict={},添加元素的只需要dict[element] =value即调用的时候也是如此
dict[element] = xxx,但前提是element字典里如果不在字典里就会报错
这时defaultdict就能排上用场了defaultdict的作用是在于当字典里的key不存在但被查找时
返回的不是keyError而是一个默认值这个默认值是什么呢下面会说
1基础介绍
defaultdict([default_factory[, ...]])
返回一个新的类似字典的对象 defaultdict是内置dict类的子类它重载了一个方法并添加了一个可写的实例变量
其余的功能与dict类相同此处不再重复说明
本对象包含一个名为default_factory的属性构造时第一个参数用于为该属性提供初始值默认为 None
所有其他参数包括关键字参数都相当于传递给 dict 的构造函数
defaultdict 对象除了支持标准 dict 的操作还支持以下方法作为扩展
__missing__(key)
如果 default_factory 属性为 None则调用本方法会抛出 KeyError 异常附带参数 key
如果 default_factory 不为 None则它会被不带参数地调用来为 key 提供一个默认值
这个值和 key 作为一对键值对被插入到字典中并作为本方法的返回值返回
如果调用 default_factory 时抛出了异常这个异常会原封不动地向外层传递
在无法找到所需键值时本方法会被 dict 中的 __getitem__() 方法调用
无论本方法返回了值还是抛出了异常都会被 __getitem__() 传递
注意__missing__() 不会 __getitem__() 以外的其他方法调用
意味着 get() 会像正常的 dict 那样返回 None而不是使用 default_factory
"""
from collections import defaultdict
"""
2示例介绍
使用 list 作为 default_factory很轻松地将-值对组成的序列转换为-列表组成的字典
"""
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
d = defaultdict(list)
for k, v in s:
d[k].append(v)
print(sorted(d.items()))
"""
当每个键第一次遇见时它还没有在字典里面所以自动创建该条目即调用default_factory方法
返回一个空的 list list.append() 操作添加值到这个新的列表里当再次存取该键时就正常操作list.append()
添加另一个值到列表中这个计数比它的等价方法dict.setdefault()要快速和简单
"""
s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
d = {}
for k, v in s:
d.setdefault(k, []).append(v)
print(sorted(d.items()))
# 设置 default_factory为int使defaultdict用于计数类似其他语言中的 bag或multiset
s = 'mississippi'
d = defaultdict(int)
for k in s:
d[k] += 1
print(sorted(d.items()))
# 设置 default_factory 为 set 使 defaultdict 用于构建 set 集合:
s = [('red', 1), ('blue', 2), ('red', 3), ('blue', 4), ('red', 1), ('blue', 4)]
d = defaultdict(set)
for k, v in s:
d[k].add(v)
print(sorted(d.items()))
print(d['aaa'])

148
test/collections/deque.py Normal file
View File

@ -0,0 +1,148 @@
"""
deque
双端队列可以快速的从另外一侧追加和推出对象,deque是一个双向链表
针对list连续的数据结构插入和删除进行优化它提供了两端都可以操作的序列
这表示在序列的前后你都可以执行添加或删除操作双向队列(deque)对象支持以下方法
"""
from collections import deque
"""
1append()
添加 x 到右端
"""
d = deque('ghi')
d.append('j')
print(d)
"""
2appendleft()
添加 x 到左端
"""
d.appendleft('f')
print(d)
"""
3clear()
移除所有元素使其长度为0.
"""
d = deque('ghi')
d.clear()
print(d)
"""
4copy()
创建一份浅拷贝
"""
d = deque('xiaoweuge')
y = d.copy()
print(y)
"""
5count()
计算 deque 中元素等于 x 的个数
"""
d = deque('xiaoweuge-shuai')
print(d.count('a'))
"""
6extend()
扩展deque的右侧通过添加iterable参数中的元素
"""
a = deque('abc')
b = deque('cd')
a.extend(b)
print(a)
#与append 的区别
a = deque('abc')
b = deque('cd')
a.append(b)
print(a)
"""
7extendleft()
扩展deque的左侧通过添加iterable参数中的元素注意左添加时在结果中iterable参数中的顺序将被反过来添加
"""
a = deque('abc')
b = deque('cd')
a.extendleft(b)
print(a)
"""
8index()
返回 x deque 中的位置在索引 start 之后索引 stop 之前 返回第一个匹配项如果未找到则引发 ValueError
"""
d = deque('xiaoweuge')
print(d.index('w'))
"""
9insert()
在位置 i 插入 x
如果插入会导致一个限长 deque 超出长度 maxlen 的话就引发一个 IndexError
"""
a = deque('abc')
a.insert(1, 'X')
print(a)
"""
10pop()
移去并且返回一个元素deque 最右侧的那一个 如果没有元素的话就引发一个 IndexError
"""
d = deque('abc')
print(d.pop())
"""
11popleft()
移去并且返回一个元素deque 最左侧的那一个 如果没有元素的话就引发 IndexError
"""
d = deque('abc')
print(d.popleft())
"""
12remove(value)
移除找到的第一个 value 如果没有的话就引发 ValueError
"""
a = deque('abca')
a.remove('a')
print(a)
"""
13reverse()
将deque逆序排列返回 None
"""
#逆序排列
d = deque('ghi') # 创建一个deque
print(list(reversed(d)))
"""
14rotate(n=1)
向右循环移动 n 如果 n 是负数就向左循环
如果deque不是空的向右循环移动一步就等价于 d.appendleft(d.pop()) 向左循环一步就等价于 d.append(d.popleft())
"""
# 向右边挤一挤
d = deque('ghijkl')
d.rotate(1)
print(d)
# 向左边挤一挤
d.rotate(-1)
print(d)
#看一个更明显的
x = deque('12345')
x.rotate()
print(x)
d = deque(['12',' av', 'cd'])
d.rotate(1)
print(d)
"""
15maxlen
Deque的最大尺寸如果没有限定的话就是 None
"""
d=deque(maxlen=10)
for i in range(20):
d.append(i)
print(d)

View File

@ -0,0 +1,83 @@
from collections import namedtuple
"""
可命名元组-namedtuple
生成可以使用名字来访问元素内容的tuple子类命名元组赋予每个位置一个含义提供可读性和自文档性
它们可以用于任何普通元组并添加了通过名字获取值的能力通过索引值也是可以的
1参数介绍
namedtuple(typename,field_names,*,verbose=False, rename=False, module=None)
1typename该参数指定所创建的tuple子类的类名相当于用户定义了一个新类
2field_names该参数是一个字符串序列 ['x''y']此外field_names 也可直接使用单个字符串代表所有字段名多个字段名用空格逗号隔开 'x y' 'x,y'任何有效的 Python 标识符都可作为字段名不能以下画线开头有效的标识符可由字母数字下画线组成但不能以数字下面线开头也不能是关键字 returnglobalpassraise
3rename如果将该参数设为 True那么无效的字段名将会被自动替换为位置名例如指定 ['abc','def','ghi','abc']它将会被替换为 ['abc', '_1','ghi','_3']这是因为 def 字段名是关键字 abc 字段名重复了
4verbose如果该参数被设为 True那么当该子类被创建后该类定义就被立即打印出来
5module如果设置了该参数那么该类将位于该模块下因此该自定义类的 __module__ 属性将被设为该参数值
"""
# 定义命名元组类Point
Point = namedtuple('Point', ['x', 'y'])
# 初始化Point对象即可用位置参数也可用命名参数
p = Point(11, y=22)
# 像普通元组一样用根据索引访问元素
print(p[0] + p[1])
#执行元组解包,按元素的位置解包
a, b = p
print(a, b)
#根据字段名访问各元素
print(p.x + p.y)
print(p)
"""
备注: 在Python中带有前导下划线的方法通常被认为是私有的
但是namedtuple提供的其他方法(._asdict()._make()._replace())是公开的
除了继承元组的方法命名元组还支持三个额外的方法和两个属性为了防止字段名冲突方法和属性以下划线开始
"""
"""
_make(iterable)
类方法从存在的序列或迭代实例创建一个新实例
"""
t = [14, 55]
print(Point._make(t))
"""
_asdict()
返回一个新的dict 它将字段名称映射到它们对应的值
"""
p = Point(x=11, y=22)
print(p._asdict())
"""
_replace(**kwargs)
返回一个新的命名元组实例并将指定域替换为新的值
"""
p = Point(x=11, y=22)
p._replace(x=33)
print(p._replace(x=33))
"""
两个属性
_fields
字符串元组列出了字段名用于提醒和从现有元组创建一个新的命名元组类型
"""
print(p._fields)
Color = namedtuple('Color', 'red green blue')
Pixel = namedtuple('Pixel', Point._fields + Color._fields)
print(Pixel._fields)
"""
_field_defaults
字典将字段名称映射到默认值
"""
Account = namedtuple('Account', ['type', 'balance'], defaults=[0])
print(Account._field_defaults)
print(Account('premium'))
"""
getattr()
要获取这个名字域的值使用 getattr() 函数 :
"""
print(getattr(p, 'x'))

0
test/color/__init__.py Normal file
View File

73
test/color/color_test.py Normal file
View File

@ -0,0 +1,73 @@
import cv2
import numpy as np
from PIL import Image, ImageDraw, ImageFont
rainbows = [
[0, 0, 255],
[255, 0, 0],
[211, 0, 148],
[0, 127, 0],
[0, 69, 255],
[0, 255, 0],
[255, 0, 255],
[0, 0, 127],
[127, 0, 255],
[255, 129, 0],
[139, 139, 0],
[255, 255, 0],
[127, 255, 0],
[0, 127, 255],
[0, 255, 127],
[255, 127, 255],
[8, 101, 139],
[171, 130, 255],
[139, 112, 74],
[205, 205, 180]]
# rainbows = [[0, 0, 255],
# [211, 0, 148],
# [0, 69, 255],
# [133, 21, 199],
# [0, 100, 0],
# [34, 139, 34],
# [8, 101, 139],
# [11, 134, 184],
# [92, 92, 205],
# [147, 20, 255],
# [255, 0, 255],
# [96, 48, 176],
# [205, 205, 105],
# [139, 139, 102],
# [255, 245, 0],
# [170, 205, 102],
# [155, 205, 155],
# [0, 205, 0],
# [79, 79, 47],
# [105, 105, 105],
# [112, 25, 25],
# [205, 0, 0],
# ]
def get_label_array(color=None, label=None, font=None, fontSize=40):
x, y, width, height = font.getbbox(label)
text_image = np.zeros((height, width, 3), dtype=np.uint8)
text_image = Image.fromarray(text_image)
draw = ImageDraw.Draw(text_image)
draw.rectangle((0, 0, width, height), fill=tuple(color))
draw.text((0, -3), label, fill=(255, 255, 255), font=font)
im_array = np.asarray(text_image)
scale = fontSize / height
im_array = cv2.resize(im_array, (0, 0), fx=scale, fy=scale)
return im_array
if __name__ == '__main__':
font = ImageFont.truetype('platech.ttf', 40, encoding='utf-8')
im_arrays = []
for color in rainbows:
im_array = get_label_array(color=color, label="植被", font=font, fontSize=40)
im_arrays.append(im_array)
frame_merge = np.hstack(tuple(im_arrays))
cv2.imshow('frame1', frame_merge)
cv2.waitKey(10000000)

BIN
test/color/platech.ttf Normal file

Binary file not shown.

0
test/cpu/__init__.py Normal file
View File

63
test/cpu/test.py Normal file
View File

@ -0,0 +1,63 @@
import platform
import subprocess
import fileinput
def get_mac_cpu_speed():
commond = 'system_profiler SPHardwareDataType | grep "Processor Speed" | cut -d ":" -f2'
proc = subprocess.Popen([commond], shell=True, stdout=subprocess.PIPE)
output = proc.communicate()[0]
output = output.decode() # bytes 转str
speed = output.lstrip().rstrip('\n')
return speed
def get_linux_cpu_speed():
for line in fileinput.input('/proc/cpuinfo'):
if 'MHz' in line:
value = line.split(':')[1].strip()
value = float(value)
speed = round(value / 1024, 1)
return "{speed} GHz".format(speed=speed)
def get_windows_cpu_speed():
import winreg
key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"HARDWARE\DESCRIPTION\System\CentralProcessor\0")
speed, type = winreg.QueryValueEx(key, "~MHz")
speed = round(float(speed)/1024, 1)
return "{speed} GHz".format(speed=speed)
def get_cpu_speed():
osname = platform.system() # 获取操作系统的名称
speed = ''
if osname == "Darwin":
speed = get_mac_cpu_speed()
if osname == "Linux":
speed = get_linux_cpu_speed()
if osname in ["Windows", "Win32"]:
speed = get_windows_cpu_speed()
return speed
# print(get_cpu_speed())
import psutil
# CPU逻辑数量
# print(psutil.cpu_count())
# CPU物理核心
# print(psutil.cpu_count(logical=False))
# print(psutil.cpu_percent(interval=1, percpu=True))
#
# print(psutil.virtual_memory())
# print(psutil.virtual_memory().percent)#获取内存使用率
# print(psutil.swap_memory())
# print(psutil.disk_partitions()) # 磁盘分区信息
# print(psutil.disk_usage('/')) # 磁盘使用情况
# print(psutil.disk_io_counters()) # 磁盘IO
print(len(psutil.pids()))

0
test/cuda/__init__.py Normal file
View File

88
test/cuda/test.py Normal file
View File

@ -0,0 +1,88 @@
import time
from pathlib import Path
import GPUtil
import cv2
import numpy as np
import torch
from PIL import ImageFont, Image, ImageDraw
# print(Path(__file__)) # 表示当前脚本文件的路径
# print(Path(__file__).parent) # 表示当前路径的父级目录
# import time
# from contextlib import contextmanager
#
# @contextmanager
# def timer():
# start_time = time.time()
# yield
# end_time = time.time()
# print('Time elapsed:', end_time - start_time)
# # 使用上下文管理器
# with timer():
# time.sleep(1)
# print(torch.cuda.is_available())
# print(GPUtil.getGPUs()[0].name)
# def get_first_gpu_name():
# gps = GPUtil.getGPUs()
# if gps is None or len(gps) == 0:
# raise Exception("未获取到gpu资源, 先检测服务器是否已经配置GPU资源")
# return gps[0].name
# gpu_name = get_first_gpu_name()
# aa = [g for g in ['3090', '2080', '4090', 'A10'] if g in gpu_name]
# print(aa)
#
# import tensorrt as trt
# # 定义反序列化引擎文件的函数
# def deserialize_engine_from_file(engine_file_path):
# runtime = trt.Runtime(trt.Logger())
# engine = None
# with open(engine_file_path, "rb") as f:
# while True:
# data = f.read(1024 * 1024)
# if not data:
# break
# tmp_engine = runtime.deserialize_cuda_engine(data)
# if engine is None:
# engine = tmp_engine
# else:
# for i in range(tmp_engine.num_bindings):
# engine.set_binding_shape(i, tmp_engine.get_binding_shape(i))
# return engine
# engine_file_path = "/path/to/engine_file.engine"
# s = time.time()
# engine = deserialize_engine_from_file(engine_file_path)
# print("1 加载trt文件时间", time.time() - s)
# s1 = time.time()
# with open(engine_file_path, "rb") as f1, trt.Runtime(trt.Logger(trt.Logger.ERROR)) as runtime:
# model = runtime.deserialize_cuda_engine(f1.read())
# print("2 加载trt文件时间", time.time() - s1)
def get_label_array(color=None, label=None, outfontsize=None, fontpath="conf/platech.ttf"):
# Plots one bounding box on image 'im' using PIL
fontsize = outfontsize
font = ImageFont.truetype(fontpath, fontsize, encoding='utf-8')
x,y,txt_width, txt_height = font.getbbox(label)
print(x,y,txt_width, txt_height)
im = np.zeros((txt_height, txt_width, 3), dtype=np.uint8)
im = Image.fromarray(im)
draw = ImageDraw.Draw(im)
draw.rectangle([0, 0, txt_width, txt_height], fill=tuple(color))
draw.text((0, -3), label, fill=(255, 255, 255), font=font)
im_array = np.asarray(im)
# if outfontsize:
# scaley = outfontsize / txt_height
# im_array = cv2.resize(im_array, (0, 0), fx=scaley, fy=scaley)
return im_array
aaa = time.time()
im_array = get_label_array(color=(0, 255, 0), label="排口", outfontsize=40, fontpath="platech.ttf")
print(time.time() - aaa)
cv2.imshow("frame", im_array)
cv2.waitKey(0)

27
test/cuda/test1.py Normal file
View File

@ -0,0 +1,27 @@
from sklearn import linear_model
# x = [[20, 3],
# [23, 7],
# [31, 10],
# [42, 13],
# [50, 7],
# [60, 5]]
# y = [0, 1, 1, 1, 0, 0]
# lr = linear_model.LogisticRegression()
# lr.fit(x, y)
# testX = [[28, 8]]
# label = lr.predict(testX)
# print("predicted label = ", label)
#
# prob = lr.predict_proba(testX)
# print("probability = ", prob)
import tensorflow as tf
tf.compat.v1.disable_eager_execution()
hello = tf.constant("hello, world!")
sess = tf.compat.v1.Session()
result = sess.run(hello)
sess.close()
print(result)

0
test/demo/__init__.py Normal file
View File

221
test/demo/demo1.py Normal file
View File

@ -0,0 +1,221 @@
import copy
import json
import os
import time
from concurrent.futures import ThreadPoolExecutor
from multiprocessing import Queue, Process
from loguru import logger
import subprocess as sp
import cv2
import numpy as np
from aip import AipImageClassify
from enums.BaiduSdkEnum import BAIDUERRORDATA, VehicleEnumVALUE
from enums.ExceptionEnum import ExceptionType
from enums.ModelTypeEnum import ModelType
from exception.CustomerException import ServiceException
def get_recording_video_info(url):
try:
video_info = 'ffprobe -show_format -show_streams -of json %s' % url
p = sp.Popen(video_info, stdout=sp.PIPE, stderr=sp.PIPE, shell=True)
out, err = p.communicate(timeout=17)
if p.returncode != 0:
raise Exception("未获取视频信息!!!!!")
probe = json.loads(out.decode('utf-8'))
if probe is None or probe.get("streams") is None:
raise Exception("未获取视频信息!!!!!:")
video_stream = next((stream for stream in probe['streams'] if stream.get('codec_type') == 'video'), None)
if video_stream is None:
raise Exception("未获取视频信息!!!!!")
width = video_stream.get('width')
height = video_stream.get('height')
nb_frames = video_stream.get('nb_frames')
fps = video_stream.get('r_frame_rate')
up, down = str(fps).split('/')
fps = int(eval(up) / eval(down))
return (width, height, nb_frames, fps)
except Exception as e:
raise e
client = AipImageClassify(str(31096670), 'Dam3O4tgPRN3qh4OYE82dbg7', '1PGZ9LAXRR5zcT5MN9rHcW8kLBIS5DAa')
def vehicleDetect(client, iamge, options={}):
reply_num = 0
reply_value = None
while True:
try:
options["show"] = "true"
res_image = client.vehicleDetect(iamge,options)
error_code = res_image.get("error_code")
if error_code:
enum = BAIDUERRORDATA.get(error_code)
# 如果异常编码未知, 返回空值
if enum is None:
logger.error("百度云车辆检测异常error_code:{}", error_code)
return None
# 重试指定次数后,还是异常,输出统一内部异常
if enum.value[3] == 0:
if reply_value is None:
reply_value = 10
logger.error("百度云车辆检测异常error_code:{}, error_msg:{}, reply_num:{}", enum.value[0], enum.value[2], reply_num)
raise Exception()
# 重试指定次数后,还是异常,输出对应的异常
if enum.value[3] == 1:
if reply_value is None:
reply_value = 10
raise ServiceException(str(enum.value[0]), enum.value[2])
# 重试指定次数后,还是异常,输出空
if enum.value[3] == 2:
if reply_value is None:
reply_value = 10
if reply_num >= reply_value:
return None
return res_image
except ServiceException as s:
time.sleep(0.2)
reply_num += 1
if reply_num > reply_value:
logger.exception("车辆检测识别失败: {}", s.msg)
raise ServiceException(e.code, e.msg)
except Exception as e:
logger.exception("车辆检测失败: {}, 当前重试次数:{}", e, reply_num)
time.sleep(0.2)
reply_num += 1
if reply_num > reply_value:
logger.exception("车辆检测识别失败: {}", e)
raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
ExceptionType.SERVICE_INNER_EXCEPTION.value[1])
def mark(content, info, img, color):
score = info.get("probability")
if score is None:
score = info.get("location").get("score")
text = "%s: %.2f]" % (content, score)
text_xy = (info.get("location").get("left"), info.get("location").get("top") - 25)
img_lu = (info.get("location").get("left"), info.get("location").get("top"))
img_rd = (info.get("location").get("left") + info.get("location").get("width"),
info.get("location").get("top") + info.get("location").get("height"))
cv2.putText(img, text, text_xy, cv2.FONT_HERSHEY_SIMPLEX, 1.0, color, 2, cv2.LINE_AA)
count = 1
if img.shape[1] > 1600:
count = 2
cv2.rectangle(img, img_lu, img_rd, color, count)
return img
def pull_stream(url, queue, nb_frames):
command = ['ffmpeg -re -y -i ' + url +' -f rawvideo -pix_fmt bgr24 -an -']
pull_p = sp.Popen(command, stdout=sp.PIPE, shell=True)
aa = 0
try:
while True:
if queue.qsize() == 200:
time.sleep(1)
continue
in_bytes = pull_p.stdout.read(width*height*3)
if in_bytes is not None and len(in_bytes) > 0:
img = np.frombuffer(in_bytes, np.uint8).reshape([height, width, 3])
queue.put({"status": "1", "img": img})
aa+=1
else:
if aa -10 > nb_frames:
queue.put({"status": "2"})
pull_p.terminate()
pull_p.wait()
break;
except Exception as e:
logger.exception("拉流异常: {}", e)
finally:
pull_p.terminate()
pull_p.wait()
def getQueue(queue):
eBody = None
try:
eBody = queue.get(block=False)
return eBody
except Exception as e:
pass
return eBody
def buildFrame(queue, senlin_mod, client, width, height, nb_frames, fps):
frames = []
status = None
for i in range(queue.qsize()):
frame_result = getQueue(queue)
if frame_result is None:
time.sleep(0.01)
continue
if frame_result.get("status") == '1':
frames.append((frame_result.get("img"), senlin_mod, client, width, height, nb_frames, fps))
else:
status = frame_result.get("status")
return frames, status
def process(frame):
try:
p_result, timeOut = frame[1].process(copy.deepcopy(frame[0]), frame[3])
or_result, or_image = cv2.imencode(".jpg", frame[0])
result = vehicleDetect(frame[2], or_image)
if result is not None:
vehicleInfo = result.get("vehicle_info")
if vehicleInfo is not None and len(vehicleInfo) > 0:
for i, info in enumerate(vehicleInfo):
value = VehicleEnumVALUE.get(info.get("type"))
if value is None:
logger.error("车辆识别出现未支持的目标类型type:{}", info.get("type"))
raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
ExceptionType.SERVICE_INNER_EXCEPTION.value[1])
p_result[1] = mark(value.value[1], info, p_result[1], (255, 0, 255))
frame_merge = np.hstack((frame[0], p_result[1]))
return frame_merge
except Exception as e:
logger.exception("模型分析异常: {}", e)
return None
queue = Queue(200)
url ='/home/th/tuo_heng/dev/11.mp4'
width, height, nb_frames, fps = get_recording_video_info(url)
my_process = Process(target = pull_stream, args=(url, queue, nb_frames))
#启动子进程
my_process.start()
current_path = os.path.abspath(os.path.dirname(__file__))
import GPUtil
senlin_mod = Model(str(GPUtil.getAvailable()[0]), [2,3,4], logger, "11111", ModelType.FOREST_FARM_MODEL)
or_video_file = cv2.VideoWriter("aaa.mp4", cv2.VideoWriter_fourcc(*'mp4v'), fps,
(int(width) * 2, int(height)))
with ThreadPoolExecutor(max_workers=3) as t:
task_frame = None
while True:
frames = []
status = None
if task_frame is not None:
frames, status = task_frame.result()
task_frame = t.submit(buildFrame, queue, senlin_mod, client, width, height, nb_frames, fps)
if len(frames) == 0 and status is None:
time.sleep(0.02)
continue
if frames is not None and len(frames) > 0:
for result in t.map(process, frames):
if result is not None:
or_video_file.write(result)
if status is None:
continue
if status.get("status") == "2":
t.shutdown(wait=False)
or_video_file.release()
t.shutdown(wait=False)
or_video_file.release()

189
test/demo/demo2.py Normal file
View File

@ -0,0 +1,189 @@
import asyncio
import copy
import json
import os
import time
from concurrent.futures import ThreadPoolExecutor
from multiprocessing import Queue, Process
from loguru import logger
import subprocess as sp
import cv2
import numpy as np
from aip import AipImageClassify
import sys
from enums.BaiduSdkEnum import BAIDUERRORDATA, VehicleEnumVALUE
from enums.ExceptionEnum import ExceptionType
from enums.ModelTypeEnum import ModelType
from exception.CustomerException import ServiceException
from util.ModelUtils import Model
def get_recording_video_info(url):
try:
video_info = 'ffprobe -show_format -show_streams -of json %s' % url
p = sp.Popen(video_info, stdout=sp.PIPE, stderr=sp.PIPE, shell=True)
out, err = p.communicate(timeout=17)
if p.returncode != 0:
raise Exception("未获取视频信息!!!!!")
probe = json.loads(out.decode('utf-8'))
if probe is None or probe.get("streams") is None:
raise Exception("未获取视频信息!!!!!:")
video_stream = next((stream for stream in probe['streams'] if stream.get('codec_type') == 'video'), None)
if video_stream is None:
raise Exception("未获取视频信息!!!!!")
width = video_stream.get('width')
height = video_stream.get('height')
nb_frames = video_stream.get('nb_frames')
fps = video_stream.get('r_frame_rate')
up, down = str(fps).split('/')
fps = int(eval(up) / eval(down))
return (width, height, nb_frames, fps)
except Exception as e:
raise e
client = AipImageClassify(str(31096670), 'Dam3O4tgPRN3qh4OYE82dbg7', '1PGZ9LAXRR5zcT5MN9rHcW8kLBIS5DAa')
def vehicleDetect(client, iamge, options={}):
reply_num = 0
reply_value = None
while True:
try:
options["show"] = "true"
res_image = client.vehicleDetect(iamge,options)
error_code = res_image.get("error_code")
if error_code:
enum = BAIDUERRORDATA.get(error_code)
# 如果异常编码未知, 返回空值
if enum is None:
logger.error("百度云车辆检测异常error_code:{}", error_code)
return None
# 重试指定次数后,还是异常,输出统一内部异常
if enum.value[3] == 0:
if reply_value is None:
reply_value = 10
logger.error("百度云车辆检测异常error_code:{}, error_msg:{}, reply_num:{}", enum.value[0], enum.value[2], reply_num)
raise Exception()
# 重试指定次数后,还是异常,输出对应的异常
if enum.value[3] == 1:
if reply_value is None:
reply_value = 10
raise ServiceException(str(enum.value[0]), enum.value[2])
# 重试指定次数后,还是异常,输出空
if enum.value[3] == 2:
if reply_value is None:
reply_value = 10
if reply_num >= reply_value:
return None
return res_image
except ServiceException as s:
time.sleep(0.2)
reply_num += 1
if reply_num > reply_value:
logger.exception("车辆检测识别失败: {}", s.msg)
raise ServiceException(e.code, e.msg)
except Exception as e:
logger.exception("车辆检测失败: {}, 当前重试次数:{}", e, reply_num)
time.sleep(0.2)
reply_num += 1
if reply_num > reply_value:
logger.exception("车辆检测识别失败: {}", e)
raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
ExceptionType.SERVICE_INNER_EXCEPTION.value[1])
def mark(content, info, img, color):
score = info.get("probability")
if score is None:
score = info.get("location").get("score")
text = "%s: %.2f" % (content, score)
text_xy = (info.get("location").get("left"), info.get("location").get("top") - 25)
img_lu = (info.get("location").get("left"), info.get("location").get("top"))
img_rd = (info.get("location").get("left") + info.get("location").get("width"),
info.get("location").get("top") + info.get("location").get("height"))
cv2.putText(img, text, text_xy, cv2.FONT_HERSHEY_SIMPLEX, 1.0, color, 2, cv2.LINE_AA)
count = 1
if img.shape[1] > 1600:
count = 2
cv2.rectangle(img, img_lu, img_rd, color, count)
return img
async def mode_handler(img, width):
return senlin_mod.process(copy.deepcopy(img), width)
async def modprocess(img, width):
p_result, timeOut = await mode_handler(img, width)
return p_result, timeOut
async def car_handler(img, width):
return car_mod.process(copy.deepcopy(img), width)
async def carprocess(img, width):
p_result, timeOut = await car_handler(img, width)
return p_result, timeOut
async def baidu_handler(img, client):
or_result, or_image = cv2.imencode(".jpg", img)
return vehicleDetect(client, or_image)
async def baiduprocess(img, client):
result = await baidu_handler(img, client)
return result
url ='/home/th/tuo_heng/dev/11.mp4'
width, height, nb_frames, fps = get_recording_video_info(url)
current_path = os.path.abspath(os.path.dirname(__file__))
import GPUtil
senlin_mod = Model(str(GPUtil.getAvailable()[0]), [2,3,4], logger, "11112", ModelType.FOREST_FARM_MODEL)
car_mod = Model(str(GPUtil.getAvailable()[0]), [0], logger, "11112", ModelType.VEHICLE_MODEL)
or_video_file = cv2.VideoWriter("aaa2.mp4", cv2.VideoWriter_fourcc(*'mp4v'), fps,
(int(width) * 2, int(height)))
command = ['ffmpeg -re -y -i ' + url +' -f rawvideo -pix_fmt bgr24 -an -']
pull_p = sp.Popen(command, stdout=sp.PIPE, shell=True)
num = 0
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
try:
while True:
print(num, nb_frames)
in_bytes = pull_p.stdout.read(width*height*3)
if in_bytes is not None and len(in_bytes) > 0:
img = np.frombuffer(in_bytes, np.uint8).reshape([height, width, 3])
# r = loop.run_until_complete(asyncio.gather(modprocess(img, width), carprocess(img, width)))
p_result, timeOut = senlin_mod.process(copy.deepcopy(img), width)
p_result1, timeOut1 = car_mod.process(copy.deepcopy(p_result[1]), width)
# r = loop.run_until_complete(asyncio.gather(modprocess(img, width), baiduprocess(img, client)))
# p_result, timeOut = r[0]
# result = r[1]
# p_result, timeOut = senlin_mod.process(copy.deepcopy(img), width)
# if result is not None:
# vehicleInfo = result.get("vehicle_info")
# if vehicleInfo is not None and len(vehicleInfo) > 0:
# for i, info in enumerate(vehicleInfo):
# value = VehicleEnumVALUE.get(info.get("type"))
# if value is None:
# logger.error("车辆识别出现未支持的目标类型type:{}", info.get("type"))
# raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0],
# ExceptionType.SERVICE_INNER_EXCEPTION.value[1])
# p_result[1] = mark(value.value[1], info, p_result[1], (255, 0, 255))
frame_merge = np.hstack((img, p_result1[1]))
or_video_file.write(frame_merge)
num+=1
else:
if num -10 > nb_frames:
break;
finally:
or_video_file.release()
pull_p.terminate()
pull_p.wait()

15
test/demo/demo3.py Normal file
View File

@ -0,0 +1,15 @@
import multiprocessing as mp
import time
from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor
from multiprocessing import Queue, shared_memory
import tensorrt as trt
# multiprocessing.set_start_method('spawn')
Detweights = "/home/th/tuo_heng/dev/AIlib2/weights/river2/yolov5_2080Ti_fp16.engine"
with open(Detweights, "rb") as f:
model = f.read()
Segweights = "/home/th/tuo_heng/dev/AIlib2/weights/river2/stdc_360X640_2080Ti_fp16.engine"
with open(Segweights, "rb") as f:
segmodel = f.read()
print(type(model), type(segmodel))

32
test/demo/demo4.py Normal file
View File

@ -0,0 +1,32 @@
import multiprocessing as mp
import time
from concurrent.futures import ProcessPoolExecutor
from multiprocessing import Queue, shared_memory
import tensorrt as trt
# multiprocessing.set_start_method('spawn')
Detweights = "/home/th/tuo_heng/dev/AIlib2/weights/river2/yolov5_2080Ti_fp16.engine"
start = time.time()
with open(Detweights, "rb") as f, trt.Runtime(trt.Logger(trt.Logger.ERROR)) as runtime:
model = runtime.deserialize_cuda_engine(f.read())
print(time.time() - start)
start1 = time.time()
Segweights = "/home/th/tuo_heng/dev/AIlib2/weights/river2/stdc_360X640_2080Ti_fp16.engine"
with open(Segweights, "rb") as f, trt.Runtime(trt.Logger(trt.Logger.ERROR)) as runtime:
segmodel = runtime.deserialize_cuda_engine(f.read())
print(time.time() - start1)
def aa(buf):
print(id(buf[0]), id(buf[1]))
shm = shared_memory.SharedMemory(name='share', create=True, size=10000)
buf = shm.buf
buf = model
buf[1] = segmodel
print(id(model), id(segmodel))
p = mp.Process(target=aa, args=(buf,))
p1 = mp.Process(target=aa, args=(buf,))
p.start()
p1.start()
time.sleep(10)

Some files were not shown because too many files have changed in this diff Show More