commit 3ad82a181dfe38406c3439de9eb789f168b42bd7 Author: th Date: Sat Apr 26 10:09:38 2025 +0800 first diff --git a/__init__.py b/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/__pycache__/dsp_master.cpython-38.pyc b/__pycache__/dsp_master.cpython-38.pyc new file mode 100644 index 0000000..ae39e3b Binary files /dev/null and b/__pycache__/dsp_master.cpython-38.pyc differ diff --git a/common/Constant.py b/common/Constant.py new file mode 100644 index 0000000..c147670 --- /dev/null +++ b/common/Constant.py @@ -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}$' + } + } +} diff --git a/common/YmlConstant.py b/common/YmlConstant.py new file mode 100644 index 0000000..eecc780 --- /dev/null +++ b/common/YmlConstant.py @@ -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' diff --git a/common/__init__.py b/common/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/common/__pycache__/Constant.cpython-310.pyc b/common/__pycache__/Constant.cpython-310.pyc new file mode 100644 index 0000000..d164c38 Binary files /dev/null and b/common/__pycache__/Constant.cpython-310.pyc differ diff --git a/common/__pycache__/Constant.cpython-38.pyc b/common/__pycache__/Constant.cpython-38.pyc new file mode 100644 index 0000000..73d6a84 Binary files /dev/null and b/common/__pycache__/Constant.cpython-38.pyc differ diff --git a/common/__pycache__/YmlConstant.cpython-38.pyc b/common/__pycache__/YmlConstant.cpython-38.pyc new file mode 100644 index 0000000..30975e0 Binary files /dev/null and b/common/__pycache__/YmlConstant.cpython-38.pyc differ diff --git a/common/__pycache__/__init__.cpython-310.pyc b/common/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..58366ca Binary files /dev/null and b/common/__pycache__/__init__.cpython-310.pyc differ diff --git a/common/__pycache__/__init__.cpython-38.pyc b/common/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..03bd997 Binary files /dev/null and b/common/__pycache__/__init__.cpython-38.pyc differ diff --git a/concurrency/CommonThread.py b/concurrency/CommonThread.py new file mode 100644 index 0000000..efcf548 --- /dev/null +++ b/concurrency/CommonThread.py @@ -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("线程停止完成!") diff --git a/concurrency/FeedbackThread.py b/concurrency/FeedbackThread.py new file mode 100644 index 0000000..bc5f1fe --- /dev/null +++ b/concurrency/FeedbackThread.py @@ -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("问题反馈线程执行完成") diff --git a/concurrency/FileUploadThread.py b/concurrency/FileUploadThread.py new file mode 100644 index 0000000..069f921 --- /dev/null +++ b/concurrency/FileUploadThread.py @@ -0,0 +1,385 @@ +# -*- 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 +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._algSwitch = self._context['service']['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: + 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: + 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) diff --git a/concurrency/FileUploadThread_20250106.py b/concurrency/FileUploadThread_20250106.py new file mode 100644 index 0000000..5531f9d --- /dev/null +++ b/concurrency/FileUploadThread_20250106.py @@ -0,0 +1,305 @@ +# -*- 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'])) + for tk in task: + tk.result() + 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) diff --git a/concurrency/FileUploadThread_withMiniSdk.py b/concurrency/FileUploadThread_withMiniSdk.py new file mode 100644 index 0000000..2275541 --- /dev/null +++ b/concurrency/FileUploadThread_withMiniSdk.py @@ -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) diff --git a/concurrency/HeartbeatThread.py b/concurrency/HeartbeatThread.py new file mode 100644 index 0000000..90ac707 --- /dev/null +++ b/concurrency/HeartbeatThread.py @@ -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) diff --git a/concurrency/IntelligentRecognitionProcess.py b/concurrency/IntelligentRecognitionProcess.py new file mode 100644 index 0000000..7c40632 --- /dev/null +++ b/concurrency/IntelligentRecognitionProcess.py @@ -0,0 +1,1482 @@ +# -*- coding: utf-8 -*- +import base64 +import os +from concurrent.futures import ThreadPoolExecutor +from os.path import join, exists, getsize +from time import time, sleep +from traceback import format_exc +import requests +import cv2 + +from multiprocessing import Process, Queue + +import numpy as np +from loguru import logger + +from common.Constant import init_progess, success_progess +from concurrency.FileUploadThread import ImageTypeImageFileUpload +from concurrency.HeartbeatThread import Heartbeat + +from concurrency.PullVideoStreamProcess import OnlinePullVideoStreamProcess, OfflinePullVideoStreamProcess +from concurrency.PushVideoStreamProcess import OnPushStreamProcess, OffPushStreamProcess + +from util.GPUtils import check_gpu_resource +from util.LogUtils import init_log +from concurrency.CommonThread import Common +from concurrency.PullStreamThread import RecordingPullStreamThread +from concurrency.RecordingHeartbeatThread import RecordingHeartbeat +from enums.AnalysisStatusEnum import AnalysisStatus +from enums.AnalysisTypeEnum import AnalysisType +from enums.ExceptionEnum import ExceptionType +from enums.ModelTypeEnum import ModelType +from enums.RecordingStatusEnum import RecordingStatus +from util.AliyunSdk import ThAliyunVodSdk +from util.MinioSdk import MinioSdk +from util.CpuUtils import check_cpu +from util.Cv2Utils import write_or_video, push_video_stream, close_all_p +from entity.FeedBack import message_feedback, recording_feedback +from exception.CustomerException import ServiceException +from util.ImageUtils import url2Array, add_water_pic +from util.ModelUtils import MODEL_CONFIG +from util.OcrBaiduSdk import OcrBaiduSdk + +from enums.BaiduSdkEnum import VehicleEnumVALUE +from enums.ModelTypeEnum import BaiduModelTarget +from util.PlotsUtils import xywh2xyxy2 +from util.QueUtil import put_queue, get_no_block_queue, clear_queue +from util.TimeUtils import now_date_to_str, YMDHMSF +from util.CpuUtils import print_cpu_status +import inspect +class IntelligentRecognitionProcess(Process): + __slots__ = ('_fb_queue', '_msg', '_analyse_type', '_context', 'event_queue', '_pull_queue', '_hb_queue', + "_image_queue", "_push_queue", '_push_ex_queue') + + def __init__(self, *args): + super().__init__() + # 入参 + self._fb_queue, self._msg, self._analyse_type, self._context = args + # 初始化参数 + self.event_queue, self._pull_queue, self._hb_queue, self._image_queue, self._push_queue, self._push_ex_queue = \ + Queue(), Queue(10), Queue(), Queue(), Queue(), Queue() + + # 发送waitting消息 + put_queue(self._fb_queue, message_feedback(self._msg["request_id"], AnalysisStatus.WAITING.value, + self._analyse_type, progress=init_progess), timeout=2, is_ex=True) + self._storage_source = self._context['service']['storage_source'] + self._algStatus = False + def sendEvent(self, eBody): + put_queue(self.event_queue, eBody, timeout=2, is_ex=True) + + def clear_queue(self): + clear_queue(self.event_queue) + clear_queue(self._pull_queue) + clear_queue(self._hb_queue) + clear_queue(self._image_queue) + clear_queue(self._push_queue) + clear_queue(self._push_ex_queue) + + @staticmethod + def build_video_path(context, msg, is_build_or=True): + random_time = now_date_to_str(YMDHMSF) + pre_path = '%s/%s%s' % (context["base_dir"], context["video"]["file_path"], random_time) + end_path = '%s%s' % (msg["request_id"], ".mp4") + if is_build_or: + context["orFilePath"] = '%s%s%s' % (pre_path, "_on_or_", end_path) + context["aiFilePath"] = '%s%s%s' % (pre_path, "_on_ai_", end_path) + + @staticmethod + def start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context): + hb_thread = Heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + hb_thread.setDaemon(True) + hb_thread.start() + return hb_thread + + + + + +class OnlineIntelligentRecognitionProcess(IntelligentRecognitionProcess): + __slots__ = () + + @staticmethod + def start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context): + pushProcess = OnPushStreamProcess(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + pushProcess.daemon = True + pushProcess.start() + return pushProcess + + @staticmethod + def start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, frame_num): + pullProcess = OnlinePullVideoStreamProcess(msg, context, fb_queue, pull_queue, image_queue, analyse_type, + frame_num) + pullProcess.daemon = True + pullProcess.start() + return pullProcess + + + def upload_video(self,base_dir, env, request_id, orFilePath, aiFilePath): + if self._storage_source==1: + minioSdk = MinioSdk(base_dir, env, request_id ) + upload_video_thread_or = Common(minioSdk.put_object, orFilePath, "or_online_%s.mp4" % request_id) + upload_video_thread_ai = Common(minioSdk.put_object, aiFilePath, "ai_online_%s.mp4" % request_id) + else: + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_or = Common(aliyunVodSdk.get_play_url, orFilePath, "or_online_%s" % request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + + + upload_video_thread_or.setDaemon(True) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_or.start() + upload_video_thread_ai.start() + or_url = upload_video_thread_or.get_result() + ai_url = upload_video_thread_ai.get_result() + return or_url, ai_url + ''' + @staticmethod + def upload_video(base_dir, env, request_id, orFilePath, aiFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_or = Common(aliyunVodSdk.get_play_url, orFilePath, "or_online_%s" % request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + upload_video_thread_or.setDaemon(True) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_or.start() + upload_video_thread_ai.start() + or_url = upload_video_thread_or.get_result() + ai_url = upload_video_thread_ai.get_result() + return or_url, ai_url + ''' + + @staticmethod + def ai_normal_dtection(model, frame, request_id): + model_conf, code = model + retResults = MODEL_CONFIG[code][3]([model_conf, frame, request_id])[0] + if type(retResults) is np.ndarray or len(retResults) == 0: + ret = retResults + if type(retResults) is np.ndarray: + ret = retResults.tolist() + else: + ret = retResults[2] + return code, ret + + @staticmethod + def obj_det(self, model_array, frame, task_status, cframe, tt, request_id): + push_obj = [] + if task_status[1] == 1: + dtection_result = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result.append(result) + for d in dtection_result: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) == 0: + task_status[1] = 0 + if task_status[1] == 0: + if cframe % 30 == 0: + dtection_result1 = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result1.append(result) + for d in dtection_result1: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) > 0: + task_status[1] = 1 + return push_obj + + @staticmethod + def checkPT(start_time, service_timeout, pull_process, push_process, hb_thread, push_ex_queue, pull_queue, + request_id): + 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 pull_process is not None and not pull_process.is_alive(): + while True: + if pull_queue.empty() or pull_queue.qsize() == 0: + break + pull_result = get_no_block_queue(pull_queue) + if pull_result is not None and pull_result[0] == 1: + raise ServiceException(pull_result[1], pull_result[2]) + logger.info("拉流进程异常停止, requestId: {}", request_id) + raise Exception("拉流进程异常停止!") + if hb_thread is not None and not hb_thread.is_alive(): + logger.info("心跳线程异常停止, requestId: {}", request_id) + raise Exception("心跳线程异常停止!") + if push_process is not None and not push_process.is_alive(): + while True: + if push_ex_queue.empty() or push_ex_queue.qsize() == 0: + break + push_result = get_no_block_queue(push_ex_queue) + if push_result is not None and push_result[0] == 1: + raise ServiceException(push_result[1], push_result[2]) + logger.info("推流进程异常停止, requestId: {}", request_id) + raise Exception("推流进程异常停止!") + + def run(self): + msg, context, analyse_type = self._msg, self._context, self._analyse_type + self.build_video_path(context, msg) + request_id = msg["request_id"] + base_dir, env = context["base_dir"], context["env"] + service_timeout = int(context["service"]["timeout"]) + ex = None + # 拉流进程、推流进程、心跳线程 + pull_process, push_process, hb_thread = None, None, None + + # 事件队列、拉流队列、心跳队列、反馈队列 + event_queue, pull_queue, hb_queue, fb_queue = self.event_queue, self._pull_queue, self._hb_queue, self._fb_queue + + # 推流队列、推流异常队列、图片队列 + push_queue, push_ex_queue, image_queue = self._push_queue, self._push_ex_queue, self._image_queue + try: + # 初始化日志 + init_log(base_dir, env) + # 打印启动日志 + logger.info("开始启动实时分析进程!requestId: {}", request_id) + + # 启动拉流进程(包含拉流线程, 图片上传线程,mqtt读取线程) + # 拉流进程初始化时间长, 先启动 + pull_process = self.start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, 25) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #7.0, + # 启动心跳线程 + hb_thread = self.start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + + + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #7.0, + # 加载算法模型 + model_array = get_model(msg, context, analyse_type) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #9.5 + # 启动推流进程 + push_process = self.start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + # 第一个参数: 模型是否初始化 0:未初始化 1:初始化 + # 第二个参数: 检测是否有问题 0: 没有问题, 1: 有问题 + task_status = [0, 0] + draw_config = {} + start_time = time() + # 识别2个线程性能最优 + with ThreadPoolExecutor(max_workers=2) as t: + # 可能使用模型组合, 模型组合最多3个模型, 1对3, 上面的2个线程对应6个线程 + with ThreadPoolExecutor(max_workers=6) as tt: + while True: + # 检查拉流进程是否正常, 心跳线程是否正常 + self.checkPT(start_time, service_timeout, pull_process, push_process, hb_thread, push_ex_queue, + pull_queue, request_id) + # 检查推流是否异常 + push_status = get_no_block_queue(push_ex_queue) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #9.5,11.2 + if push_status is not None and push_status[0] == 1: + raise ServiceException(push_status[1], push_status[2]) + # 获取停止指令 + event_result = get_no_block_queue(event_queue) + + if event_result: + cmdStr = event_result.get("command") + #接收到算法开启、或者关闭的命令 + if cmdStr in ['algStart' , 'algStop' ]: + logger.info("发送向推流进程发送算法命令, requestId: {}, {}", request_id,cmdStr ) + put_queue(push_queue, (2, cmdStr), timeout=1, is_ex=True) + pull_process.sendCommand({"command": cmdStr}) + + # 接收到停止指令 + if "stop" == cmdStr: + logger.info("实时任务开始停止, requestId: {}", request_id) + pull_process.sendCommand({"command": 'stop'}) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + pull_result = get_no_block_queue(pull_queue) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + if pull_result is None: + sleep(1) + continue + # (4, (frame_list, frame_index_list, all_frames)) + if pull_result[0] == 4: + frame_list, frame_index_list, all_frames = pull_result[1] + if len(frame_list) > 0: + # 判断是否已经初始化 + if task_status[0] == 0: + task_status[0] = 1 + for i, model in enumerate(model_array): + model_conf, code = model + model_param = model_conf[1] + # (modeType, model_param, allowedList, names, rainbows) + MODEL_CONFIG[code][2](frame_list[0].shape[1], frame_list[0].shape[0], + model_conf) + if draw_config.get("font_config") is None: + draw_config["font_config"] = model_param['font_config'] + if draw_config.get(code) is None: + draw_config[code] = {} + draw_config[code]["allowedList"] = model_conf[2] + draw_config[code]["rainbows"] = model_conf[4] + draw_config[code]["label_arrays"] = model_param['label_arraylist'] + if "label_dict" in model_param: + draw_config[code]["label_dict"] = model_param['label_dict'] + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + # 多线程并发处理, 经过测试两个线程最优 + det_array = [] + for i, frame in enumerate(frame_list): + det_result = t.submit(self.obj_det, self, model_array, frame, task_status, + frame_index_list[i], tt, request_id) + det_array.append(det_result) + push_objs = [det.result() for det in det_array] + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + put_queue(push_queue, + (1, (frame_list, frame_index_list, all_frames, draw_config, push_objs)), + timeout=2, is_ex=True) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + del det_array, push_objs + del frame_list, frame_index_list, all_frames + elif pull_result[0] == 1: + # 拉流发生异常 + put_queue(push_queue, (2, 'stop_ex'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + raise ServiceException(pull_result[1], pull_result[2]) + elif pull_result[0] == 2: + put_queue(push_queue, (2, 'stop'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + break + else: + raise Exception("未知拉流状态异常!") + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, 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: + orFilePath, aiFilePath = context["orFilePath"], context["aiFilePath"] + base_dir, env = context["base_dir"], context["env"] + or_url, ai_url, exc = "", "", None + try: + # 如果拉流进程存在, 关闭拉流进程(拉流线程、图片上传线程) + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + logger.info("关闭拉流进程, requestId:{}", request_id) + pull_process.join(timeout=120) + logger.info("关闭拉流进程1, requestId:{}", request_id) + if exists(orFilePath) and exists(aiFilePath) and getsize(orFilePath) > 100: + or_url, ai_url = self.upload_video(base_dir, env, request_id, orFilePath, aiFilePath) + if or_url is None or ai_url is None: + logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + # 停止心跳线程 + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=1) + hb_thread.join(timeout=120) + if exists(orFilePath): + logger.info("开始删除原视频, orFilePath: {}, requestId: {}", orFilePath, request_id) + os.remove(orFilePath) + logger.info("删除原视频成功, orFilePath: {}, requestId: {}", orFilePath, request_id) + if exists(aiFilePath): + logger.info("开始删除AI视频, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + os.remove(aiFilePath) + logger.info("删除AI视频成功, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + # 如果有异常, 检查是否有原视频和AI视频,有则上传,响应失败 + if ex: + code, msg = ex + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + video_url=or_url, + ai_video_url=ai_url), timeout=2, is_ex=False) + else: + if or_url is None or len(or_url) == 0 or ai_url is None or len(ai_url) == 0: + raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1]) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess, + video_url=or_url, + ai_video_url=ai_url), timeout=2, is_ex=False) + + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, request_id) + exc = s.code, s.msg + except Exception: + logger.error("服务异常: {}, requestId: {},", format_exc(), request_id) + exc = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + logger.info("关闭拉流进程, requestId:{}", request_id) + pull_process.join(timeout=120) + logger.info("关闭拉流进程1, requestId:{}", request_id) + if exc: + code, msg = exc + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + video_url=or_url, + ai_video_url=ai_url), timeout=2, is_ex=False) + logger.info("清理队列, requestId:{}", request_id) + self.clear_queue() + logger.info("清理队列完成, requestId:{}", request_id) + + +class OfflineIntelligentRecognitionProcess(IntelligentRecognitionProcess): + __slots__ = () + + def upload_video(self,base_dir, env, request_id, aiFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + if self._storage_source==1: + minioSdk = MinioSdk(base_dir, env, request_id ) + upload_video_thread_ai = Common(minioSdk.put_object, aiFilePath, "ai_online_%s.mp4" % request_id) + else: + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + ai_url = upload_video_thread_ai.get_result() + return ai_url + + ''' + @staticmethod + def upload_video(base_dir, env, request_id, aiFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + ai_url = upload_video_thread_ai.get_result() + return ai_url + ''' + @staticmethod + def ai_normal_dtection(model, frame, request_id): + model_conf, code = model + retResults = MODEL_CONFIG[code][3]([model_conf, frame, request_id])[0] + if type(retResults) is np.ndarray or len(retResults) == 0: + ret = retResults + if type(retResults) is np.ndarray: + ret = retResults.tolist() + else: + ret = retResults[2] + return code, ret + + @staticmethod + def obj_det(self, model_array, frame, task_status, cframe, tt, request_id): + push_obj = [] + if task_status[1] == 1: + dtection_result = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result.append(result) + for d in dtection_result: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) == 0: + task_status[1] = 0 + if task_status[1] == 0: + if cframe % 30 == 0: + dtection_result1 = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result1.append(result) + for d in dtection_result1: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) > 0: + task_status[1] = 1 + return push_obj + + @staticmethod + def start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context): + pushProcess = OffPushStreamProcess(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + pushProcess.daemon = True + pushProcess.start() + return pushProcess + + @staticmethod + def start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, frame_num): + pullProcess = OfflinePullVideoStreamProcess(msg, context, fb_queue, pull_queue, image_queue, analyse_type, + frame_num) + pullProcess.daemon = True + pullProcess.start() + return pullProcess + + @staticmethod + def checkPT(service_timeout, start_time, pull_process, push_process, hb_thread, push_ex_queue, pull_queue, + request_id): + 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 pull_process is not None and not pull_process.is_alive(): + while True: + if pull_queue.empty() or pull_queue.qsize() == 0: + break + pull_result = get_no_block_queue(pull_queue) + if pull_result is not None and pull_result[0] == 1: + raise ServiceException(pull_result[1], pull_result[2]) + logger.info("拉流进程异常停止, requestId: {}", request_id) + raise Exception("拉流进程异常停止!") + if hb_thread is not None and not hb_thread.is_alive(): + logger.info("心跳线程异常停止, requestId: {}", request_id) + raise Exception("心跳线程异常停止!") + if push_process is not None and not push_process.is_alive(): + while True: + if push_ex_queue.empty() or push_ex_queue.qsize() == 0: + break + push_result = get_no_block_queue(push_ex_queue) + if push_result is not None and push_result[0] == 1: + raise ServiceException(push_result[1], push_result[2]) + logger.info("推流进程异常停止, requestId: {}", request_id) + raise Exception("推流进程异常停止!") + + def run(self): + msg, context, analyse_type, ex = self._msg, self._context, self._analyse_type, None + self.build_video_path(context, msg, is_build_or=False) + request_id, base_dir, env = msg["request_id"], context["base_dir"], context["env"] + # 拉流进程、推流进程、心跳线程 + pull_process, push_process, hb_thread = None, None, None + service_timeout = int(context["service"]["timeout"]) + # 事件队列、拉流队列、心跳队列、反馈队列 + event_queue, pull_queue, hb_queue, fb_queue = self.event_queue, self._pull_queue, self._hb_queue, self._fb_queue + # 推流队列、推流异常队列、图片队列 + push_queue, push_ex_queue, image_queue = self._push_queue, self._push_ex_queue, self._image_queue + try: + # 初始化日志 + init_log(base_dir, env) + # 打印启动日志 + logger.info("开始启动离线分析进程!requestId: {}", request_id) + # 启动拉流进程(包含拉流线程, 图片上传线程) + # 拉流进程初始化时间长, 先启动 + pull_process = self.start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, 25) + # 启动心跳线程 + hb_thread = self.start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + # 加载算法模型 + model_array = get_model(msg, context, analyse_type) + # 启动推流进程 + push_process = self.start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + # 第一个参数: 模型是否初始化 0:未初始化 1:初始化 + # 第二个参数: 检测是否有问题 0: 没有问题, 1: 有问题 + task_status = [0, 0] + draw_config = {} + start_time = time() + # 识别2个线程性能最优 + with ThreadPoolExecutor(max_workers=2) as t: + # 可能使用模型组合, 模型组合最多3个模型, 1对3, 上面的2个线程对应6个线程 + with ThreadPoolExecutor(max_workers=6) as tt: + while True: + # 检查拉流进程是否正常, 心跳线程是否正常 + self.checkPT(service_timeout, start_time, pull_process, push_process, hb_thread, push_ex_queue, + pull_queue, request_id) + # 检查推流是否异常 + push_status = get_no_block_queue(push_ex_queue) + if push_status is not None and push_status[0] == 1: + raise ServiceException(push_status[1], push_status[2]) + # 获取停止指令 + event_result = get_no_block_queue(event_queue) + if event_result: + cmdStr = event_result.get("command") + # 接收到停止指令 + if "stop" == cmdStr: + logger.info("离线任务开始停止, requestId: {}", request_id) + pull_process.sendCommand({"command": 'stop'}) + if cmdStr in ['algStart' , 'algStop' ]: + logger.info("发送向推流进程发送算法命令, requestId: {}, {}", request_id,cmdStr ) + put_queue(push_queue, (2, cmdStr), timeout=1, is_ex=True) + pull_process.sendCommand({"command": cmdStr}) + + pull_result = get_no_block_queue(pull_queue) + if pull_result is None: + sleep(1) + continue + # (4, (frame_list, frame_index_list, all_frames)) + if pull_result[0] == 4: + frame_list, frame_index_list, all_frames = pull_result[1] + if len(frame_list) > 0: + # 判断是否已经初始化 + if task_status[0] == 0: + task_status[0] = 1 + for i, model in enumerate(model_array): + model_conf, code = model + model_param = model_conf[1] + # (modeType, model_param, allowedList, names, rainbows) + MODEL_CONFIG[code][2](frame_list[0].shape[1], frame_list[0].shape[0], + model_conf) + if draw_config.get("font_config") is None: + draw_config["font_config"] = model_param['font_config'] + if draw_config.get(code) is None: + draw_config[code] = {} + draw_config[code]["allowedList"] = model_conf[2] + draw_config[code]["rainbows"] = model_conf[4] + draw_config[code]["label_arrays"] = model_param['label_arraylist'] + if "label_dict" in model_param: + draw_config[code]["label_dict"] = model_param['label_dict'] + det_array = [] + for i, frame in enumerate(frame_list): + det_result = t.submit(self.obj_det, self, model_array, frame, task_status, + frame_index_list[i], tt, request_id) + det_array.append(det_result) + push_objs = [det.result() for det in det_array] + put_queue(push_queue, + (1, (frame_list, frame_index_list, all_frames, draw_config, push_objs)), + timeout=2, is_ex=True) + del det_array, push_objs + del frame_list, frame_index_list, all_frames + elif pull_result[0] == 1: + put_queue(push_queue, (2, 'stop_ex'), timeout=1, is_ex=True) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + raise ServiceException(pull_result[1], pull_result[2]) + elif pull_result[0] == 2: + logger.info("离线任务开始停止, requestId: {}", request_id) + put_queue(push_queue, (2, 'stop'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + break + else: + raise Exception("未知拉流状态异常!") + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, 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: + base_dir, env, aiFilePath = context["base_dir"], context["env"], context["aiFilePath"] + ai_url, exc = "", None + try: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + push_process.join(timeout=120) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(timeout=120) + if exists(aiFilePath) and getsize(aiFilePath) > 100: + ai_url = self.upload_video(base_dir, env, request_id, aiFilePath) + if ai_url is None: + logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + # 停止心跳线程 + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=1) + hb_thread.join(timeout=120) + if exists(aiFilePath): + logger.info("开始删除AI视频, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + os.remove(aiFilePath) + logger.info("删除AI视频成功, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + # 如果有异常, 检查是否有原视频和AI视频,有则上传,响应失败 + if ex: + code, msg = ex + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + ai_video_url=ai_url), timeout=2, is_ex=False) + else: + if ai_url is None or len(ai_url) == 0: + raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1]) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess, + ai_video_url=ai_url), timeout=2, is_ex=False) + + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, request_id) + exc = s.code, s.msg + except Exception: + logger.error("服务异常: {}, requestId: {},", format_exc(), request_id) + exc = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + push_process.join(timeout=120) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(timeout=120) + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=1) + hb_thread.join(timeout=120) + if exc: + code, msg = exc + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + ai_video_url=ai_url), timeout=2, is_ex=False) + self.clear_queue() + + +''' +图片识别 +''' + + +class PhotosIntelligentRecognitionProcess(Process): + __slots__ = ("_fb_queue", "_msg", "_analyse_type", "_context", "_image_queue") + + def __init__(self, *args): + super().__init__() + self._fb_queue, self._msg, self._analyse_type, self._context = args + self._image_queue = Queue() + put_queue(self._fb_queue, message_feedback(self._msg["request_id"], AnalysisStatus.WAITING.value, + self._analyse_type, progress=init_progess), timeout=2, is_ex=True) + self.build_logo(self._msg, self._context) + self._storage_source = self._context['service']['storage_source'] + + @staticmethod + def build_logo(msg, context): + logo = None + if context["video"]["video_add_water"]: + logo = msg.get("logo_url") + if logo is not None and len(logo) > 0: + logo = url2Array(logo, enable_ex=False) + if logo is None: + logo = cv2.imread(join(context['base_dir'], "image/logo.png"), -1) + context['logo'] = logo + + def epidemic_prevention(self, imageUrl, model, orc, request_id): + try: + # modeType, allowedList, new_device, model, par, img_type + model_conf, code = model + modeType, allowedList, new_device, model, par, img_type = model_conf + image = url2Array(imageUrl) + param = [image, new_device, model, par, img_type, request_id] + dataBack = MODEL_CONFIG[code][3](param) + if img_type == 'plate': + carCode = '' + if dataBack is None or dataBack.get("plateImage") is None or len(dataBack.get("plateImage")) == 0: + result = orc.license_plate_recognition(image, request_id) + score = '' + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + logger.error("车牌识别为空: {}", result) + carCode = '' + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + else: + result = orc.license_plate_recognition(dataBack.get("plateImage")[0], request_id) + score = dataBack.get("plateImage")[1] + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + result = orc.license_plate_recognition(image, request_id) + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + logger.error("车牌识别为空: {}", result) + carCode = '' + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + if len(carCode) > 0: + plate_result = {'type': str(3), 'modelCode': code, 'carUrl': imageUrl, + 'carCode': carCode, + 'score': score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(3), + plate_result), timeout=2, is_ex=True) + if img_type == 'code': + if dataBack is None or dataBack.get("type") is None: + return + # 行程码 + if dataBack.get("type") == 1 and 1 in allowedList: + # 手机号 + if dataBack.get("phoneNumberImage") is None or len(dataBack.get("phoneNumberImage")) == 0: + phoneNumberRecognition = '' + phone_score = '' + else: + phone = orc.universal_text_recognition(dataBack.get("phoneNumberImage")[0], request_id) + phone_score = dataBack.get("phoneNumberImage")[1] + if phone is None or phone.get("words_result") is None or len(phone.get("words_result")) == 0: + logger.error("手机号识别为空: {}", phone) + phoneNumberRecognition = '' + else: + phoneNumberRecognition = phone.get("words_result") + if dataBack.get("cityImage") is None or len(dataBack.get("cityImage")) == 0: + cityRecognition = '' + city_score = '' + else: + city = orc.universal_text_recognition(dataBack.get("cityImage")[0], request_id) + city_score = dataBack.get("cityImage")[1] + if city is None or city.get("words_result") is None or len(city.get("words_result")) == 0: + logger.error("城市识别为空: {}", city) + cityRecognition = '' + else: + cityRecognition = city.get("words_result") + if len(phoneNumberRecognition) > 0 or len(cityRecognition) > 0: + trip_result = {'type': str(1), + 'modelCode': code, + 'imageUrl': imageUrl, + 'phoneNumberRecognition': phoneNumberRecognition, + 'phone_sorce': phone_score, + 'cityRecognition': cityRecognition, + 'city_score': city_score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(1), + trip_result), timeout=2, is_ex=True) + if dataBack.get("type") == 2 and 2 in allowedList: + if dataBack.get("nameImage") is None or len(dataBack.get("nameImage")) == 0: + nameRecognition = '' + name_score = '' + else: + name = orc.universal_text_recognition(dataBack.get("nameImage")[0], request_id) + name_score = dataBack.get("nameImage")[1] + if name is None or name.get("words_result") is None or len(name.get("words_result")) == 0: + logger.error("名字识别为空: {}", name) + nameRecognition = '' + else: + nameRecognition = name.get("words_result") + + if dataBack.get("phoneNumberImage") is None or len(dataBack.get("phoneNumberImage")) == 0: + phoneNumberRecognition = '' + phone_score = '' + else: + phone = orc.universal_text_recognition(dataBack.get("phoneNumberImage")[0], request_id) + phone_score = dataBack.get("phoneNumberImage")[1] + if phone is None or phone.get("words_result") is None or len(phone.get("words_result")) == 0: + logger.error("手机号识别为空: {}", phone) + phoneNumberRecognition = '' + else: + phoneNumberRecognition = phone.get("words_result") + if dataBack.get("hsImage") is None or len(dataBack.get("hsImage")) == 0: + hsRecognition = '' + hs_score = '' + else: + hs = orc.universal_text_recognition(dataBack.get("hsImage")[0], request_id) + hs_score = dataBack.get("hsImage")[1] + if hs is None or hs.get("words_result") is None or len(hs.get("words_result")) == 0: + logger.error("核酸识别为空: {}", hs) + hsRecognition = '' + else: + hsRecognition = hs.get("words_result") + if len(nameRecognition) > 0 or len(phoneNumberRecognition) > 0 or len(hsRecognition) > 0: + healthy_result = {'type': str(2), + 'modelCode': code, + 'imageUrl': imageUrl, + 'color': dataBack.get("color"), + 'nameRecognition': nameRecognition, + 'name_score': name_score, + 'phoneNumberRecognition': phoneNumberRecognition, + 'phone_score': phone_score, + 'hsRecognition': hsRecognition, + 'hs_score': hs_score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(2), + healthy_result), timeout=2, is_ex=True) + except ServiceException as s: + raise s + except Exception as e: + logger.error("模型分析异常: {}, requestId: {}", format_exc(), request_id) + raise e + + ''' + # 防疫模型 + ''' + + def epidemicPrevention(self, imageUrls, model, base_dir, env, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + orc = OcrBaiduSdk(base_dir, env) + obj_list = [] + for imageUrl in imageUrls: + obj = t.submit(self.epidemic_prevention, imageUrl, model, orc, request_id) + obj_list.append(obj) + for r in obj_list: + r.result(60) + + def image_recognition(self, imageUrl, mod, image_queue, logo, request_id): + try: + model_conf, code = mod + model_param = model_conf[1] + image = url2Array(imageUrl) + MODEL_CONFIG[code][2](image.shape[1], image.shape[0], model_conf) + p_result = MODEL_CONFIG[code][3]([model_conf, image, request_id])[0] + #print(' line872:p_result[2]:',p_result[2] ) + if p_result is None or len(p_result) < 3 or p_result[2] is None or len(p_result[2]) == 0: + return + if logo: + image = add_water_pic(image, logo, request_id) + # (modeType, model_param, allowedList, names, rainbows) + allowedList = model_conf[2] + label_arraylist = model_param['label_arraylist'] + font_config = model_param['font_config'] + rainbows = model_conf[4] + det_xywh = {code: {}} + ai_result_list = p_result[2] + for ai_result in ai_result_list: + box, score, cls = xywh2xyxy2(ai_result) + # 如果检测目标在识别任务中,继续处理 + if cls in allowedList: + label_array = label_arraylist[cls] + color = rainbows[cls] + cd = det_xywh[code].get(cls) + 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]) + #print('ai_result_list:{},allowlist:{}'.format(ai_result_list,allowedList )) + if len(det_xywh) > 0: + put_queue(image_queue, (1, (det_xywh, imageUrl, image, font_config, "")), timeout=2, is_ex=False) + except ServiceException as s: + raise s + except Exception as e: + logger.error("模型分析异常: {}, requestId: {}", format_exc(), self._msg.get("request_id")) + raise e + + def publicIdentification(self, imageUrls, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + obj_list = [] + for imageUrl in imageUrls: + obj = t.submit(self.image_recognition, imageUrl, mod, image_queue, logo, request_id) + obj_list.append(obj) + for r in obj_list: + r.result(60) + + ''' + 1. imageUrls: 图片url数组,多张图片 + 2. mod: 模型对象 + 3. image_queue: 图片队列 + ''' + + def baiduRecognition(self, imageUrls, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + thread_result = [] + for imageUrl in imageUrls: + obj = t.submit(self.baidu_recognition, imageUrl, mod, image_queue, logo, request_id) + thread_result.append(obj) + for r in thread_result: + r.result(60) + + def baidu_recognition(self, imageUrl, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + try: + # modeType, aipImageClassifyClient, aipBodyAnalysisClient, allowedList, rainbows, + # vehicle_names, person_names, requestId + model_conf, code = mod + allowedList = model_conf[3] + rainbows = model_conf[4] + # 图片转数组 + img = url2Array(imageUrl) + vehicle_label_arrays, person_label_arrays, font_config = MODEL_CONFIG[code][2](img.shape[1], + img.shape[0], + model_conf) + obj_list = [] + for target in allowedList: + parm = [target, imageUrl, model_conf[1], model_conf[2], request_id] + reuslt = t.submit(self.baidu_method, code, parm, img, image_queue, vehicle_label_arrays, + person_label_arrays, font_config, rainbows, logo) + obj_list.append(reuslt) + for r in obj_list: + r.result(60) + except ServiceException as s: + raise s + except Exception as e: + logger.error("百度AI分析异常: {}, requestId: {}", format_exc(), request_id) + raise e + + @staticmethod + def baidu_method(code, parm, img, image_queue, vehicle_label_arrays, person_label_arrays, font_config, + rainbows, logo): + # [target, url, aipImageClassifyClient, aipBodyAnalysisClient, requestId] + request_id = parm[4] + target = parm[0] + image_url = parm[1] + result = MODEL_CONFIG[code][3](parm) + if target == BaiduModelTarget.VEHICLE_DETECTION.value[1] and result is not None: + vehicleInfo = result.get("vehicle_info") + if vehicleInfo is not None and len(vehicleInfo) > 0: + det_xywh = {code: {}} + copy_frame = img.copy() + for i, info in enumerate(vehicleInfo): + value = VehicleEnumVALUE.get(info.get("type")) + target_num = value.value[2] + label_array = vehicle_label_arrays[target_num] + color = rainbows[target_num] + if value is None: + logger.error("车辆识别出现未支持的目标类型!type:{}, requestId:{}", info.get("type"), request_id) + return + left_top = (int(info.get("location").get("left")), int(info.get("location").get("top"))) + right_top = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top"))) + right_bottom = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + left_bottom = (int(info.get("location").get("left")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + box = [left_top, right_top, right_bottom, left_bottom] + score = float("%.2f" % info.get("probability")) + if logo: + copy_frame = add_water_pic(copy_frame, logo, request_id) + if det_xywh[code].get(target) is None: + det_xywh[code][target] = [[target, box, score, label_array, color]] + else: + det_xywh[code][target].append([target, box, score, label_array, color]) + info["id"] = str(i) + if len(det_xywh[code]) > 0: + result["type"] = str(target) + result["modelCode"] = code + put_queue(image_queue, (1, (det_xywh, image_url, copy_frame, font_config, result)), timeout=2, + is_ex=True) + # 人体识别 + if target == BaiduModelTarget.HUMAN_DETECTION.value[1] and result is not None: + personInfo = result.get("person_info") + personNum = result.get("person_num") + if personNum is not None and personNum > 0 and personInfo is not None and len(personInfo) > 0: + det_xywh = {code: {}} + copy_frame = img.copy() + for i, info in enumerate(personInfo): + left_top = (int(info.get("location").get("left")), int(info.get("location").get("top"))) + right_top = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top"))) + right_bottom = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + left_bottom = (int(info.get("location").get("left")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + box = [left_top, right_top, right_bottom, left_bottom] + score = float("%.2f" % info.get("location").get("score")) + label_array = person_label_arrays[0] + color = rainbows[0] + if logo: + copy_frame = add_water_pic(copy_frame, logo, request_id) + if det_xywh[code].get(target) is None: + det_xywh[code][target] = [[target, box, score, label_array, color]] + else: + det_xywh[code][target].append([target, box, score, label_array, color]) + info["id"] = str(i) + if len(det_xywh[code]) > 0: + result["type"] = str(target) + result["modelCode"] = code + put_queue(image_queue, (1, (det_xywh, image_url, copy_frame, font_config, result)), timeout=2) + # 人流量 + if target == BaiduModelTarget.PEOPLE_COUNTING.value[1] and result is not None: + base64Image = result.get("image") + if base64Image is not None and len(base64Image) > 0: + baiduImage = base64.b64decode(base64Image) + result["type"] = str(target) + result["modelCode"] = code + del result["image"] + put_queue(image_queue, (1, (None, image_url, baiduImage, None, result)), timeout=2) + + @staticmethod + def start_File_upload(fb_queue, context, msg, image_queue, analyse_type): + image_thread = ImageTypeImageFileUpload(fb_queue, context, msg, image_queue, analyse_type) + image_thread.setDaemon(True) + image_thread.start() + return image_thread + def check_ImageUrl_Vaild(self,url,timeout=1): + try: + # 发送 HTTP 请求,尝试访问图片 + response = requests.get(url, timeout=timeout) # 设置超时时间为 10 秒 + if response.status_code == 200: + return True,url + else: + return False,f"图片地址无效,状态码:{response.status_code}" + except requests.exceptions.RequestException as e: + # 捕获请求过程中可能出现的异常(如网络问题、超时等) + return False,str(e) + + def run(self): + fb_queue, msg, analyse_type, context = self._fb_queue, self._msg, self._analyse_type, self._context + request_id, logo, image_queue = msg["request_id"], context['logo'], self._image_queue + base_dir, env = context["base_dir"], context["env"] + imageUrls = msg["image_urls"] + image_thread = None + init_log(base_dir, env) + valFlag=True + for url in imageUrls: + valFlag,ret = self.check_ImageUrl_Vaild(url,timeout=1) + + if not valFlag: + logger.error("图片分析异常: {}, requestId:{},url:{}",ret, request_id,url) + #print("AnalysisStatus.FAILED.value:{},ExceptionType.URL_ADDRESS_ACCESS_FAILED.value[0]:{},ExceptionType.URL_ADDRESS_ACCESS_FAILED.value[1]:{}".format(AnalysisStatus.FAILED.value,ExceptionType.URL_ADDRESS_ACCESS_FAILED.value[0],ExceptionType.URL_ADDRESS_ACCESS_FAILED.value[1] ) ) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + ExceptionType.URL_ADDRESS_ACCESS_FAILED.value[0], + ExceptionType.URL_ADDRESS_ACCESS_FAILED.value[1]), timeout=2) + + return + + + with ThreadPoolExecutor(max_workers=1) as t: + try: + #init_log(base_dir, env) + logger.info("开始启动图片识别进程, requestId: {}", request_id) + model_array = get_model(msg, context, analyse_type) + image_thread = self.start_File_upload(fb_queue, context, msg, image_queue, analyse_type) + task_list = [] + for model in model_array: + # 百度模型逻辑 + if model[1] == ModelType.BAIDU_MODEL.value[1]: + result = t.submit(self.baiduRecognition, imageUrls, model, image_queue, logo, request_id) + task_list.append(result) + # 防疫模型 + elif model[1] == ModelType.EPIDEMIC_PREVENTION_MODEL.value[1]: + result = t.submit(self.epidemicPrevention, imageUrls, model, base_dir, env, request_id) + task_list.append(result) + # 车牌模型 + elif model[1] == ModelType.PLATE_MODEL.value[1]: + result = t.submit(self.epidemicPrevention, imageUrls, model, base_dir, env, request_id) + task_list.append(result) + else: + result = t.submit(self.publicIdentification, imageUrls, model, image_queue, logo, request_id) + task_list.append(result) + for r in task_list: + r.result(60) + if image_thread and not image_thread.is_alive(): + raise Exception("图片识别图片上传线程异常停止!!!") + if image_thread and image_thread.is_alive(): + put_queue(image_queue, (2, 'stop'), timeout=2) + image_thread.join(120) + logger.info("图片进程任务完成,requestId:{}", request_id) + put_queue(fb_queue, message_feedback(request_id, + AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess), timeout=2, is_ex=True) + except ServiceException as s: + logger.error("图片分析异常,异常编号:{}, 异常描述:{}, requestId:{}", s.code, s.msg, request_id) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + s.code, + s.msg), timeout=2) + except Exception: + logger.error("图片分析异常: {}, requestId:{}", format_exc(), request_id) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]), timeout=2) + finally: + if image_thread and image_thread.is_alive(): + clear_queue(image_queue) + put_queue(image_queue, (2, 'stop'), timeout=2) + image_thread.join(120) + clear_queue(image_queue) + + +class ScreenRecordingProcess(Process): + __slots__ = ('_fb_queue', '_context', '_msg', '_analysisType', '_event_queue', '_hb_queue', '_analysisType') + + def __init__(self, *args): + super().__init__() + # 传参 + self._fb_queue, self._context, self._msg, self._analysisType = args + self._event_queue, self._hb_queue, self._pull_queue = Queue(), Queue(), Queue(10) + put_queue(self._fb_queue, + recording_feedback(self._msg["request_id"], RecordingStatus.RECORDING_WAITING.value[0]), + timeout=1, is_ex=True) + self._storage_source = self._context['service']['storage_source'] + def sendEvent(self, result): + put_queue(self._event_queue, result, timeout=2, is_ex=True) + + @staticmethod + def start_pull_stream_thread(msg, context, pull_queue, hb_queue, fb_queue, frame_num): + pullThread = RecordingPullStreamThread(msg, context, pull_queue, hb_queue, fb_queue, frame_num) + pullThread.setDaemon(True) + pullThread.start() + return pullThread + + @staticmethod + def start_hb_thread(fb_queue, hb_queue, request_id): + hb = RecordingHeartbeat(fb_queue, hb_queue, request_id) + hb.setDaemon(True) + hb.start() + return hb + + @staticmethod + def check(start_time, service_timeout, pull_thread, hb_thread, request_id): + 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 pull_thread and not pull_thread.is_alive(): + logger.info("录屏拉流线程停止异常, requestId: {}", request_id) + raise Exception("录屏拉流线程异常停止") + if hb_thread and not hb_thread.is_alive(): + logger.info("录屏心跳线程异常停止, requestId: {}", request_id) + raise Exception("录屏心跳线程异常停止") + + def run(self): + msg, context = self._msg, self._context + request_id, push_url = msg['request_id'], msg.get('push_url') + pull_queue, fb_queue, hb_queue, event_queue = self._pull_queue, self._fb_queue, self._hb_queue, \ + self._event_queue + base_dir, env, service_timeout = context['base_dir'], context['env'], int(context["service"]["timeout"]) + pre_path, end_path = '%s/%s%s' % (base_dir, context["video"]["file_path"], now_date_to_str(YMDHMSF)), \ + '%s%s' % (request_id, ".mp4") + orFilePath = '%s%s%s' % (pre_path, "_on_or_", end_path) + pull_thread, hb_thread = None, None + or_write_status, p_push_status = [0, 0], [0, 0] + or_video_file, push_p = None, None + ex = None + try: + # 初始化日志 + init_log(base_dir, env) + # 启动拉流线程 + pull_thread = self.start_pull_stream_thread(msg, context, pull_queue, hb_queue, fb_queue, 25) + hb_thread = self.start_hb_thread(fb_queue, hb_queue, request_id) + start_time = time() + with ThreadPoolExecutor(max_workers=2) as t: + while True: + # 检查拉流线程和心跳线程 + self.check(start_time, service_timeout, pull_thread, hb_thread, request_id) + # 判断是否需要停止录屏 + event_result = get_no_block_queue(event_queue) + if event_result is not None: + cmdStr = event_result.get("command") + # 接收到停止指令 + if 'stop' == cmdStr: + logger.info("录屏任务开始停止, requestId: {}", request_id) + pull_thread.sendEvent({"command": "stop"}) + pull_result = get_no_block_queue(pull_queue) + if pull_result is None: + sleep(1) + continue + if pull_result[0] == 1: + close_all_p(push_p, or_video_file, None, request_id) + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(180) + raise ServiceException(pull_result[1], pull_result[2]) + elif pull_result[0] == 2: + close_all_p(push_p, or_video_file, None, request_id) + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(180) + break + elif pull_result[0] == 4: + frame_list, frame_index_list, all_frames = pull_result[1] + if len(frame_list) > 0: + 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, {"progress": task_process}, timeout=1) + write_or_video_result = t.submit(write_or_video, frame, orFilePath, or_video_file, + or_write_status, request_id) + if push_url is not None and len(push_url) > 0: + push_p_result = t.submit(push_video_stream, frame, push_p, push_url, p_push_status, + request_id) + push_p = push_p_result.result() + or_video_file = write_or_video_result.result() + else: + raise Exception("未知拉流状态异常!") + logger.info("录屏线程任务完成,requestId:{}", self._msg.get("request_id")) + except ServiceException as s: + logger.error("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, self._msg.get("request_id")) + ex = s.code, s.msg + except Exception: + logger.error("服务异常: {}, requestId: {},", format_exc(), self._msg.get("request_id")) + ex = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + or_url = "" + exn = None + try: + # 关闭推流管道, 原视频写流客户端 + close_all_p(push_p, or_video_file, None, request_id) + # 关闭拉流线程 + if pull_thread and pull_thread.is_alive(): + pull_thread.sendEvent({"command": "stop_ex"}) + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(120) + # 判断是否需要上传视频 + if exists(orFilePath) and getsize(orFilePath) > 100: + or_url = self.upload_video(base_dir, env, request_id, orFilePath) + if or_url is None or len(or_url) == 0: + logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + # 停止心跳线程 + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=10, is_ex=False) + hb_thread.join(timeout=120) + if exists(orFilePath): + logger.info("开始删除原视频, orFilePath: {}, requestId: {}", orFilePath, request_id) + os.remove(orFilePath) + logger.info("删除原视频成功, orFilePath: {}, requestId: {}", orFilePath, request_id) + # 如果有异常, 检查是否有原视频和AI视频,有则上传,响应失败 + if ex: + code, msg = ex + put_queue(fb_queue, recording_feedback(request_id, RecordingStatus.RECORDING_FAILED.value[0], + error_code=code, + error_msg=msg, + video_url=or_url), timeout=10, is_ex=False) + else: + if or_url is None or len(or_url) == 0: + raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1]) + put_queue(fb_queue, recording_feedback(request_id, RecordingStatus.RECORDING_SUCCESS.value[0], + progress=success_progess, + video_url=or_url), timeout=10, is_ex=False) + except ServiceException as s: + exn = s.code, s.msg + except Exception: + logger.error("异常:{}, requestId: {}", format_exc(), request_id) + exn = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + if pull_thread and pull_thread.is_alive(): + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(120) + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=10, is_ex=False) + hb_thread.join(timeout=120) + self.clear_queue_end() + if exn: + code, msg = exn + put_queue(fb_queue, recording_feedback(request_id, RecordingStatus.RECORDING_FAILED.value[0], + error_code=code, + error_msg=msg, + video_url=or_url), timeout=10, is_ex=False) + + def clear_queue_end(self): + clear_queue(self._event_queue) + clear_queue(self._hb_queue) + clear_queue(self._pull_queue) + + + + + def upload_video(self,base_dir, env, request_id, orFilePath): + if self._storage_source==1: + minioSdk = MinioSdk(base_dir, env, request_id ) + upload_video_thread_ai = Common(minioSdk.put_object, aiFilePath, "%s/ai_online.mp4" % request_id) + else: + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + or_url = upload_video_thread_ai.get_result() + return or_url + ''' + @staticmethod + def upload_video(base_dir, env, request_id, orFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, orFilePath, "or_online_%s" % request_id) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + or_url = upload_video_thread_ai.get_result() + return or_url + ''' + +""" +"models": [{ + "code": "模型编号", + "categories":[{ + "id": "模型id", + "config": { + "k1": "v1", + "k2": "v2" + } + }] +}] +""" + + +def get_model(msg, context, analyse_type): + # 初始变量 + request_id, base_dir, gpu_name, env = msg["request_id"], context["base_dir"], context["gpu_name"], context["env"] + models, model_num_limit = msg["models"], context["service"]["model"]['limit'] + try: + # 实时、离线元组 + analyse_type_tuple = (AnalysisType.ONLINE.value, AnalysisType.OFFLINE.value) + # (实时、离线)检查模型组合, 目前只支持3个模型组合 + if analyse_type in analyse_type_tuple: + if len(models) > model_num_limit: + raise ServiceException(ExceptionType.MODEL_GROUP_LIMIT_EXCEPTION.value[0], + ExceptionType.MODEL_GROUP_LIMIT_EXCEPTION.value[1]) + modelArray, codeArray = [], set() + for model in models: + # 模型编码 + code = model["code"] + # 检验code是否重复 + if code in codeArray: + raise ServiceException(ExceptionType.MODEL_DUPLICATE_EXCEPTION.value[0], + ExceptionType.MODEL_DUPLICATE_EXCEPTION.value[1]) + codeArray.add(code) + # 检测目标数组 + needed_objectsIndex = list(set([int(category["id"]) for category in model["categories"]])) + logger.info("模型编号: {}, 检查目标: {}, requestId: {}", code, needed_objectsIndex, request_id) + model_method = MODEL_CONFIG.get(code) + if model_method is None: + logger.error("未匹配到对应的模型, requestId:{}", request_id) + raise ServiceException(ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[0], + ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[1]) + # 检查cpu资源、gpu资源 + check_cpu(base_dir, request_id) + gpu_ids = check_gpu_resource(request_id) + # 如果实时识别、离线识别 + if analyse_type in analyse_type_tuple: + if model["is_video"] == "1": + mod = model_method[0](gpu_ids[0], needed_objectsIndex, request_id, gpu_name, base_dir, env) + modelArray.append((mod.model_conf, code)) + else: + raise ServiceException(ExceptionType.MODEL_NOT_SUPPORT_VIDEO_EXCEPTION.value[0], + ExceptionType.MODEL_NOT_SUPPORT_VIDEO_EXCEPTION.value[1], + model_method[1].value[2]) + # 如果是图片识别 + if analyse_type == AnalysisType.IMAGE.value: + if model["is_image"] == "1": + mod = model_method[0](gpu_ids[0], needed_objectsIndex, request_id, gpu_name, base_dir, env) + modelArray.append((mod.model_conf, code)) + else: + raise ServiceException(ExceptionType.MODEL_NOT_SUPPORT_IMAGE_EXCEPTION.value[0], + ExceptionType.MODEL_NOT_SUPPORT_IMAGE_EXCEPTION.value[1], + model_method[1].value[2]) + if len(modelArray) == 0: + raise ServiceException(ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[0], + ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[1]) + return modelArray + except ServiceException as s: + raise s + except Exception: + logger.error("模型配置处理异常: {}, request_id: {}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) diff --git a/concurrency/IntelligentRecognitionProcess2.py b/concurrency/IntelligentRecognitionProcess2.py new file mode 100644 index 0000000..9afed2b --- /dev/null +++ b/concurrency/IntelligentRecognitionProcess2.py @@ -0,0 +1,1098 @@ +# -*- coding: utf-8 -*- +import base64 +import os +from concurrent.futures import ThreadPoolExecutor +from os.path import join, exists, getsize +from time import time, sleep +from traceback import format_exc + +import cv2 + +from multiprocessing import Process, Queue +from loguru import logger + +from common.Constant import init_progess, success_progess + +from concurrency.FileUploadThread import ImageTypeImageFileUpload +from concurrency.HeartbeatThread import Heartbeat +from concurrency.PullVideoStreamProcess2 import OnlinePullVideoStreamProcess2, OfflinePullVideoStreamProcess2 +from concurrency.PushVideoStreamProcess2 import OnPushStreamProcess2, OffPushStreamProcess2 + +from util.GPUtils import check_gpu_resource +from util.LogUtils import init_log +from concurrency.CommonThread import Common +from enums.AnalysisStatusEnum import AnalysisStatus +from enums.AnalysisTypeEnum import AnalysisType +from enums.ExceptionEnum import ExceptionType +from enums.ModelTypeEnum2 import ModelType2 +from util import TimeUtils +from util.AliyunSdk import ThAliyunVodSdk +from util.CpuUtils import check_cpu +from entity.FeedBack import message_feedback +from exception.CustomerException import ServiceException +from util.ImageUtils import url2Array, add_water_pic +from util.ModelUtils2 import MODEL_CONFIG2 +from util.OcrBaiduSdk import OcrBaiduSdk + +from enums.BaiduSdkEnum import VehicleEnumVALUE +from enums.ModelTypeEnum import BaiduModelTarget +from util.PlotsUtils import xywh2xyxy2 +from util.QueUtil import put_queue, get_no_block_queue, clear_queue +from util.TimeUtils import now_date_to_str, YMDHMSF + + +class IntelligentRecognitionProcess2(Process): + __slots__ = ('_fb_queue', '_msg', '_analyse_type', '_context', 'event_queue', '_pull_queue', '_hb_queue', + "_image_queue", "_push_queue", '_push_ex_queue') + + def __init__(self, *args): + super().__init__() + self._fb_queue, self._msg, self._analyse_type, self._context = args + self.event_queue, self._pull_queue, self._hb_queue, self._image_queue = Queue(), Queue(10), Queue(), Queue() + self._push_queue, self._push_ex_queue = Queue(), Queue() + put_queue(self._fb_queue, message_feedback(self._msg["request_id"], + AnalysisStatus.WAITING.value, + self._analyse_type, + progress=init_progess), timeout=2, is_ex=True) + + 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 clear_queue(self): + clear_queue(self.event_queue) + clear_queue(self._pull_queue) + clear_queue(self._hb_queue) + clear_queue(self._image_queue) + clear_queue(self._push_queue) + clear_queue(self._push_ex_queue) + + @staticmethod + def ai_dtection(model, frame_list, frame_index_list, request_id): + retResults = MODEL_CONFIG2[model[1]][3]([frame_list, frame_index_list, model[0][1], request_id])[0] + if len(frame_list) == 1: + return model[1], [retResults[2]] + return model[1], retResults[2] + + @staticmethod + def build_video_path(context, msg, is_build_or=True): + random_time = now_date_to_str(YMDHMSF) + pre_path = '%s/%s%s' % (context["base_dir"], context["video"]["file_path"], random_time) + end_path = '%s%s' % (msg["request_id"], ".mp4") + if is_build_or: + context["orFilePath"] = '%s%s%s' % (pre_path, "_on_or_", end_path) + context["aiFilePath"] = '%s%s%s' % (pre_path, "_on_ai_", end_path) + + @staticmethod + def start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context): + hb_thread = Heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + hb_thread.setDaemon(True) + hb_thread.start() + return hb_thread + + +class OnlineIntelligentRecognitionProcess2(IntelligentRecognitionProcess2): + __slots__ = () + + @staticmethod + def upload_video(base_dir, env, request_id, orFilePath, aiFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_or = Common(aliyunVodSdk.get_play_url, orFilePath, "or_online_%s" % request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + upload_video_thread_or.setDaemon(True) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_or.start() + upload_video_thread_ai.start() + or_url = upload_video_thread_or.get_result() + ai_url = upload_video_thread_ai.get_result() + return or_url, ai_url + + @staticmethod + def start_push_stream2(msg, push_queue, image_queue, push_ex_queue, hb_queue, context): + pushProcess = OnPushStreamProcess2(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + pushProcess.daemon = True + pushProcess.start() + return pushProcess + + @staticmethod + def start_pull_stream2(msg, context, fb_queue, pull_queue, image_queue, analyse_type, frame_num): + pullProcess = OnlinePullVideoStreamProcess2(msg, context, fb_queue, pull_queue, image_queue, analyse_type, + frame_num) + pullProcess.daemon = True + pullProcess.start() + return pullProcess + + @staticmethod + def checkPT(start_time, service_timeout, pull_process, push_process, hb_thread, push_ex_queue, pull_queue, + request_id): + 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 pull_process is not None and not pull_process.is_alive(): + while True: + if pull_queue.empty() or pull_queue.qsize() == 0: + break + pull_result = get_no_block_queue(pull_queue) + if pull_result is not None and pull_result[0] == 1: + raise ServiceException(pull_result[1], pull_result[2]) + logger.info("拉流进程异常停止, requestId: {}", request_id) + raise Exception("拉流进程异常停止!") + if hb_thread is not None and not hb_thread.is_alive(): + logger.info("心跳线程异常停止, requestId: {}", request_id) + raise Exception("心跳线程异常停止!") + if push_process is not None and not push_process.is_alive(): + while True: + if push_ex_queue.empty() or push_ex_queue.qsize() == 0: + break + push_result = get_no_block_queue(push_ex_queue) + if push_result is not None and push_result[0] == 1: + raise ServiceException(push_result[1], push_result[2]) + logger.info("推流进程异常停止, requestId: {}", request_id) + raise Exception("推流进程异常停止!") + + def run(self): + msg, context, analyse_type, ex = self._msg, self._context, self._analyse_type, None + self.build_video_path(context, msg) + request_id, base_dir, env = msg["request_id"], context["base_dir"], context["env"] + # 拉流进程、推流进程、心跳线程 + pull_process, push_process, hb_thread = None, None, None + # 事件队列、拉流队列、心跳队列、反馈队列 + event_queue, pull_queue, hb_queue, fb_queue = self.event_queue, self._pull_queue, self._hb_queue, self._fb_queue + # 推流队列、推流异常队列、图片队列 + push_queue, push_ex_queue, image_queue = self._push_queue, self._push_ex_queue, self._image_queue + service_timeout = int(context["service"]["timeout"]) + try: + # 初始化日志 + init_log(base_dir, env) + # 打印启动日志 + logger.info("开始启动实时分析进程!requestId: {}", request_id) + # 启动拉流进程(包含拉流线程, 图片上传线程) + # 拉流进程初始化时间长, 先启动 + pull_process = self.start_pull_stream2(msg, context, fb_queue, pull_queue, image_queue, analyse_type, 100) + # 启动心跳线程 + hb_thread = self.start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + # 加载算法模型 + model_array = get_model(msg, context, analyse_type) + # 启动推流进程 + push_process = self.start_push_stream2(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + # 第一个参数: 模型是否初始化 0:未初始化 1:初始化 + task_status = [0] + draw_config = {} + start_time = time() + with ThreadPoolExecutor(max_workers=3) as t: + while True: + # 检查拉流进程是否正常, 心跳线程是否正常 + self.checkPT(start_time, service_timeout, pull_process, push_process, hb_thread, push_ex_queue, + pull_queue, request_id) + # 检查推流是否异常 + push_status = get_no_block_queue(push_ex_queue) + if push_status is not None and push_status[0] == 1: + raise ServiceException(push_status[1], push_status[2]) + # 获取停止指令 + event_result = get_no_block_queue(event_queue) + if event_result: + cmdStr = event_result.get("command") + # 接收到停止指令 + if "stop" == cmdStr: + logger.info("实时任务开始停止, requestId: {}", request_id) + pull_process.sendCommand({"command": 'stop'}) + pull_result = get_no_block_queue(pull_queue) + if pull_result is None: + sleep(1) + continue + # (4, (frame_list, frame_index_list, all_frames)) + if pull_result[0] == 4: + frame_list, frame_index_list, all_frames = pull_result[1] + if len(frame_list) > 0: + # 判断是否已经初始化 + if task_status[0] == 0: + task_status[0] = 1 + for i, model in enumerate(model_array): + # (modeType, model_param, allowedList, names, rainbows) + model_conf, code = model + model_param = model_conf[1] + MODEL_CONFIG2[code][2](frame_list[0].shape[1], frame_list[0].shape[0], model_conf) + if draw_config.get("font_config") is None: + draw_config["font_config"] = model_param['font_config'] + if draw_config.get(code) is None: + draw_config[code] = {} + draw_config[code]["allowedList"] = model_conf[2] + draw_config[code]["rainbows"] = model_conf[4] + draw_config[code]["label_arrays"] = model_param['label_arraylist'] + det_array = [] + for model in model_array: + result = t.submit(self.ai_dtection, model, frame_list, frame_index_list, request_id) + det_array.append(result) + push_objs = [det.result() for det in det_array] + put_queue(push_queue, + (1, (frame_list, frame_index_list, all_frames, draw_config, push_objs)), + timeout=10) + del det_array, push_objs + del frame_list, frame_index_list, all_frames + elif pull_result[0] == 1: + put_queue(push_queue, (2, 'stop_ex'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + raise ServiceException(pull_result[1], pull_result[2]) + elif pull_result[0] == 2: + put_queue(push_queue, (2, 'stop'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + break + else: + raise Exception("未知拉流状态异常!") + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, 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: + orFilePath, aiFilePath = context["orFilePath"], context["aiFilePath"] + base_dir, env = context["base_dir"], context["env"] + or_url, ai_url, exc = "", "", None + try: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + logger.info("关闭拉流进程, requestId:{}", request_id) + pull_process.join(timeout=120) + logger.info("关闭拉流进程1, requestId:{}", request_id) + if exists(orFilePath) and exists(aiFilePath) and getsize(orFilePath) > 100: + or_url, ai_url = self.upload_video(base_dir, env, request_id, orFilePath, aiFilePath) + if or_url is None or ai_url is None: + logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + # 停止心跳线程 + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=10, is_ex=False) + hb_thread.join(timeout=120) + if exists(orFilePath): + logger.info("开始删除原视频, orFilePath: {}, requestId: {}", orFilePath, request_id) + os.remove(orFilePath) + logger.info("删除原视频成功, orFilePath: {}, requestId: {}", orFilePath, request_id) + if exists(aiFilePath): + logger.info("开始删除AI视频, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + os.remove(aiFilePath) + logger.info("删除AI视频成功, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + # 如果有异常, 检查是否有原视频和AI视频,有则上传,响应失败 + if ex: + code, msg = ex + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + video_url=or_url, + ai_video_url=ai_url), timeout=10, is_ex=False) + else: + if or_url is None or len(or_url) == 0 or ai_url is None or len(ai_url) == 0: + raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1]) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess, + video_url=or_url, + ai_video_url=ai_url), timeout=10, is_ex=False) + + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, request_id) + exc = s.code, s.msg + except Exception: + logger.error("服务异常: {}, requestId: {},", format_exc(), request_id) + exc = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + logger.info("关闭拉流进程, requestId:{}", request_id) + pull_process.join(timeout=120) + logger.info("关闭拉流进程1, requestId:{}", request_id) + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=10, is_ex=False) + hb_thread.join(timeout=120) + if exc: + code, msg = exc + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + video_url=or_url, + ai_video_url=ai_url), timeout=10, is_ex=False) + self.clear_queue() + + +class OfflineIntelligentRecognitionProcess2(IntelligentRecognitionProcess2): + __slots__ = () + + @staticmethod + def upload_video(base_dir, env, request_id, aiFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + ai_url = upload_video_thread_ai.get_result() + return ai_url + + @staticmethod + def start_push_stream2(msg, push_queue, image_queue, push_ex_queue, hb_queue, context): + pushProcess = OffPushStreamProcess2(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + pushProcess.daemon = True + pushProcess.start() + return pushProcess + + @staticmethod + def start_pull_stream2(msg, context, fb_queue, pull_queue, image_queue, analyse_type, frame_num): + pullProcess = OfflinePullVideoStreamProcess2(msg, context, fb_queue, pull_queue, image_queue, analyse_type, + frame_num) + pullProcess.daemon = True + pullProcess.start() + return pullProcess + + @staticmethod + def checkPT(start_time, service_timeout, pull_process, push_process, hb_thread, push_ex_queue, pull_queue, + request_id): + 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 pull_process is not None and not pull_process.is_alive(): + while True: + if pull_queue.empty() or pull_queue.qsize() == 0: + break + pull_result = get_no_block_queue(pull_queue) + if pull_result is not None and pull_result[0] == 1: + raise ServiceException(pull_result[1], pull_result[2]) + logger.info("拉流进程异常停止, requestId: {}", request_id) + raise Exception("拉流进程异常停止!") + if hb_thread is not None and not hb_thread.is_alive(): + logger.info("心跳线程异常停止, requestId: {}", request_id) + raise Exception("心跳线程异常停止!") + if push_process is not None and not push_process.is_alive(): + while True: + if push_ex_queue.empty() or push_ex_queue.qsize() == 0: + break + push_result = get_no_block_queue(push_ex_queue) + if push_result is not None and push_result[0] == 1: + raise ServiceException(push_result[1], push_result[2]) + logger.info("推流进程异常停止, requestId: {}", request_id) + raise Exception("推流进程异常停止!") + + def run(self): + msg, context, analyse_type, ex = self._msg, self._context, self._analyse_type, None + self.build_video_path(context, msg, is_build_or=False) + request_id, base_dir, env = msg["request_id"], context["base_dir"], context["env"] + # 拉流进程、推流进程 + pull_process, push_process = None, None + # 心跳线程 + hb_thread = None + # 事件队列、拉流队列、心跳队列、反馈队列 + event_queue, pull_queue, hb_queue, fb_queue = self.event_queue, self._pull_queue, self._hb_queue, self._fb_queue + # 推流队列、推流异常队列、图片队列 + push_queue, push_ex_queue, image_queue = self._push_queue, self._push_ex_queue, self._image_queue + try: + # 初始化日志 + init_log(base_dir, env) + # 打印启动日志 + logger.info("开始启动离线分析进程!requestId: {}", request_id) + # 启动拉流进程(包含拉流线程, 图片上传线程) + # 拉流进程初始化时间长, 先启动 + pull_process = self.start_pull_stream2(msg, context, fb_queue, pull_queue, image_queue, analyse_type, 100) + # 启动心跳线程 + hb_thread = self.start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + # 加载算法模型 + model_array = get_model(msg, context, analyse_type) + # 启动推流进程 + push_process = self.start_push_stream2(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + # 第一个参数: 模型是否初始化 0:未初始化 1:初始化 + # 第二个参数: 检测是否有问题 0: 没有问题, 1: 有问题 + task_status = [0, 0] + draw_config = {} + service_timeout = int(context["service"]["timeout"]) + start_time = time() + with ThreadPoolExecutor(max_workers=2) as t: + while True: + # 检查拉流进程是否正常, 心跳线程是否正常 + self.checkPT(start_time, service_timeout, pull_process, push_process, hb_thread, push_ex_queue, + pull_queue, request_id) + # 检查推流是否异常 + push_status = get_no_block_queue(push_ex_queue) + if push_status is not None and push_status[0] == 1: + raise ServiceException(push_status[1], push_status[2]) + # 获取停止指令 + event_result = get_no_block_queue(event_queue) + if event_result: + cmdStr = event_result.get("command") + # 接收到停止指令 + if "stop" == cmdStr: + logger.info("离线任务开始停止, requestId: {}", request_id) + pull_process.sendCommand({"command": 'stop'}) + pull_result = get_no_block_queue(pull_queue) + if pull_result is None: + sleep(1) + continue + # (4, (frame_list, frame_index_list, all_frames)) + if pull_result[0] == 4: + frame_list, frame_index_list, all_frames = pull_result[1] + if len(frame_list) > 0: + # 判断是否已经初始化 + if task_status[0] == 0: + task_status[0] = 1 + for i, model in enumerate(model_array): + model_conf, code = model + model_param = model_conf[1] + # (modeType, model_param, allowedList, names, rainbows) + MODEL_CONFIG2[code][2](frame_list[0].shape[1], frame_list[0].shape[0], + model_conf) + if draw_config.get("font_config") is None: + draw_config["font_config"] = model_param['font_config'] + if draw_config.get(code) is None: + draw_config[code] = {} + draw_config[code]["allowedList"] = model_conf[2] + draw_config[code]["rainbows"] = model_conf[4] + draw_config[code]["label_arrays"] = model_param['label_arraylist'] + # 多线程并发处理, 经过测试两个线程最优 + det_array = [] + for model in model_array: + result = t.submit(self.ai_dtection, model, frame_list, frame_index_list, request_id) + det_array.append(result) + push_objs = [det.result() for det in det_array] + put_queue(push_queue, + (1, (frame_list, frame_index_list, all_frames, draw_config, push_objs)), + timeout=10) + del det_array, push_objs + del frame_list, frame_index_list, all_frames + elif pull_result[0] == 1: + put_queue(push_queue, (2, 'stop_ex'), timeout=1, is_ex=True) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + raise ServiceException(pull_result[1], pull_result[2]) + elif pull_result[0] == 2: + logger.info("离线任务开始停止, requestId: {}", request_id) + put_queue(push_queue, (2, 'stop'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + break + else: + raise Exception("未知拉流状态异常!") + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, 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: + base_dir, env, aiFilePath = context["base_dir"], context["env"], context["aiFilePath"] + ai_url, exc = "", None + try: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + push_process.join(timeout=120) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(timeout=120) + if exists(aiFilePath) and getsize(aiFilePath) > 100: + ai_url = self.upload_video(base_dir, env, request_id, aiFilePath) + if ai_url is None: + logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + # 停止心跳线程 + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=2, is_ex=False) + hb_thread.join(timeout=120) + if exists(aiFilePath): + logger.info("开始删除AI视频, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + os.remove(aiFilePath) + logger.info("删除AI视频成功, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + # 如果有异常, 检查是否有原视频和AI视频,有则上传,响应失败 + if ex: + code, msg = ex + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + ai_video_url=ai_url), timeout=10, is_ex=False) + else: + if ai_url is None or len(ai_url) == 0: + raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1]) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess, + ai_video_url=ai_url), timeout=10, is_ex=False) + + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, request_id) + exc = s.code, s.msg + except Exception: + logger.error("服务异常: {}, requestId: {},", format_exc(), request_id) + exc = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + push_process.join(timeout=120) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(timeout=120) + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=10, is_ex=False) + hb_thread.join(timeout=120) + if exc: + code, msg = exc + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + ai_video_url=ai_url), timeout=10, is_ex=False) + self.clear_queue() + + +''' +图片识别 +''' + + +class PhotosIntelligentRecognitionProcess2(Process): + __slots__ = ("_fb_queue", "_msg", "_analyse_type", "_context", "_image_queue") + + def __init__(self, *args): + super().__init__() + self._fb_queue, self._msg, self._analyse_type, self._context = args + self._image_queue = Queue() + put_queue(self._fb_queue, message_feedback(self._msg["request_id"], + AnalysisStatus.WAITING.value, + self._analyse_type, + progress=init_progess), timeout=1, is_ex=True) + + self.build_logo(self._msg, self._context) + + @staticmethod + def build_logo(msg, context): + logo = None + if context["video"]["video_add_water"]: + logo = msg.get("logo_url") + if logo is not None and len(logo) > 0: + logo = url2Array(logo, enable_ex=False) + if logo is None: + logo = cv2.imread(join(context['base_dir'], "image/logo.png"), -1) + context['logo'] = logo + + def epidemic_prevention(self, imageUrl, model, orc, request_id): + try: + # modeType, allowedList, new_device, model, par, img_type + model_conf, code = model + modeType, model_param, allowedList = model_conf + img_type = model_param["img_type"] + image = url2Array(imageUrl) + param = [model_param, image, request_id] + dataBack = MODEL_CONFIG2[code][3](param) + if img_type == 'plate': + carCode = '' + if dataBack is None or dataBack.get("plateImage") is None or len(dataBack.get("plateImage")) == 0: + result = orc.license_plate_recognition(image, request_id) + score = '' + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + logger.error("车牌识别为空: {}", result) + carCode = '' + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + else: + result = orc.license_plate_recognition(dataBack.get("plateImage")[0], request_id) + score = dataBack.get("plateImage")[1] + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + result = orc.license_plate_recognition(image, request_id) + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + logger.error("车牌识别为空: {}", result) + carCode = '' + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + if len(carCode) > 0: + plate_result = {'type': str(3), 'modelCode': code, 'carUrl': imageUrl, + 'carCode': carCode, + 'score': score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(3), + plate_result), + timeout=1) + if img_type == 'code': + if dataBack is None or dataBack.get("type") is None: + return + # 行程码 + if dataBack.get("type") == 1 and 1 in allowedList: + # 手机号 + if dataBack.get("phoneNumberImage") is None or len(dataBack.get("phoneNumberImage")) == 0: + phoneNumberRecognition = '' + phone_score = '' + else: + phone = orc.universal_text_recognition(dataBack.get("phoneNumberImage")[0], request_id) + phone_score = dataBack.get("phoneNumberImage")[1] + if phone is None or phone.get("words_result") is None or len(phone.get("words_result")) == 0: + logger.error("手机号识别为空: {}", phone) + phoneNumberRecognition = '' + else: + phoneNumberRecognition = phone.get("words_result") + if dataBack.get("cityImage") is None or len(dataBack.get("cityImage")) == 0: + cityRecognition = '' + city_score = '' + else: + city = orc.universal_text_recognition(dataBack.get("cityImage")[0], request_id) + city_score = dataBack.get("cityImage")[1] + if city is None or city.get("words_result") is None or len(city.get("words_result")) == 0: + logger.error("城市识别为空: {}", city) + cityRecognition = '' + else: + cityRecognition = city.get("words_result") + if len(phoneNumberRecognition) > 0 or len(cityRecognition) > 0: + trip_result = {'type': str(1), + 'modelCode': code, + 'imageUrl': imageUrl, + 'phoneNumberRecognition': phoneNumberRecognition, + 'phone_sorce': phone_score, + 'cityRecognition': cityRecognition, + 'city_score': city_score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(1), + trip_result), + timeout=1) + if dataBack.get("type") == 2 and 2 in allowedList: + if dataBack.get("nameImage") is None or len(dataBack.get("nameImage")) == 0: + nameRecognition = '' + name_score = '' + else: + name = orc.universal_text_recognition(dataBack.get("nameImage")[0], request_id) + name_score = dataBack.get("nameImage")[1] + if name is None or name.get("words_result") is None or len(name.get("words_result")) == 0: + logger.error("名字识别为空: {}", name) + nameRecognition = '' + else: + nameRecognition = name.get("words_result") + + if dataBack.get("phoneNumberImage") is None or len(dataBack.get("phoneNumberImage")) == 0: + phoneNumberRecognition = '' + phone_score = '' + else: + phone = orc.universal_text_recognition(dataBack.get("phoneNumberImage")[0], request_id) + phone_score = dataBack.get("phoneNumberImage")[1] + if phone is None or phone.get("words_result") is None or len(phone.get("words_result")) == 0: + logger.error("手机号识别为空: {}", phone) + phoneNumberRecognition = '' + else: + phoneNumberRecognition = phone.get("words_result") + if dataBack.get("hsImage") is None or len(dataBack.get("hsImage")) == 0: + hsRecognition = '' + hs_score = '' + else: + hs = orc.universal_text_recognition(dataBack.get("hsImage")[0], request_id) + hs_score = dataBack.get("hsImage")[1] + if hs is None or hs.get("words_result") is None or len(hs.get("words_result")) == 0: + logger.error("核酸识别为空: {}", hs) + hsRecognition = '' + else: + hsRecognition = hs.get("words_result") + if len(nameRecognition) > 0 or len(phoneNumberRecognition) > 0 or len(hsRecognition) > 0: + healthy_result = {'type': str(2), + 'modelCode': code, + 'imageUrl': imageUrl, + 'color': dataBack.get("color"), + 'nameRecognition': nameRecognition, + 'name_score': name_score, + 'phoneNumberRecognition': phoneNumberRecognition, + 'phone_score': phone_score, + 'hsRecognition': hsRecognition, + 'hs_score': hs_score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(2), + healthy_result), + timeout=1) + except ServiceException as s: + raise s + except Exception as e: + logger.error("模型分析异常: {}, requestId: {}", format_exc(), request_id) + raise e + + ''' + # 防疫模型 + ''' + + def epidemicPrevention(self, imageUrls, model, base_dir, env, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + orc = OcrBaiduSdk(base_dir, env) + obj_list = [] + for imageUrl in imageUrls: + obj = t.submit(self.epidemic_prevention, imageUrl, model, orc, request_id) + obj_list.append(obj) + for r in obj_list: + r.result(60) + + def image_recognition(self, imageUrl, mod, image_queue, logo, request_id): + try: + model_conf, code = mod + model_param = model_conf[1] + image = url2Array(imageUrl) + MODEL_CONFIG2[code][2](image.shape[1], image.shape[0], model_conf) + p_result = MODEL_CONFIG2[code][3]([[image], [0], model_param, request_id])[0] + if p_result is None or len(p_result) < 3 or p_result[2] is None or len(p_result[2]) == 0: + return + if logo: + image = add_water_pic(image, logo, request_id) + # (modeType, model_param, allowedList, names, rainbows) + allowedList = model_conf[2] + label_arraylist = model_param['label_arraylist'] + font_config = model_param['font_config'] + rainbows = model_conf[4] + det_xywh = {code: {}} + ai_result_list = p_result[2] + for ai_result in ai_result_list: + box, score, cls = xywh2xyxy2(ai_result) + # 如果检测目标在识别任务中,继续处理 + if cls in allowedList: + label_array = label_arraylist[cls] + color = rainbows[cls] + cd = det_xywh[code].get(cls) + 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]) + logger.info(" line813 ai_result_list{}, det_xywh: {}, allowedList:{} ".format( ai_result_list, det_xywh,allowedList) ) + if len(det_xywh) > 0: + put_queue(image_queue, (1, (det_xywh, imageUrl, image, font_config, ""))) + except ServiceException as s: + raise s + except Exception as e: + logger.error("模型分析异常: {}, requestId: {}", format_exc(), self._msg.get("request_id")) + raise e + + def publicIdentification(self, imageUrls, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + obj_list = [] + logger.info(' publicIdentification line823') + for imageUrl in imageUrls: + obj = t.submit(self.image_recognition, imageUrl, mod, image_queue, logo, request_id) + obj_list.append(obj) + for r in obj_list: + r.result(60) + + ''' + 1. imageUrls: 图片url数组,多张图片 + 2. mod: 模型对象 + 3. image_queue: 图片队列 + ''' + + def baiduRecognition(self, imageUrls, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + thread_result = [] + for imageUrl in imageUrls: + obj = t.submit(self.baidu_recognition, imageUrl, mod, image_queue, logo, request_id) + thread_result.append(obj) + for r in thread_result: + r.result() + + def baidu_recognition(self, imageUrl, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + try: + # (modeType, model_param, allowedList, (vehicle_names, person_names), rainbows) + model_conf, code = mod + model_param = model_conf[1] + allowedList = model_conf[2] + rainbows = model_conf[4] + # 图片转数组 + img = url2Array(imageUrl) + MODEL_CONFIG2[code][2](img.shape[1], img.shape[0], model_conf) + vehicle_label_arrays = model_param["vehicle_label_arrays"] + person_label_arrays = model_param["person_label_arrays"] + font_config = model_param["font_config"] + obj_list = [] + for target in allowedList: + parm = [model_param, target, imageUrl, request_id] + reuslt = t.submit(self.baidu_method, code, parm, img, image_queue, vehicle_label_arrays, + person_label_arrays, font_config, rainbows, logo) + obj_list.append(reuslt) + for r in obj_list: + r.result() + except ServiceException as s: + raise s + except Exception as e: + logger.error("百度AI分析异常: {}, requestId: {}", format_exc(), request_id) + raise e + + @staticmethod + def baidu_method(code, parm, img, image_queue, vehicle_label_arrays, person_label_arrays, font_config, + rainbows, logo): + # [model_param, target, imageUrl, request_id]] + request_id = parm[3] + target = parm[1] + image_url = parm[2] + result = MODEL_CONFIG2[code][3](parm) + if target == BaiduModelTarget.VEHICLE_DETECTION.value[1] and result is not None: + vehicleInfo = result.get("vehicle_info") + if vehicleInfo is not None and len(vehicleInfo) > 0: + det_xywh = {code: {}} + copy_frame = img.copy() + for i, info in enumerate(vehicleInfo): + value = VehicleEnumVALUE.get(info.get("type")) + target_num = value.value[2] + label_array = vehicle_label_arrays[target_num] + color = rainbows[target_num] + if value is None: + logger.error("车辆识别出现未支持的目标类型!type:{}, requestId:{}", info.get("type"), request_id) + return + left_top = (int(info.get("location").get("left")), int(info.get("location").get("top"))) + right_top = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top"))) + right_bottom = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + left_bottom = (int(info.get("location").get("left")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + box = [left_top, right_top, right_bottom, left_bottom] + score = float("%.2f" % info.get("probability")) + if logo: + copy_frame = add_water_pic(copy_frame, logo, request_id) + if det_xywh[code].get(target) is None: + det_xywh[code][target] = [[target, box, score, label_array, color]] + else: + det_xywh[code][target].append([target, box, score, label_array, color]) + info["id"] = str(i) + if len(det_xywh[code]) > 0: + result["type"] = str(target) + result["modelCode"] = code + put_queue(image_queue, (1, (det_xywh, image_url, copy_frame, font_config, result))) + # 人体识别 + if target == BaiduModelTarget.HUMAN_DETECTION.value[1] and result is not None: + personInfo = result.get("person_info") + personNum = result.get("person_num") + if personNum is not None and personNum > 0 and personInfo is not None and len(personInfo) > 0: + det_xywh = {code: {}} + copy_frame = img.copy() + for i, info in enumerate(personInfo): + left_top = (int(info.get("location").get("left")), int(info.get("location").get("top"))) + right_top = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top"))) + right_bottom = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + left_bottom = (int(info.get("location").get("left")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + box = [left_top, right_top, right_bottom, left_bottom] + score = float("%.2f" % info.get("location").get("score")) + label_array = person_label_arrays[0] + color = rainbows[0] + if logo: + copy_frame = add_water_pic(copy_frame, logo, request_id) + if det_xywh[code].get(target) is None: + det_xywh[code][target] = [[target, box, score, label_array, color]] + else: + det_xywh[code][target].append([target, box, score, label_array, color]) + info["id"] = str(i) + if len(det_xywh[code]) > 0: + result["type"] = str(target) + result["modelCode"] = code + put_queue(image_queue, (1, (det_xywh, image_url, copy_frame, font_config, result))) + # 人流量 + if target == BaiduModelTarget.PEOPLE_COUNTING.value[1] and result is not None: + base64Image = result.get("image") + if base64Image is not None and len(base64Image) > 0: + baiduImage = base64.b64decode(base64Image) + result["type"] = str(target) + result["modelCode"] = code + del result["image"] + put_queue(image_queue, (1, (None, image_url, baiduImage, None, result))) + + @staticmethod + def start_File_upload(*args): + fb_queue, context, msg, image_queue, analyse_type = args + image_thread = ImageTypeImageFileUpload(fb_queue, context, msg, image_queue, analyse_type) + image_thread.setDaemon(True) + image_thread.start() + return image_thread + + def run(self): + fb_queue, msg, analyse_type, context = self._fb_queue, self._msg, self._analyse_type, self._context + request_id, logo, image_queue = msg["request_id"], context['logo'], self._image_queue + base_dir, env = context["base_dir"], context["env"] + imageUrls = msg["image_urls"] + image_thread = None + with ThreadPoolExecutor(max_workers=3) as t: + try: + init_log(base_dir, env) + logger.info("开始启动图片识别进程, requestId: {}", request_id) + model_array = get_model(msg, context, analyse_type) + image_thread = self.start_File_upload(fb_queue, context, msg, image_queue, analyse_type) + task_list = [] + for model in model_array: + # 百度模型逻辑 + if model[1] == ModelType2.BAIDU_MODEL.value[1]: + result = t.submit(self.baiduRecognition, imageUrls, model, image_queue, logo, request_id) + task_list.append(result) + # 防疫模型 + elif model[1] == ModelType2.EPIDEMIC_PREVENTION_MODEL.value[1]: + result = t.submit(self.epidemicPrevention, imageUrls, model, base_dir, env, request_id) + task_list.append(result) + # 车牌模型 + elif model[1] == ModelType2.PLATE_MODEL.value[1]: + result = t.submit(self.epidemicPrevention, imageUrls, model, base_dir, env, request_id) + task_list.append(result) + else: + result = t.submit(self.publicIdentification, imageUrls, model, image_queue, logo, request_id) + task_list.append(result) + for r in task_list: + r.result(timeout=60) + logger.info(' line993: result:-------- ' ) + if image_thread and not image_thread.is_alive(): + raise Exception("图片识别图片上传线程异常停止!!!") + if image_thread and image_thread.is_alive(): + put_queue(image_queue, (2, 'stop'), timeout=10, is_ex=True) + image_thread.join(120) + logger.info("图片进程任务完成,requestId:{}", request_id) + put_queue(fb_queue, message_feedback(request_id, + AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess), timeout=10, is_ex=True) + except ServiceException as s: + logger.error("图片分析异常,异常编号:{}, 异常描述:{}, requestId:{}", s.code, s.msg, request_id) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + s.code, + s.msg)) + except Exception: + logger.error("图片分析异常: {}, requestId:{}", format_exc(), request_id) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1])) + finally: + if image_thread and image_thread.is_alive(): + put_queue(image_queue, (2, 'stop'), timeout=10, is_ex=True) + image_thread.join(120) + clear_queue(image_queue) + + +""" +"models": [{ + "code": "模型编号", + "categories":[{ + "id": "模型id", + "config": { + "k1": "v1", + "k2": "v2" + } + }] +}] +""" + + +def get_model(msg, context, analyse_type): + # 初始变量 + request_id, base_dir, gpu_name, env = msg["request_id"], context["base_dir"], context["gpu_name"], context["env"] + models, model_num_limit = msg["models"], context["service"]["model"]['limit'] + try: + # 实时、离线元组 + analyse_type_tuple = (AnalysisType.ONLINE.value, AnalysisType.OFFLINE.value) + # (实时、离线)检查模型组合, 目前只支持3个模型组合 + if analyse_type in analyse_type_tuple: + if len(models) > model_num_limit: + raise ServiceException(ExceptionType.MODEL_GROUP_LIMIT_EXCEPTION.value[0], + ExceptionType.MODEL_GROUP_LIMIT_EXCEPTION.value[1]) + modelArray, codeArray = [], set() + for model in models: + # 模型编码 + code = model["code"] + # 检验code是否重复 + if code in codeArray: + raise ServiceException(ExceptionType.MODEL_DUPLICATE_EXCEPTION.value[0], + ExceptionType.MODEL_DUPLICATE_EXCEPTION.value[1]) + codeArray.add(code) + # 检测目标数组 + needed_objectsIndex = list(set([int(category["id"]) for category in model["categories"]])) + logger.info("模型编号: {}, 检查目标: {}, requestId: {}", code, needed_objectsIndex, request_id) + model_method = MODEL_CONFIG2.get(code) + if model_method is None: + logger.error("未匹配到对应的模型, requestId:{}", request_id) + raise ServiceException(ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[0], + ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[1]) + # 检查cpu资源、gpu资源 + check_cpu(base_dir, request_id) + gpu_ids = check_gpu_resource(request_id) + # 如果实时识别、离线识别 + if analyse_type in analyse_type_tuple: + if model["is_video"] == "1": + mod = model_method[0](gpu_ids[0], needed_objectsIndex, request_id, gpu_name, base_dir, env) + modelArray.append((mod.model_conf, code)) + else: + raise ServiceException(ExceptionType.MODEL_NOT_SUPPORT_VIDEO_EXCEPTION.value[0], + ExceptionType.MODEL_NOT_SUPPORT_VIDEO_EXCEPTION.value[1], + model_method[1].value[2]) + # 如果是图片识别 + if analyse_type == AnalysisType.IMAGE.value: + if model["is_image"] == "1": + mod = model_method[0](gpu_ids[0], needed_objectsIndex, request_id, gpu_name, base_dir, env) + modelArray.append((mod.model_conf, code)) + else: + raise ServiceException(ExceptionType.MODEL_NOT_SUPPORT_IMAGE_EXCEPTION.value[0], + ExceptionType.MODEL_NOT_SUPPORT_IMAGE_EXCEPTION.value[1], + model_method[1].value[2]) + if len(modelArray) == 0: + raise ServiceException(ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[0], + ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[1]) + return modelArray + except ServiceException as s: + raise s + except Exception: + logger.error("模型配置处理异常: {}, request_id: {}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) diff --git a/concurrency/IntelligentRecognitionProcess_20250106.py b/concurrency/IntelligentRecognitionProcess_20250106.py new file mode 100644 index 0000000..3e56ce0 --- /dev/null +++ b/concurrency/IntelligentRecognitionProcess_20250106.py @@ -0,0 +1,1444 @@ +# -*- coding: utf-8 -*- +import base64 +import os +from concurrent.futures import ThreadPoolExecutor +from os.path import join, exists, getsize +from time import time, sleep +from traceback import format_exc + +import cv2 + +from multiprocessing import Process, Queue + +import numpy as np +from loguru import logger + +from common.Constant import init_progess, success_progess +from concurrency.FileUploadThread import ImageTypeImageFileUpload +from concurrency.HeartbeatThread import Heartbeat + +from concurrency.PullVideoStreamProcess import OnlinePullVideoStreamProcess, OfflinePullVideoStreamProcess +from concurrency.PushVideoStreamProcess import OnPushStreamProcess, OffPushStreamProcess + +from util.GPUtils import check_gpu_resource +from util.LogUtils import init_log +from concurrency.CommonThread import Common +from concurrency.PullStreamThread import RecordingPullStreamThread +from concurrency.RecordingHeartbeatThread import RecordingHeartbeat +from enums.AnalysisStatusEnum import AnalysisStatus +from enums.AnalysisTypeEnum import AnalysisType +from enums.ExceptionEnum import ExceptionType +from enums.ModelTypeEnum import ModelType +from enums.RecordingStatusEnum import RecordingStatus +from util.AliyunSdk import ThAliyunVodSdk +from util.CpuUtils import check_cpu +from util.Cv2Utils import write_or_video, push_video_stream, close_all_p +from entity.FeedBack import message_feedback, recording_feedback +from exception.CustomerException import ServiceException +from util.ImageUtils import url2Array, add_water_pic +from util.ModelUtils import MODEL_CONFIG +from util.OcrBaiduSdk import OcrBaiduSdk + +from enums.BaiduSdkEnum import VehicleEnumVALUE +from enums.ModelTypeEnum import BaiduModelTarget +from util.PlotsUtils import xywh2xyxy2 +from util.QueUtil import put_queue, get_no_block_queue, clear_queue +from util.TimeUtils import now_date_to_str, YMDHMSF +from util.CpuUtils import print_cpu_status +import inspect +class IntelligentRecognitionProcess(Process): + __slots__ = ('_fb_queue', '_msg', '_analyse_type', '_context', 'event_queue', '_pull_queue', '_hb_queue', + "_image_queue", "_push_queue", '_push_ex_queue') + + def __init__(self, *args): + super().__init__() + # 入参 + self._fb_queue, self._msg, self._analyse_type, self._context = args + # 初始化参数 + self.event_queue, self._pull_queue, self._hb_queue, self._image_queue, self._push_queue, self._push_ex_queue = \ + Queue(), Queue(10), Queue(), Queue(), Queue(), Queue() + + # 发送waitting消息 + put_queue(self._fb_queue, message_feedback(self._msg["request_id"], AnalysisStatus.WAITING.value, + self._analyse_type, progress=init_progess), timeout=2, is_ex=True) + self._storage_source = self._context['service']['storage_source'] + + def sendEvent(self, eBody): + put_queue(self.event_queue, eBody, timeout=2, is_ex=True) + + def clear_queue(self): + clear_queue(self.event_queue) + clear_queue(self._pull_queue) + clear_queue(self._hb_queue) + clear_queue(self._image_queue) + clear_queue(self._push_queue) + clear_queue(self._push_ex_queue) + + @staticmethod + def build_video_path(context, msg, is_build_or=True): + random_time = now_date_to_str(YMDHMSF) + pre_path = '%s/%s%s' % (context["base_dir"], context["video"]["file_path"], random_time) + end_path = '%s%s' % (msg["request_id"], ".mp4") + if is_build_or: + context["orFilePath"] = '%s%s%s' % (pre_path, "_on_or_", end_path) + context["aiFilePath"] = '%s%s%s' % (pre_path, "_on_ai_", end_path) + + @staticmethod + def start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context): + hb_thread = Heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + hb_thread.setDaemon(True) + hb_thread.start() + return hb_thread + + + + + +class OnlineIntelligentRecognitionProcess(IntelligentRecognitionProcess): + __slots__ = () + + @staticmethod + def start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context): + pushProcess = OnPushStreamProcess(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + pushProcess.daemon = True + pushProcess.start() + return pushProcess + + @staticmethod + def start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, frame_num): + pullProcess = OnlinePullVideoStreamProcess(msg, context, fb_queue, pull_queue, image_queue, analyse_type, + frame_num) + pullProcess.daemon = True + pullProcess.start() + return pullProcess + + + def upload_video(self,base_dir, env, request_id, orFilePath, aiFilePath): + if self._storage_source==1: + minioSdk = MinioSdk(base_dir, env, request_id ) + upload_video_thread_or = Common(minioSdk.put_object, orFilePath, "%s/or_online.mp4" % request_id) + upload_video_thread_ai = Common(minioSdk.put_object, aiFilePath, "%s/ai_online.mp4" % request_id) + else: + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_or = Common(aliyunVodSdk.get_play_url, orFilePath, "or_online_%s" % request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + + + upload_video_thread_or.setDaemon(True) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_or.start() + upload_video_thread_ai.start() + or_url = upload_video_thread_or.get_result() + ai_url = upload_video_thread_ai.get_result() + return or_url, ai_url + ''' + @staticmethod + def upload_video(base_dir, env, request_id, orFilePath, aiFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_or = Common(aliyunVodSdk.get_play_url, orFilePath, "or_online_%s" % request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + upload_video_thread_or.setDaemon(True) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_or.start() + upload_video_thread_ai.start() + or_url = upload_video_thread_or.get_result() + ai_url = upload_video_thread_ai.get_result() + return or_url, ai_url + ''' + + @staticmethod + def ai_normal_dtection(model, frame, request_id): + model_conf, code = model + retResults = MODEL_CONFIG[code][3]([model_conf, frame, request_id])[0] + if type(retResults) is np.ndarray or len(retResults) == 0: + ret = retResults + if type(retResults) is np.ndarray: + ret = retResults.tolist() + else: + ret = retResults[2] + return code, ret + + @staticmethod + def obj_det(self, model_array, frame, task_status, cframe, tt, request_id): + push_obj = [] + if task_status[1] == 1: + dtection_result = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result.append(result) + for d in dtection_result: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) == 0: + task_status[1] = 0 + if task_status[1] == 0: + if cframe % 30 == 0: + dtection_result1 = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result1.append(result) + for d in dtection_result1: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) > 0: + task_status[1] = 1 + return push_obj + + @staticmethod + def checkPT(start_time, service_timeout, pull_process, push_process, hb_thread, push_ex_queue, pull_queue, + request_id): + 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 pull_process is not None and not pull_process.is_alive(): + while True: + if pull_queue.empty() or pull_queue.qsize() == 0: + break + pull_result = get_no_block_queue(pull_queue) + if pull_result is not None and pull_result[0] == 1: + raise ServiceException(pull_result[1], pull_result[2]) + logger.info("拉流进程异常停止, requestId: {}", request_id) + raise Exception("拉流进程异常停止!") + if hb_thread is not None and not hb_thread.is_alive(): + logger.info("心跳线程异常停止, requestId: {}", request_id) + raise Exception("心跳线程异常停止!") + if push_process is not None and not push_process.is_alive(): + while True: + if push_ex_queue.empty() or push_ex_queue.qsize() == 0: + break + push_result = get_no_block_queue(push_ex_queue) + if push_result is not None and push_result[0] == 1: + raise ServiceException(push_result[1], push_result[2]) + logger.info("推流进程异常停止, requestId: {}", request_id) + raise Exception("推流进程异常停止!") + + def run(self): + msg, context, analyse_type = self._msg, self._context, self._analyse_type + self.build_video_path(context, msg) + request_id = msg["request_id"] + base_dir, env = context["base_dir"], context["env"] + service_timeout = int(context["service"]["timeout"]) + ex = None + # 拉流进程、推流进程、心跳线程 + pull_process, push_process, hb_thread = None, None, None + + # 事件队列、拉流队列、心跳队列、反馈队列 + event_queue, pull_queue, hb_queue, fb_queue = self.event_queue, self._pull_queue, self._hb_queue, self._fb_queue + + # 推流队列、推流异常队列、图片队列 + push_queue, push_ex_queue, image_queue = self._push_queue, self._push_ex_queue, self._image_queue + try: + # 初始化日志 + init_log(base_dir, env) + # 打印启动日志 + logger.info("开始启动实时分析进程!requestId: {}", request_id) + + # 启动拉流进程(包含拉流线程, 图片上传线程,mqtt读取线程) + # 拉流进程初始化时间长, 先启动 + pull_process = self.start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, 25) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #7.0, + # 启动心跳线程 + hb_thread = self.start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + + + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #7.0, + # 加载算法模型 + model_array = get_model(msg, context, analyse_type) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #9.5 + # 启动推流进程 + push_process = self.start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + # 第一个参数: 模型是否初始化 0:未初始化 1:初始化 + # 第二个参数: 检测是否有问题 0: 没有问题, 1: 有问题 + task_status = [0, 0] + draw_config = {} + start_time = time() + # 识别2个线程性能最优 + with ThreadPoolExecutor(max_workers=2) as t: + # 可能使用模型组合, 模型组合最多3个模型, 1对3, 上面的2个线程对应6个线程 + with ThreadPoolExecutor(max_workers=6) as tt: + while True: + # 检查拉流进程是否正常, 心跳线程是否正常 + self.checkPT(start_time, service_timeout, pull_process, push_process, hb_thread, push_ex_queue, + pull_queue, request_id) + # 检查推流是否异常 + push_status = get_no_block_queue(push_ex_queue) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #9.5,11.2 + if push_status is not None and push_status[0] == 1: + raise ServiceException(push_status[1], push_status[2]) + # 获取停止指令 + event_result = get_no_block_queue(event_queue) + + if event_result: + cmdStr = event_result.get("command") + + # 接收到停止指令 + if "stop" == cmdStr: + logger.info("实时任务开始停止, requestId: {}", request_id) + pull_process.sendCommand({"command": 'stop'}) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + pull_result = get_no_block_queue(pull_queue) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + if pull_result is None: + sleep(1) + continue + # (4, (frame_list, frame_index_list, all_frames)) + if pull_result[0] == 4: + frame_list, frame_index_list, all_frames = pull_result[1] + if len(frame_list) > 0: + # 判断是否已经初始化 + if task_status[0] == 0: + task_status[0] = 1 + for i, model in enumerate(model_array): + model_conf, code = model + model_param = model_conf[1] + # (modeType, model_param, allowedList, names, rainbows) + MODEL_CONFIG[code][2](frame_list[0].shape[1], frame_list[0].shape[0], + model_conf) + if draw_config.get("font_config") is None: + draw_config["font_config"] = model_param['font_config'] + if draw_config.get(code) is None: + draw_config[code] = {} + draw_config[code]["allowedList"] = model_conf[2] + draw_config[code]["rainbows"] = model_conf[4] + draw_config[code]["label_arrays"] = model_param['label_arraylist'] + if "label_dict" in model_param: + draw_config[code]["label_dict"] = model_param['label_dict'] + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + # 多线程并发处理, 经过测试两个线程最优 + det_array = [] + for i, frame in enumerate(frame_list): + det_result = t.submit(self.obj_det, self, model_array, frame, task_status, + frame_index_list[i], tt, request_id) + det_array.append(det_result) + push_objs = [det.result() for det in det_array] + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + put_queue(push_queue, + (1, (frame_list, frame_index_list, all_frames, draw_config, push_objs)), + timeout=2, is_ex=True) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + del det_array, push_objs + del frame_list, frame_index_list, all_frames + elif pull_result[0] == 1: + # 拉流发生异常 + put_queue(push_queue, (2, 'stop_ex'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + raise ServiceException(pull_result[1], pull_result[2]) + elif pull_result[0] == 2: + put_queue(push_queue, (2, 'stop'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + break + else: + raise Exception("未知拉流状态异常!") + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, 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: + orFilePath, aiFilePath = context["orFilePath"], context["aiFilePath"] + base_dir, env = context["base_dir"], context["env"] + or_url, ai_url, exc = "", "", None + try: + # 如果拉流进程存在, 关闭拉流进程(拉流线程、图片上传线程) + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + logger.info("关闭拉流进程, requestId:{}", request_id) + pull_process.join(timeout=120) + logger.info("关闭拉流进程1, requestId:{}", request_id) + if exists(orFilePath) and exists(aiFilePath) and getsize(orFilePath) > 100: + or_url, ai_url = self.upload_video(base_dir, env, request_id, orFilePath, aiFilePath) + if or_url is None or ai_url is None: + logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + # 停止心跳线程 + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=1) + hb_thread.join(timeout=120) + if exists(orFilePath): + logger.info("开始删除原视频, orFilePath: {}, requestId: {}", orFilePath, request_id) + os.remove(orFilePath) + logger.info("删除原视频成功, orFilePath: {}, requestId: {}", orFilePath, request_id) + if exists(aiFilePath): + logger.info("开始删除AI视频, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + os.remove(aiFilePath) + logger.info("删除AI视频成功, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + # 如果有异常, 检查是否有原视频和AI视频,有则上传,响应失败 + if ex: + code, msg = ex + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + video_url=or_url, + ai_video_url=ai_url), timeout=2, is_ex=False) + else: + if or_url is None or len(or_url) == 0 or ai_url is None or len(ai_url) == 0: + raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1]) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess, + video_url=or_url, + ai_video_url=ai_url), timeout=2, is_ex=False) + + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, request_id) + exc = s.code, s.msg + except Exception: + logger.error("服务异常: {}, requestId: {},", format_exc(), request_id) + exc = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + logger.info("关闭拉流进程, requestId:{}", request_id) + pull_process.join(timeout=120) + logger.info("关闭拉流进程1, requestId:{}", request_id) + if exc: + code, msg = exc + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + video_url=or_url, + ai_video_url=ai_url), timeout=2, is_ex=False) + logger.info("清理队列, requestId:{}", request_id) + self.clear_queue() + logger.info("清理队列完成, requestId:{}", request_id) + + +class OfflineIntelligentRecognitionProcess(IntelligentRecognitionProcess): + __slots__ = () + + def upload_video(self,base_dir, env, request_id, aiFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + if self._storage_source==1: + minioSdk = MinioSdk(base_dir, env, request_id ) + upload_video_thread_ai = Common(minioSdk.put_object, aiFilePath, "%s/ai_online.mp4" % request_id) + else: + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + ai_url = upload_video_thread_ai.get_result() + return ai_url + + ''' + @staticmethod + def upload_video(base_dir, env, request_id, aiFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + ai_url = upload_video_thread_ai.get_result() + return ai_url + ''' + @staticmethod + def ai_normal_dtection(model, frame, request_id): + model_conf, code = model + retResults = MODEL_CONFIG[code][3]([model_conf, frame, request_id])[0] + if type(retResults) is np.ndarray or len(retResults) == 0: + ret = retResults + if type(retResults) is np.ndarray: + ret = retResults.tolist() + else: + ret = retResults[2] + return code, ret + + @staticmethod + def obj_det(self, model_array, frame, task_status, cframe, tt, request_id): + push_obj = [] + if task_status[1] == 1: + dtection_result = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result.append(result) + for d in dtection_result: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) == 0: + task_status[1] = 0 + if task_status[1] == 0: + if cframe % 30 == 0: + dtection_result1 = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result1.append(result) + for d in dtection_result1: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) > 0: + task_status[1] = 1 + return push_obj + + @staticmethod + def start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context): + pushProcess = OffPushStreamProcess(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + pushProcess.daemon = True + pushProcess.start() + return pushProcess + + @staticmethod + def start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, frame_num): + pullProcess = OfflinePullVideoStreamProcess(msg, context, fb_queue, pull_queue, image_queue, analyse_type, + frame_num) + pullProcess.daemon = True + pullProcess.start() + return pullProcess + + @staticmethod + def checkPT(service_timeout, start_time, pull_process, push_process, hb_thread, push_ex_queue, pull_queue, + request_id): + 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 pull_process is not None and not pull_process.is_alive(): + while True: + if pull_queue.empty() or pull_queue.qsize() == 0: + break + pull_result = get_no_block_queue(pull_queue) + if pull_result is not None and pull_result[0] == 1: + raise ServiceException(pull_result[1], pull_result[2]) + logger.info("拉流进程异常停止, requestId: {}", request_id) + raise Exception("拉流进程异常停止!") + if hb_thread is not None and not hb_thread.is_alive(): + logger.info("心跳线程异常停止, requestId: {}", request_id) + raise Exception("心跳线程异常停止!") + if push_process is not None and not push_process.is_alive(): + while True: + if push_ex_queue.empty() or push_ex_queue.qsize() == 0: + break + push_result = get_no_block_queue(push_ex_queue) + if push_result is not None and push_result[0] == 1: + raise ServiceException(push_result[1], push_result[2]) + logger.info("推流进程异常停止, requestId: {}", request_id) + raise Exception("推流进程异常停止!") + + def run(self): + msg, context, analyse_type, ex = self._msg, self._context, self._analyse_type, None + self.build_video_path(context, msg, is_build_or=False) + request_id, base_dir, env = msg["request_id"], context["base_dir"], context["env"] + # 拉流进程、推流进程、心跳线程 + pull_process, push_process, hb_thread = None, None, None + service_timeout = int(context["service"]["timeout"]) + # 事件队列、拉流队列、心跳队列、反馈队列 + event_queue, pull_queue, hb_queue, fb_queue = self.event_queue, self._pull_queue, self._hb_queue, self._fb_queue + # 推流队列、推流异常队列、图片队列 + push_queue, push_ex_queue, image_queue = self._push_queue, self._push_ex_queue, self._image_queue + try: + # 初始化日志 + init_log(base_dir, env) + # 打印启动日志 + logger.info("开始启动离线分析进程!requestId: {}", request_id) + # 启动拉流进程(包含拉流线程, 图片上传线程) + # 拉流进程初始化时间长, 先启动 + pull_process = self.start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, 25) + # 启动心跳线程 + hb_thread = self.start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + # 加载算法模型 + model_array = get_model(msg, context, analyse_type) + # 启动推流进程 + push_process = self.start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + # 第一个参数: 模型是否初始化 0:未初始化 1:初始化 + # 第二个参数: 检测是否有问题 0: 没有问题, 1: 有问题 + task_status = [0, 0] + draw_config = {} + start_time = time() + # 识别2个线程性能最优 + with ThreadPoolExecutor(max_workers=2) as t: + # 可能使用模型组合, 模型组合最多3个模型, 1对3, 上面的2个线程对应6个线程 + with ThreadPoolExecutor(max_workers=6) as tt: + while True: + # 检查拉流进程是否正常, 心跳线程是否正常 + self.checkPT(service_timeout, start_time, pull_process, push_process, hb_thread, push_ex_queue, + pull_queue, request_id) + # 检查推流是否异常 + push_status = get_no_block_queue(push_ex_queue) + if push_status is not None and push_status[0] == 1: + raise ServiceException(push_status[1], push_status[2]) + # 获取停止指令 + event_result = get_no_block_queue(event_queue) + if event_result: + cmdStr = event_result.get("command") + # 接收到停止指令 + if "stop" == cmdStr: + logger.info("离线任务开始停止, requestId: {}", request_id) + pull_process.sendCommand({"command": 'stop'}) + pull_result = get_no_block_queue(pull_queue) + if pull_result is None: + sleep(1) + continue + # (4, (frame_list, frame_index_list, all_frames)) + if pull_result[0] == 4: + frame_list, frame_index_list, all_frames = pull_result[1] + if len(frame_list) > 0: + # 判断是否已经初始化 + if task_status[0] == 0: + task_status[0] = 1 + for i, model in enumerate(model_array): + model_conf, code = model + model_param = model_conf[1] + # (modeType, model_param, allowedList, names, rainbows) + MODEL_CONFIG[code][2](frame_list[0].shape[1], frame_list[0].shape[0], + model_conf) + if draw_config.get("font_config") is None: + draw_config["font_config"] = model_param['font_config'] + if draw_config.get(code) is None: + draw_config[code] = {} + draw_config[code]["allowedList"] = model_conf[2] + draw_config[code]["rainbows"] = model_conf[4] + draw_config[code]["label_arrays"] = model_param['label_arraylist'] + if "label_dict" in model_param: + draw_config[code]["label_dict"] = model_param['label_dict'] + det_array = [] + for i, frame in enumerate(frame_list): + det_result = t.submit(self.obj_det, self, model_array, frame, task_status, + frame_index_list[i], tt, request_id) + det_array.append(det_result) + push_objs = [det.result() for det in det_array] + put_queue(push_queue, + (1, (frame_list, frame_index_list, all_frames, draw_config, push_objs)), + timeout=2, is_ex=True) + del det_array, push_objs + del frame_list, frame_index_list, all_frames + elif pull_result[0] == 1: + put_queue(push_queue, (2, 'stop_ex'), timeout=1, is_ex=True) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + raise ServiceException(pull_result[1], pull_result[2]) + elif pull_result[0] == 2: + logger.info("离线任务开始停止, requestId: {}", request_id) + put_queue(push_queue, (2, 'stop'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + break + else: + raise Exception("未知拉流状态异常!") + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, 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: + base_dir, env, aiFilePath = context["base_dir"], context["env"], context["aiFilePath"] + ai_url, exc = "", None + try: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + push_process.join(timeout=120) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(timeout=120) + if exists(aiFilePath) and getsize(aiFilePath) > 100: + ai_url = self.upload_video(base_dir, env, request_id, aiFilePath) + if ai_url is None: + logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + # 停止心跳线程 + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=1) + hb_thread.join(timeout=120) + if exists(aiFilePath): + logger.info("开始删除AI视频, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + os.remove(aiFilePath) + logger.info("删除AI视频成功, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + # 如果有异常, 检查是否有原视频和AI视频,有则上传,响应失败 + if ex: + code, msg = ex + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + ai_video_url=ai_url), timeout=2, is_ex=False) + else: + if ai_url is None or len(ai_url) == 0: + raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1]) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess, + ai_video_url=ai_url), timeout=2, is_ex=False) + + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, request_id) + exc = s.code, s.msg + except Exception: + logger.error("服务异常: {}, requestId: {},", format_exc(), request_id) + exc = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + push_process.join(timeout=120) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(timeout=120) + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=1) + hb_thread.join(timeout=120) + if exc: + code, msg = exc + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + ai_video_url=ai_url), timeout=2, is_ex=False) + self.clear_queue() + + +''' +图片识别 +''' + + +class PhotosIntelligentRecognitionProcess(Process): + __slots__ = ("_fb_queue", "_msg", "_analyse_type", "_context", "_image_queue") + + def __init__(self, *args): + super().__init__() + self._fb_queue, self._msg, self._analyse_type, self._context = args + self._image_queue = Queue() + put_queue(self._fb_queue, message_feedback(self._msg["request_id"], AnalysisStatus.WAITING.value, + self._analyse_type, progress=init_progess), timeout=2, is_ex=True) + self.build_logo(self._msg, self._context) + self._storage_source = self._context['service']['storage_source'] + + @staticmethod + def build_logo(msg, context): + logo = None + if context["video"]["video_add_water"]: + logo = msg.get("logo_url") + if logo is not None and len(logo) > 0: + logo = url2Array(logo, enable_ex=False) + if logo is None: + logo = cv2.imread(join(context['base_dir'], "image/logo.png"), -1) + context['logo'] = logo + + def epidemic_prevention(self, imageUrl, model, orc, request_id): + try: + # modeType, allowedList, new_device, model, par, img_type + model_conf, code = model + modeType, allowedList, new_device, model, par, img_type = model_conf + image = url2Array(imageUrl) + param = [image, new_device, model, par, img_type, request_id] + dataBack = MODEL_CONFIG[code][3](param) + if img_type == 'plate': + carCode = '' + if dataBack is None or dataBack.get("plateImage") is None or len(dataBack.get("plateImage")) == 0: + result = orc.license_plate_recognition(image, request_id) + score = '' + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + logger.error("车牌识别为空: {}", result) + carCode = '' + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + else: + result = orc.license_plate_recognition(dataBack.get("plateImage")[0], request_id) + score = dataBack.get("plateImage")[1] + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + result = orc.license_plate_recognition(image, request_id) + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + logger.error("车牌识别为空: {}", result) + carCode = '' + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + if len(carCode) > 0: + plate_result = {'type': str(3), 'modelCode': code, 'carUrl': imageUrl, + 'carCode': carCode, + 'score': score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(3), + plate_result), timeout=2, is_ex=True) + if img_type == 'code': + if dataBack is None or dataBack.get("type") is None: + return + # 行程码 + if dataBack.get("type") == 1 and 1 in allowedList: + # 手机号 + if dataBack.get("phoneNumberImage") is None or len(dataBack.get("phoneNumberImage")) == 0: + phoneNumberRecognition = '' + phone_score = '' + else: + phone = orc.universal_text_recognition(dataBack.get("phoneNumberImage")[0], request_id) + phone_score = dataBack.get("phoneNumberImage")[1] + if phone is None or phone.get("words_result") is None or len(phone.get("words_result")) == 0: + logger.error("手机号识别为空: {}", phone) + phoneNumberRecognition = '' + else: + phoneNumberRecognition = phone.get("words_result") + if dataBack.get("cityImage") is None or len(dataBack.get("cityImage")) == 0: + cityRecognition = '' + city_score = '' + else: + city = orc.universal_text_recognition(dataBack.get("cityImage")[0], request_id) + city_score = dataBack.get("cityImage")[1] + if city is None or city.get("words_result") is None or len(city.get("words_result")) == 0: + logger.error("城市识别为空: {}", city) + cityRecognition = '' + else: + cityRecognition = city.get("words_result") + if len(phoneNumberRecognition) > 0 or len(cityRecognition) > 0: + trip_result = {'type': str(1), + 'modelCode': code, + 'imageUrl': imageUrl, + 'phoneNumberRecognition': phoneNumberRecognition, + 'phone_sorce': phone_score, + 'cityRecognition': cityRecognition, + 'city_score': city_score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(1), + trip_result), timeout=2, is_ex=True) + if dataBack.get("type") == 2 and 2 in allowedList: + if dataBack.get("nameImage") is None or len(dataBack.get("nameImage")) == 0: + nameRecognition = '' + name_score = '' + else: + name = orc.universal_text_recognition(dataBack.get("nameImage")[0], request_id) + name_score = dataBack.get("nameImage")[1] + if name is None or name.get("words_result") is None or len(name.get("words_result")) == 0: + logger.error("名字识别为空: {}", name) + nameRecognition = '' + else: + nameRecognition = name.get("words_result") + + if dataBack.get("phoneNumberImage") is None or len(dataBack.get("phoneNumberImage")) == 0: + phoneNumberRecognition = '' + phone_score = '' + else: + phone = orc.universal_text_recognition(dataBack.get("phoneNumberImage")[0], request_id) + phone_score = dataBack.get("phoneNumberImage")[1] + if phone is None or phone.get("words_result") is None or len(phone.get("words_result")) == 0: + logger.error("手机号识别为空: {}", phone) + phoneNumberRecognition = '' + else: + phoneNumberRecognition = phone.get("words_result") + if dataBack.get("hsImage") is None or len(dataBack.get("hsImage")) == 0: + hsRecognition = '' + hs_score = '' + else: + hs = orc.universal_text_recognition(dataBack.get("hsImage")[0], request_id) + hs_score = dataBack.get("hsImage")[1] + if hs is None or hs.get("words_result") is None or len(hs.get("words_result")) == 0: + logger.error("核酸识别为空: {}", hs) + hsRecognition = '' + else: + hsRecognition = hs.get("words_result") + if len(nameRecognition) > 0 or len(phoneNumberRecognition) > 0 or len(hsRecognition) > 0: + healthy_result = {'type': str(2), + 'modelCode': code, + 'imageUrl': imageUrl, + 'color': dataBack.get("color"), + 'nameRecognition': nameRecognition, + 'name_score': name_score, + 'phoneNumberRecognition': phoneNumberRecognition, + 'phone_score': phone_score, + 'hsRecognition': hsRecognition, + 'hs_score': hs_score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(2), + healthy_result), timeout=2, is_ex=True) + except ServiceException as s: + raise s + except Exception as e: + logger.error("模型分析异常: {}, requestId: {}", format_exc(), request_id) + raise e + + ''' + # 防疫模型 + ''' + + def epidemicPrevention(self, imageUrls, model, base_dir, env, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + orc = OcrBaiduSdk(base_dir, env) + obj_list = [] + for imageUrl in imageUrls: + obj = t.submit(self.epidemic_prevention, imageUrl, model, orc, request_id) + obj_list.append(obj) + for r in obj_list: + r.result(60) + + def image_recognition(self, imageUrl, mod, image_queue, logo, request_id): + try: + model_conf, code = mod + model_param = model_conf[1] + image = url2Array(imageUrl) + MODEL_CONFIG[code][2](image.shape[1], image.shape[0], model_conf) + p_result = MODEL_CONFIG[code][3]([model_conf, image, request_id])[0] + #print(' line872:p_result[2]:',p_result[2] ) + if p_result is None or len(p_result) < 3 or p_result[2] is None or len(p_result[2]) == 0: + return + if logo: + image = add_water_pic(image, logo, request_id) + # (modeType, model_param, allowedList, names, rainbows) + allowedList = model_conf[2] + label_arraylist = model_param['label_arraylist'] + font_config = model_param['font_config'] + rainbows = model_conf[4] + det_xywh = {code: {}} + ai_result_list = p_result[2] + for ai_result in ai_result_list: + box, score, cls = xywh2xyxy2(ai_result) + # 如果检测目标在识别任务中,继续处理 + if cls in allowedList: + label_array = label_arraylist[cls] + color = rainbows[cls] + cd = det_xywh[code].get(cls) + 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]) + #print('ai_result_list:{},allowlist:{}'.format(ai_result_list,allowedList )) + if len(det_xywh) > 0: + put_queue(image_queue, (1, (det_xywh, imageUrl, image, font_config, "")), timeout=2, is_ex=False) + except ServiceException as s: + raise s + except Exception as e: + logger.error("模型分析异常: {}, requestId: {}", format_exc(), self._msg.get("request_id")) + raise e + + def publicIdentification(self, imageUrls, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + obj_list = [] + for imageUrl in imageUrls: + obj = t.submit(self.image_recognition, imageUrl, mod, image_queue, logo, request_id) + obj_list.append(obj) + for r in obj_list: + r.result(60) + + ''' + 1. imageUrls: 图片url数组,多张图片 + 2. mod: 模型对象 + 3. image_queue: 图片队列 + ''' + + def baiduRecognition(self, imageUrls, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + thread_result = [] + for imageUrl in imageUrls: + obj = t.submit(self.baidu_recognition, imageUrl, mod, image_queue, logo, request_id) + thread_result.append(obj) + for r in thread_result: + r.result(60) + + def baidu_recognition(self, imageUrl, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + try: + # modeType, aipImageClassifyClient, aipBodyAnalysisClient, allowedList, rainbows, + # vehicle_names, person_names, requestId + model_conf, code = mod + allowedList = model_conf[3] + rainbows = model_conf[4] + # 图片转数组 + img = url2Array(imageUrl) + vehicle_label_arrays, person_label_arrays, font_config = MODEL_CONFIG[code][2](img.shape[1], + img.shape[0], + model_conf) + obj_list = [] + for target in allowedList: + parm = [target, imageUrl, model_conf[1], model_conf[2], request_id] + reuslt = t.submit(self.baidu_method, code, parm, img, image_queue, vehicle_label_arrays, + person_label_arrays, font_config, rainbows, logo) + obj_list.append(reuslt) + for r in obj_list: + r.result(60) + except ServiceException as s: + raise s + except Exception as e: + logger.error("百度AI分析异常: {}, requestId: {}", format_exc(), request_id) + raise e + + @staticmethod + def baidu_method(code, parm, img, image_queue, vehicle_label_arrays, person_label_arrays, font_config, + rainbows, logo): + # [target, url, aipImageClassifyClient, aipBodyAnalysisClient, requestId] + request_id = parm[4] + target = parm[0] + image_url = parm[1] + result = MODEL_CONFIG[code][3](parm) + if target == BaiduModelTarget.VEHICLE_DETECTION.value[1] and result is not None: + vehicleInfo = result.get("vehicle_info") + if vehicleInfo is not None and len(vehicleInfo) > 0: + det_xywh = {code: {}} + copy_frame = img.copy() + for i, info in enumerate(vehicleInfo): + value = VehicleEnumVALUE.get(info.get("type")) + target_num = value.value[2] + label_array = vehicle_label_arrays[target_num] + color = rainbows[target_num] + if value is None: + logger.error("车辆识别出现未支持的目标类型!type:{}, requestId:{}", info.get("type"), request_id) + return + left_top = (int(info.get("location").get("left")), int(info.get("location").get("top"))) + right_top = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top"))) + right_bottom = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + left_bottom = (int(info.get("location").get("left")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + box = [left_top, right_top, right_bottom, left_bottom] + score = float("%.2f" % info.get("probability")) + if logo: + copy_frame = add_water_pic(copy_frame, logo, request_id) + if det_xywh[code].get(target) is None: + det_xywh[code][target] = [[target, box, score, label_array, color]] + else: + det_xywh[code][target].append([target, box, score, label_array, color]) + info["id"] = str(i) + if len(det_xywh[code]) > 0: + result["type"] = str(target) + result["modelCode"] = code + put_queue(image_queue, (1, (det_xywh, image_url, copy_frame, font_config, result)), timeout=2, + is_ex=True) + # 人体识别 + if target == BaiduModelTarget.HUMAN_DETECTION.value[1] and result is not None: + personInfo = result.get("person_info") + personNum = result.get("person_num") + if personNum is not None and personNum > 0 and personInfo is not None and len(personInfo) > 0: + det_xywh = {code: {}} + copy_frame = img.copy() + for i, info in enumerate(personInfo): + left_top = (int(info.get("location").get("left")), int(info.get("location").get("top"))) + right_top = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top"))) + right_bottom = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + left_bottom = (int(info.get("location").get("left")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + box = [left_top, right_top, right_bottom, left_bottom] + score = float("%.2f" % info.get("location").get("score")) + label_array = person_label_arrays[0] + color = rainbows[0] + if logo: + copy_frame = add_water_pic(copy_frame, logo, request_id) + if det_xywh[code].get(target) is None: + det_xywh[code][target] = [[target, box, score, label_array, color]] + else: + det_xywh[code][target].append([target, box, score, label_array, color]) + info["id"] = str(i) + if len(det_xywh[code]) > 0: + result["type"] = str(target) + result["modelCode"] = code + put_queue(image_queue, (1, (det_xywh, image_url, copy_frame, font_config, result)), timeout=2) + # 人流量 + if target == BaiduModelTarget.PEOPLE_COUNTING.value[1] and result is not None: + base64Image = result.get("image") + if base64Image is not None and len(base64Image) > 0: + baiduImage = base64.b64decode(base64Image) + result["type"] = str(target) + result["modelCode"] = code + del result["image"] + put_queue(image_queue, (1, (None, image_url, baiduImage, None, result)), timeout=2) + + @staticmethod + def start_File_upload(fb_queue, context, msg, image_queue, analyse_type): + image_thread = ImageTypeImageFileUpload(fb_queue, context, msg, image_queue, analyse_type) + image_thread.setDaemon(True) + image_thread.start() + return image_thread + + def run(self): + fb_queue, msg, analyse_type, context = self._fb_queue, self._msg, self._analyse_type, self._context + request_id, logo, image_queue = msg["request_id"], context['logo'], self._image_queue + base_dir, env = context["base_dir"], context["env"] + imageUrls = msg["image_urls"] + image_thread = None + with ThreadPoolExecutor(max_workers=2) as t: + try: + init_log(base_dir, env) + logger.info("开始启动图片识别进程, requestId: {}", request_id) + model_array = get_model(msg, context, analyse_type) + image_thread = self.start_File_upload(fb_queue, context, msg, image_queue, analyse_type) + task_list = [] + for model in model_array: + # 百度模型逻辑 + if model[1] == ModelType.BAIDU_MODEL.value[1]: + result = t.submit(self.baiduRecognition, imageUrls, model, image_queue, logo, request_id) + task_list.append(result) + # 防疫模型 + elif model[1] == ModelType.EPIDEMIC_PREVENTION_MODEL.value[1]: + result = t.submit(self.epidemicPrevention, imageUrls, model, base_dir, env, request_id) + task_list.append(result) + # 车牌模型 + elif model[1] == ModelType.PLATE_MODEL.value[1]: + result = t.submit(self.epidemicPrevention, imageUrls, model, base_dir, env, request_id) + task_list.append(result) + else: + result = t.submit(self.publicIdentification, imageUrls, model, image_queue, logo, request_id) + task_list.append(result) + for r in task_list: + r.result(60) + if image_thread and not image_thread.is_alive(): + raise Exception("图片识别图片上传线程异常停止!!!") + if image_thread and image_thread.is_alive(): + put_queue(image_queue, (2, 'stop'), timeout=2) + image_thread.join(120) + logger.info("图片进程任务完成,requestId:{}", request_id) + put_queue(fb_queue, message_feedback(request_id, + AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess), timeout=2, is_ex=True) + except ServiceException as s: + logger.error("图片分析异常,异常编号:{}, 异常描述:{}, requestId:{}", s.code, s.msg, request_id) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + s.code, + s.msg), timeout=2) + except Exception: + logger.error("图片分析异常: {}, requestId:{}", format_exc(), request_id) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]), timeout=2) + finally: + if image_thread and image_thread.is_alive(): + clear_queue(image_queue) + put_queue(image_queue, (2, 'stop'), timeout=2) + image_thread.join(120) + clear_queue(image_queue) + + +class ScreenRecordingProcess(Process): + __slots__ = ('_fb_queue', '_context', '_msg', '_analysisType', '_event_queue', '_hb_queue', '_analysisType') + + def __init__(self, *args): + super().__init__() + # 传参 + self._fb_queue, self._context, self._msg, self._analysisType = args + self._event_queue, self._hb_queue, self._pull_queue = Queue(), Queue(), Queue(10) + put_queue(self._fb_queue, + recording_feedback(self._msg["request_id"], RecordingStatus.RECORDING_WAITING.value[0]), + timeout=1, is_ex=True) + self._storage_source = self._context['service']['storage_source'] + def sendEvent(self, result): + put_queue(self._event_queue, result, timeout=2, is_ex=True) + + @staticmethod + def start_pull_stream_thread(msg, context, pull_queue, hb_queue, fb_queue, frame_num): + pullThread = RecordingPullStreamThread(msg, context, pull_queue, hb_queue, fb_queue, frame_num) + pullThread.setDaemon(True) + pullThread.start() + return pullThread + + @staticmethod + def start_hb_thread(fb_queue, hb_queue, request_id): + hb = RecordingHeartbeat(fb_queue, hb_queue, request_id) + hb.setDaemon(True) + hb.start() + return hb + + @staticmethod + def check(start_time, service_timeout, pull_thread, hb_thread, request_id): + 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 pull_thread and not pull_thread.is_alive(): + logger.info("录屏拉流线程停止异常, requestId: {}", request_id) + raise Exception("录屏拉流线程异常停止") + if hb_thread and not hb_thread.is_alive(): + logger.info("录屏心跳线程异常停止, requestId: {}", request_id) + raise Exception("录屏心跳线程异常停止") + + def run(self): + msg, context = self._msg, self._context + request_id, push_url = msg['request_id'], msg.get('push_url') + pull_queue, fb_queue, hb_queue, event_queue = self._pull_queue, self._fb_queue, self._hb_queue, \ + self._event_queue + base_dir, env, service_timeout = context['base_dir'], context['env'], int(context["service"]["timeout"]) + pre_path, end_path = '%s/%s%s' % (base_dir, context["video"]["file_path"], now_date_to_str(YMDHMSF)), \ + '%s%s' % (request_id, ".mp4") + orFilePath = '%s%s%s' % (pre_path, "_on_or_", end_path) + pull_thread, hb_thread = None, None + or_write_status, p_push_status = [0, 0], [0, 0] + or_video_file, push_p = None, None + ex = None + try: + # 初始化日志 + init_log(base_dir, env) + # 启动拉流线程 + pull_thread = self.start_pull_stream_thread(msg, context, pull_queue, hb_queue, fb_queue, 25) + hb_thread = self.start_hb_thread(fb_queue, hb_queue, request_id) + start_time = time() + with ThreadPoolExecutor(max_workers=2) as t: + while True: + # 检查拉流线程和心跳线程 + self.check(start_time, service_timeout, pull_thread, hb_thread, request_id) + # 判断是否需要停止录屏 + event_result = get_no_block_queue(event_queue) + if event_result is not None: + cmdStr = event_result.get("command") + # 接收到停止指令 + if 'stop' == cmdStr: + logger.info("录屏任务开始停止, requestId: {}", request_id) + pull_thread.sendEvent({"command": "stop"}) + pull_result = get_no_block_queue(pull_queue) + if pull_result is None: + sleep(1) + continue + if pull_result[0] == 1: + close_all_p(push_p, or_video_file, None, request_id) + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(180) + raise ServiceException(pull_result[1], pull_result[2]) + elif pull_result[0] == 2: + close_all_p(push_p, or_video_file, None, request_id) + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(180) + break + elif pull_result[0] == 4: + frame_list, frame_index_list, all_frames = pull_result[1] + if len(frame_list) > 0: + 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, {"progress": task_process}, timeout=1) + write_or_video_result = t.submit(write_or_video, frame, orFilePath, or_video_file, + or_write_status, request_id) + if push_url is not None and len(push_url) > 0: + push_p_result = t.submit(push_video_stream, frame, push_p, push_url, p_push_status, + request_id) + push_p = push_p_result.result() + or_video_file = write_or_video_result.result() + else: + raise Exception("未知拉流状态异常!") + logger.info("录屏线程任务完成,requestId:{}", self._msg.get("request_id")) + except ServiceException as s: + logger.error("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, self._msg.get("request_id")) + ex = s.code, s.msg + except Exception: + logger.error("服务异常: {}, requestId: {},", format_exc(), self._msg.get("request_id")) + ex = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + or_url = "" + exn = None + try: + # 关闭推流管道, 原视频写流客户端 + close_all_p(push_p, or_video_file, None, request_id) + # 关闭拉流线程 + if pull_thread and pull_thread.is_alive(): + pull_thread.sendEvent({"command": "stop_ex"}) + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(120) + # 判断是否需要上传视频 + if exists(orFilePath) and getsize(orFilePath) > 100: + or_url = self.upload_video(base_dir, env, request_id, orFilePath) + if or_url is None or len(or_url) == 0: + logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + # 停止心跳线程 + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=10, is_ex=False) + hb_thread.join(timeout=120) + if exists(orFilePath): + logger.info("开始删除原视频, orFilePath: {}, requestId: {}", orFilePath, request_id) + os.remove(orFilePath) + logger.info("删除原视频成功, orFilePath: {}, requestId: {}", orFilePath, request_id) + # 如果有异常, 检查是否有原视频和AI视频,有则上传,响应失败 + if ex: + code, msg = ex + put_queue(fb_queue, recording_feedback(request_id, RecordingStatus.RECORDING_FAILED.value[0], + error_code=code, + error_msg=msg, + video_url=or_url), timeout=10, is_ex=False) + else: + if or_url is None or len(or_url) == 0: + raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1]) + put_queue(fb_queue, recording_feedback(request_id, RecordingStatus.RECORDING_SUCCESS.value[0], + progress=success_progess, + video_url=or_url), timeout=10, is_ex=False) + except ServiceException as s: + exn = s.code, s.msg + except Exception: + logger.error("异常:{}, requestId: {}", format_exc(), request_id) + exn = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + if pull_thread and pull_thread.is_alive(): + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(120) + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=10, is_ex=False) + hb_thread.join(timeout=120) + self.clear_queue_end() + if exn: + code, msg = exn + put_queue(fb_queue, recording_feedback(request_id, RecordingStatus.RECORDING_FAILED.value[0], + error_code=code, + error_msg=msg, + video_url=or_url), timeout=10, is_ex=False) + + def clear_queue_end(self): + clear_queue(self._event_queue) + clear_queue(self._hb_queue) + clear_queue(self._pull_queue) + + + + + def upload_video(self,base_dir, env, request_id, orFilePath): + if self._storage_source==1: + minioSdk = MinioSdk(base_dir, env, request_id ) + upload_video_thread_ai = Common(minioSdk.put_object, aiFilePath, "%s/ai_online.mp4" % request_id) + else: + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + or_url = upload_video_thread_ai.get_result() + return or_url + ''' + @staticmethod + def upload_video(base_dir, env, request_id, orFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, orFilePath, "or_online_%s" % request_id) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + or_url = upload_video_thread_ai.get_result() + return or_url + ''' + +""" +"models": [{ + "code": "模型编号", + "categories":[{ + "id": "模型id", + "config": { + "k1": "v1", + "k2": "v2" + } + }] +}] +""" + + +def get_model(msg, context, analyse_type): + # 初始变量 + request_id, base_dir, gpu_name, env = msg["request_id"], context["base_dir"], context["gpu_name"], context["env"] + models, model_num_limit = msg["models"], context["service"]["model"]['limit'] + try: + # 实时、离线元组 + analyse_type_tuple = (AnalysisType.ONLINE.value, AnalysisType.OFFLINE.value) + # (实时、离线)检查模型组合, 目前只支持3个模型组合 + if analyse_type in analyse_type_tuple: + if len(models) > model_num_limit: + raise ServiceException(ExceptionType.MODEL_GROUP_LIMIT_EXCEPTION.value[0], + ExceptionType.MODEL_GROUP_LIMIT_EXCEPTION.value[1]) + modelArray, codeArray = [], set() + for model in models: + # 模型编码 + code = model["code"] + # 检验code是否重复 + if code in codeArray: + raise ServiceException(ExceptionType.MODEL_DUPLICATE_EXCEPTION.value[0], + ExceptionType.MODEL_DUPLICATE_EXCEPTION.value[1]) + codeArray.add(code) + # 检测目标数组 + needed_objectsIndex = list(set([int(category["id"]) for category in model["categories"]])) + logger.info("模型编号: {}, 检查目标: {}, requestId: {}", code, needed_objectsIndex, request_id) + model_method = MODEL_CONFIG.get(code) + if model_method is None: + logger.error("未匹配到对应的模型, requestId:{}", request_id) + raise ServiceException(ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[0], + ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[1]) + # 检查cpu资源、gpu资源 + check_cpu(base_dir, request_id) + gpu_ids = check_gpu_resource(request_id) + # 如果实时识别、离线识别 + if analyse_type in analyse_type_tuple: + if model["is_video"] == "1": + mod = model_method[0](gpu_ids[0], needed_objectsIndex, request_id, gpu_name, base_dir, env) + modelArray.append((mod.model_conf, code)) + else: + raise ServiceException(ExceptionType.MODEL_NOT_SUPPORT_VIDEO_EXCEPTION.value[0], + ExceptionType.MODEL_NOT_SUPPORT_VIDEO_EXCEPTION.value[1], + model_method[1].value[2]) + # 如果是图片识别 + if analyse_type == AnalysisType.IMAGE.value: + if model["is_image"] == "1": + mod = model_method[0](gpu_ids[0], needed_objectsIndex, request_id, gpu_name, base_dir, env) + modelArray.append((mod.model_conf, code)) + else: + raise ServiceException(ExceptionType.MODEL_NOT_SUPPORT_IMAGE_EXCEPTION.value[0], + ExceptionType.MODEL_NOT_SUPPORT_IMAGE_EXCEPTION.value[1], + model_method[1].value[2]) + if len(modelArray) == 0: + raise ServiceException(ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[0], + ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[1]) + return modelArray + except ServiceException as s: + raise s + except Exception: + logger.error("模型配置处理异常: {}, request_id: {}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) diff --git a/concurrency/IntelligentRecognitionProcess_withMiniSdk.py b/concurrency/IntelligentRecognitionProcess_withMiniSdk.py new file mode 100644 index 0000000..3e56ce0 --- /dev/null +++ b/concurrency/IntelligentRecognitionProcess_withMiniSdk.py @@ -0,0 +1,1444 @@ +# -*- coding: utf-8 -*- +import base64 +import os +from concurrent.futures import ThreadPoolExecutor +from os.path import join, exists, getsize +from time import time, sleep +from traceback import format_exc + +import cv2 + +from multiprocessing import Process, Queue + +import numpy as np +from loguru import logger + +from common.Constant import init_progess, success_progess +from concurrency.FileUploadThread import ImageTypeImageFileUpload +from concurrency.HeartbeatThread import Heartbeat + +from concurrency.PullVideoStreamProcess import OnlinePullVideoStreamProcess, OfflinePullVideoStreamProcess +from concurrency.PushVideoStreamProcess import OnPushStreamProcess, OffPushStreamProcess + +from util.GPUtils import check_gpu_resource +from util.LogUtils import init_log +from concurrency.CommonThread import Common +from concurrency.PullStreamThread import RecordingPullStreamThread +from concurrency.RecordingHeartbeatThread import RecordingHeartbeat +from enums.AnalysisStatusEnum import AnalysisStatus +from enums.AnalysisTypeEnum import AnalysisType +from enums.ExceptionEnum import ExceptionType +from enums.ModelTypeEnum import ModelType +from enums.RecordingStatusEnum import RecordingStatus +from util.AliyunSdk import ThAliyunVodSdk +from util.CpuUtils import check_cpu +from util.Cv2Utils import write_or_video, push_video_stream, close_all_p +from entity.FeedBack import message_feedback, recording_feedback +from exception.CustomerException import ServiceException +from util.ImageUtils import url2Array, add_water_pic +from util.ModelUtils import MODEL_CONFIG +from util.OcrBaiduSdk import OcrBaiduSdk + +from enums.BaiduSdkEnum import VehicleEnumVALUE +from enums.ModelTypeEnum import BaiduModelTarget +from util.PlotsUtils import xywh2xyxy2 +from util.QueUtil import put_queue, get_no_block_queue, clear_queue +from util.TimeUtils import now_date_to_str, YMDHMSF +from util.CpuUtils import print_cpu_status +import inspect +class IntelligentRecognitionProcess(Process): + __slots__ = ('_fb_queue', '_msg', '_analyse_type', '_context', 'event_queue', '_pull_queue', '_hb_queue', + "_image_queue", "_push_queue", '_push_ex_queue') + + def __init__(self, *args): + super().__init__() + # 入参 + self._fb_queue, self._msg, self._analyse_type, self._context = args + # 初始化参数 + self.event_queue, self._pull_queue, self._hb_queue, self._image_queue, self._push_queue, self._push_ex_queue = \ + Queue(), Queue(10), Queue(), Queue(), Queue(), Queue() + + # 发送waitting消息 + put_queue(self._fb_queue, message_feedback(self._msg["request_id"], AnalysisStatus.WAITING.value, + self._analyse_type, progress=init_progess), timeout=2, is_ex=True) + self._storage_source = self._context['service']['storage_source'] + + def sendEvent(self, eBody): + put_queue(self.event_queue, eBody, timeout=2, is_ex=True) + + def clear_queue(self): + clear_queue(self.event_queue) + clear_queue(self._pull_queue) + clear_queue(self._hb_queue) + clear_queue(self._image_queue) + clear_queue(self._push_queue) + clear_queue(self._push_ex_queue) + + @staticmethod + def build_video_path(context, msg, is_build_or=True): + random_time = now_date_to_str(YMDHMSF) + pre_path = '%s/%s%s' % (context["base_dir"], context["video"]["file_path"], random_time) + end_path = '%s%s' % (msg["request_id"], ".mp4") + if is_build_or: + context["orFilePath"] = '%s%s%s' % (pre_path, "_on_or_", end_path) + context["aiFilePath"] = '%s%s%s' % (pre_path, "_on_ai_", end_path) + + @staticmethod + def start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context): + hb_thread = Heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + hb_thread.setDaemon(True) + hb_thread.start() + return hb_thread + + + + + +class OnlineIntelligentRecognitionProcess(IntelligentRecognitionProcess): + __slots__ = () + + @staticmethod + def start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context): + pushProcess = OnPushStreamProcess(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + pushProcess.daemon = True + pushProcess.start() + return pushProcess + + @staticmethod + def start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, frame_num): + pullProcess = OnlinePullVideoStreamProcess(msg, context, fb_queue, pull_queue, image_queue, analyse_type, + frame_num) + pullProcess.daemon = True + pullProcess.start() + return pullProcess + + + def upload_video(self,base_dir, env, request_id, orFilePath, aiFilePath): + if self._storage_source==1: + minioSdk = MinioSdk(base_dir, env, request_id ) + upload_video_thread_or = Common(minioSdk.put_object, orFilePath, "%s/or_online.mp4" % request_id) + upload_video_thread_ai = Common(minioSdk.put_object, aiFilePath, "%s/ai_online.mp4" % request_id) + else: + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_or = Common(aliyunVodSdk.get_play_url, orFilePath, "or_online_%s" % request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + + + upload_video_thread_or.setDaemon(True) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_or.start() + upload_video_thread_ai.start() + or_url = upload_video_thread_or.get_result() + ai_url = upload_video_thread_ai.get_result() + return or_url, ai_url + ''' + @staticmethod + def upload_video(base_dir, env, request_id, orFilePath, aiFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_or = Common(aliyunVodSdk.get_play_url, orFilePath, "or_online_%s" % request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + upload_video_thread_or.setDaemon(True) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_or.start() + upload_video_thread_ai.start() + or_url = upload_video_thread_or.get_result() + ai_url = upload_video_thread_ai.get_result() + return or_url, ai_url + ''' + + @staticmethod + def ai_normal_dtection(model, frame, request_id): + model_conf, code = model + retResults = MODEL_CONFIG[code][3]([model_conf, frame, request_id])[0] + if type(retResults) is np.ndarray or len(retResults) == 0: + ret = retResults + if type(retResults) is np.ndarray: + ret = retResults.tolist() + else: + ret = retResults[2] + return code, ret + + @staticmethod + def obj_det(self, model_array, frame, task_status, cframe, tt, request_id): + push_obj = [] + if task_status[1] == 1: + dtection_result = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result.append(result) + for d in dtection_result: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) == 0: + task_status[1] = 0 + if task_status[1] == 0: + if cframe % 30 == 0: + dtection_result1 = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result1.append(result) + for d in dtection_result1: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) > 0: + task_status[1] = 1 + return push_obj + + @staticmethod + def checkPT(start_time, service_timeout, pull_process, push_process, hb_thread, push_ex_queue, pull_queue, + request_id): + 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 pull_process is not None and not pull_process.is_alive(): + while True: + if pull_queue.empty() or pull_queue.qsize() == 0: + break + pull_result = get_no_block_queue(pull_queue) + if pull_result is not None and pull_result[0] == 1: + raise ServiceException(pull_result[1], pull_result[2]) + logger.info("拉流进程异常停止, requestId: {}", request_id) + raise Exception("拉流进程异常停止!") + if hb_thread is not None and not hb_thread.is_alive(): + logger.info("心跳线程异常停止, requestId: {}", request_id) + raise Exception("心跳线程异常停止!") + if push_process is not None and not push_process.is_alive(): + while True: + if push_ex_queue.empty() or push_ex_queue.qsize() == 0: + break + push_result = get_no_block_queue(push_ex_queue) + if push_result is not None and push_result[0] == 1: + raise ServiceException(push_result[1], push_result[2]) + logger.info("推流进程异常停止, requestId: {}", request_id) + raise Exception("推流进程异常停止!") + + def run(self): + msg, context, analyse_type = self._msg, self._context, self._analyse_type + self.build_video_path(context, msg) + request_id = msg["request_id"] + base_dir, env = context["base_dir"], context["env"] + service_timeout = int(context["service"]["timeout"]) + ex = None + # 拉流进程、推流进程、心跳线程 + pull_process, push_process, hb_thread = None, None, None + + # 事件队列、拉流队列、心跳队列、反馈队列 + event_queue, pull_queue, hb_queue, fb_queue = self.event_queue, self._pull_queue, self._hb_queue, self._fb_queue + + # 推流队列、推流异常队列、图片队列 + push_queue, push_ex_queue, image_queue = self._push_queue, self._push_ex_queue, self._image_queue + try: + # 初始化日志 + init_log(base_dir, env) + # 打印启动日志 + logger.info("开始启动实时分析进程!requestId: {}", request_id) + + # 启动拉流进程(包含拉流线程, 图片上传线程,mqtt读取线程) + # 拉流进程初始化时间长, 先启动 + pull_process = self.start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, 25) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #7.0, + # 启动心跳线程 + hb_thread = self.start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + + + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #7.0, + # 加载算法模型 + model_array = get_model(msg, context, analyse_type) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #9.5 + # 启动推流进程 + push_process = self.start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + # 第一个参数: 模型是否初始化 0:未初始化 1:初始化 + # 第二个参数: 检测是否有问题 0: 没有问题, 1: 有问题 + task_status = [0, 0] + draw_config = {} + start_time = time() + # 识别2个线程性能最优 + with ThreadPoolExecutor(max_workers=2) as t: + # 可能使用模型组合, 模型组合最多3个模型, 1对3, 上面的2个线程对应6个线程 + with ThreadPoolExecutor(max_workers=6) as tt: + while True: + # 检查拉流进程是否正常, 心跳线程是否正常 + self.checkPT(start_time, service_timeout, pull_process, push_process, hb_thread, push_ex_queue, + pull_queue, request_id) + # 检查推流是否异常 + push_status = get_no_block_queue(push_ex_queue) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #9.5,11.2 + if push_status is not None and push_status[0] == 1: + raise ServiceException(push_status[1], push_status[2]) + # 获取停止指令 + event_result = get_no_block_queue(event_queue) + + if event_result: + cmdStr = event_result.get("command") + + # 接收到停止指令 + if "stop" == cmdStr: + logger.info("实时任务开始停止, requestId: {}", request_id) + pull_process.sendCommand({"command": 'stop'}) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + pull_result = get_no_block_queue(pull_queue) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + if pull_result is None: + sleep(1) + continue + # (4, (frame_list, frame_index_list, all_frames)) + if pull_result[0] == 4: + frame_list, frame_index_list, all_frames = pull_result[1] + if len(frame_list) > 0: + # 判断是否已经初始化 + if task_status[0] == 0: + task_status[0] = 1 + for i, model in enumerate(model_array): + model_conf, code = model + model_param = model_conf[1] + # (modeType, model_param, allowedList, names, rainbows) + MODEL_CONFIG[code][2](frame_list[0].shape[1], frame_list[0].shape[0], + model_conf) + if draw_config.get("font_config") is None: + draw_config["font_config"] = model_param['font_config'] + if draw_config.get(code) is None: + draw_config[code] = {} + draw_config[code]["allowedList"] = model_conf[2] + draw_config[code]["rainbows"] = model_conf[4] + draw_config[code]["label_arrays"] = model_param['label_arraylist'] + if "label_dict" in model_param: + draw_config[code]["label_dict"] = model_param['label_dict'] + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + # 多线程并发处理, 经过测试两个线程最优 + det_array = [] + for i, frame in enumerate(frame_list): + det_result = t.submit(self.obj_det, self, model_array, frame, task_status, + frame_index_list[i], tt, request_id) + det_array.append(det_result) + push_objs = [det.result() for det in det_array] + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + put_queue(push_queue, + (1, (frame_list, frame_index_list, all_frames, draw_config, push_objs)), + timeout=2, is_ex=True) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + del det_array, push_objs + del frame_list, frame_index_list, all_frames + elif pull_result[0] == 1: + # 拉流发生异常 + put_queue(push_queue, (2, 'stop_ex'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + raise ServiceException(pull_result[1], pull_result[2]) + elif pull_result[0] == 2: + put_queue(push_queue, (2, 'stop'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + break + else: + raise Exception("未知拉流状态异常!") + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, 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: + orFilePath, aiFilePath = context["orFilePath"], context["aiFilePath"] + base_dir, env = context["base_dir"], context["env"] + or_url, ai_url, exc = "", "", None + try: + # 如果拉流进程存在, 关闭拉流进程(拉流线程、图片上传线程) + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + logger.info("关闭拉流进程, requestId:{}", request_id) + pull_process.join(timeout=120) + logger.info("关闭拉流进程1, requestId:{}", request_id) + if exists(orFilePath) and exists(aiFilePath) and getsize(orFilePath) > 100: + or_url, ai_url = self.upload_video(base_dir, env, request_id, orFilePath, aiFilePath) + if or_url is None or ai_url is None: + logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + # 停止心跳线程 + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=1) + hb_thread.join(timeout=120) + if exists(orFilePath): + logger.info("开始删除原视频, orFilePath: {}, requestId: {}", orFilePath, request_id) + os.remove(orFilePath) + logger.info("删除原视频成功, orFilePath: {}, requestId: {}", orFilePath, request_id) + if exists(aiFilePath): + logger.info("开始删除AI视频, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + os.remove(aiFilePath) + logger.info("删除AI视频成功, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + # 如果有异常, 检查是否有原视频和AI视频,有则上传,响应失败 + if ex: + code, msg = ex + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + video_url=or_url, + ai_video_url=ai_url), timeout=2, is_ex=False) + else: + if or_url is None or len(or_url) == 0 or ai_url is None or len(ai_url) == 0: + raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1]) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess, + video_url=or_url, + ai_video_url=ai_url), timeout=2, is_ex=False) + + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, request_id) + exc = s.code, s.msg + except Exception: + logger.error("服务异常: {}, requestId: {},", format_exc(), request_id) + exc = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + logger.info("关闭拉流进程, requestId:{}", request_id) + pull_process.join(timeout=120) + logger.info("关闭拉流进程1, requestId:{}", request_id) + if exc: + code, msg = exc + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + video_url=or_url, + ai_video_url=ai_url), timeout=2, is_ex=False) + logger.info("清理队列, requestId:{}", request_id) + self.clear_queue() + logger.info("清理队列完成, requestId:{}", request_id) + + +class OfflineIntelligentRecognitionProcess(IntelligentRecognitionProcess): + __slots__ = () + + def upload_video(self,base_dir, env, request_id, aiFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + if self._storage_source==1: + minioSdk = MinioSdk(base_dir, env, request_id ) + upload_video_thread_ai = Common(minioSdk.put_object, aiFilePath, "%s/ai_online.mp4" % request_id) + else: + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + ai_url = upload_video_thread_ai.get_result() + return ai_url + + ''' + @staticmethod + def upload_video(base_dir, env, request_id, aiFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + ai_url = upload_video_thread_ai.get_result() + return ai_url + ''' + @staticmethod + def ai_normal_dtection(model, frame, request_id): + model_conf, code = model + retResults = MODEL_CONFIG[code][3]([model_conf, frame, request_id])[0] + if type(retResults) is np.ndarray or len(retResults) == 0: + ret = retResults + if type(retResults) is np.ndarray: + ret = retResults.tolist() + else: + ret = retResults[2] + return code, ret + + @staticmethod + def obj_det(self, model_array, frame, task_status, cframe, tt, request_id): + push_obj = [] + if task_status[1] == 1: + dtection_result = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result.append(result) + for d in dtection_result: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) == 0: + task_status[1] = 0 + if task_status[1] == 0: + if cframe % 30 == 0: + dtection_result1 = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result1.append(result) + for d in dtection_result1: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) > 0: + task_status[1] = 1 + return push_obj + + @staticmethod + def start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context): + pushProcess = OffPushStreamProcess(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + pushProcess.daemon = True + pushProcess.start() + return pushProcess + + @staticmethod + def start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, frame_num): + pullProcess = OfflinePullVideoStreamProcess(msg, context, fb_queue, pull_queue, image_queue, analyse_type, + frame_num) + pullProcess.daemon = True + pullProcess.start() + return pullProcess + + @staticmethod + def checkPT(service_timeout, start_time, pull_process, push_process, hb_thread, push_ex_queue, pull_queue, + request_id): + 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 pull_process is not None and not pull_process.is_alive(): + while True: + if pull_queue.empty() or pull_queue.qsize() == 0: + break + pull_result = get_no_block_queue(pull_queue) + if pull_result is not None and pull_result[0] == 1: + raise ServiceException(pull_result[1], pull_result[2]) + logger.info("拉流进程异常停止, requestId: {}", request_id) + raise Exception("拉流进程异常停止!") + if hb_thread is not None and not hb_thread.is_alive(): + logger.info("心跳线程异常停止, requestId: {}", request_id) + raise Exception("心跳线程异常停止!") + if push_process is not None and not push_process.is_alive(): + while True: + if push_ex_queue.empty() or push_ex_queue.qsize() == 0: + break + push_result = get_no_block_queue(push_ex_queue) + if push_result is not None and push_result[0] == 1: + raise ServiceException(push_result[1], push_result[2]) + logger.info("推流进程异常停止, requestId: {}", request_id) + raise Exception("推流进程异常停止!") + + def run(self): + msg, context, analyse_type, ex = self._msg, self._context, self._analyse_type, None + self.build_video_path(context, msg, is_build_or=False) + request_id, base_dir, env = msg["request_id"], context["base_dir"], context["env"] + # 拉流进程、推流进程、心跳线程 + pull_process, push_process, hb_thread = None, None, None + service_timeout = int(context["service"]["timeout"]) + # 事件队列、拉流队列、心跳队列、反馈队列 + event_queue, pull_queue, hb_queue, fb_queue = self.event_queue, self._pull_queue, self._hb_queue, self._fb_queue + # 推流队列、推流异常队列、图片队列 + push_queue, push_ex_queue, image_queue = self._push_queue, self._push_ex_queue, self._image_queue + try: + # 初始化日志 + init_log(base_dir, env) + # 打印启动日志 + logger.info("开始启动离线分析进程!requestId: {}", request_id) + # 启动拉流进程(包含拉流线程, 图片上传线程) + # 拉流进程初始化时间长, 先启动 + pull_process = self.start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, 25) + # 启动心跳线程 + hb_thread = self.start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + # 加载算法模型 + model_array = get_model(msg, context, analyse_type) + # 启动推流进程 + push_process = self.start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + # 第一个参数: 模型是否初始化 0:未初始化 1:初始化 + # 第二个参数: 检测是否有问题 0: 没有问题, 1: 有问题 + task_status = [0, 0] + draw_config = {} + start_time = time() + # 识别2个线程性能最优 + with ThreadPoolExecutor(max_workers=2) as t: + # 可能使用模型组合, 模型组合最多3个模型, 1对3, 上面的2个线程对应6个线程 + with ThreadPoolExecutor(max_workers=6) as tt: + while True: + # 检查拉流进程是否正常, 心跳线程是否正常 + self.checkPT(service_timeout, start_time, pull_process, push_process, hb_thread, push_ex_queue, + pull_queue, request_id) + # 检查推流是否异常 + push_status = get_no_block_queue(push_ex_queue) + if push_status is not None and push_status[0] == 1: + raise ServiceException(push_status[1], push_status[2]) + # 获取停止指令 + event_result = get_no_block_queue(event_queue) + if event_result: + cmdStr = event_result.get("command") + # 接收到停止指令 + if "stop" == cmdStr: + logger.info("离线任务开始停止, requestId: {}", request_id) + pull_process.sendCommand({"command": 'stop'}) + pull_result = get_no_block_queue(pull_queue) + if pull_result is None: + sleep(1) + continue + # (4, (frame_list, frame_index_list, all_frames)) + if pull_result[0] == 4: + frame_list, frame_index_list, all_frames = pull_result[1] + if len(frame_list) > 0: + # 判断是否已经初始化 + if task_status[0] == 0: + task_status[0] = 1 + for i, model in enumerate(model_array): + model_conf, code = model + model_param = model_conf[1] + # (modeType, model_param, allowedList, names, rainbows) + MODEL_CONFIG[code][2](frame_list[0].shape[1], frame_list[0].shape[0], + model_conf) + if draw_config.get("font_config") is None: + draw_config["font_config"] = model_param['font_config'] + if draw_config.get(code) is None: + draw_config[code] = {} + draw_config[code]["allowedList"] = model_conf[2] + draw_config[code]["rainbows"] = model_conf[4] + draw_config[code]["label_arrays"] = model_param['label_arraylist'] + if "label_dict" in model_param: + draw_config[code]["label_dict"] = model_param['label_dict'] + det_array = [] + for i, frame in enumerate(frame_list): + det_result = t.submit(self.obj_det, self, model_array, frame, task_status, + frame_index_list[i], tt, request_id) + det_array.append(det_result) + push_objs = [det.result() for det in det_array] + put_queue(push_queue, + (1, (frame_list, frame_index_list, all_frames, draw_config, push_objs)), + timeout=2, is_ex=True) + del det_array, push_objs + del frame_list, frame_index_list, all_frames + elif pull_result[0] == 1: + put_queue(push_queue, (2, 'stop_ex'), timeout=1, is_ex=True) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + raise ServiceException(pull_result[1], pull_result[2]) + elif pull_result[0] == 2: + logger.info("离线任务开始停止, requestId: {}", request_id) + put_queue(push_queue, (2, 'stop'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + break + else: + raise Exception("未知拉流状态异常!") + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, 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: + base_dir, env, aiFilePath = context["base_dir"], context["env"], context["aiFilePath"] + ai_url, exc = "", None + try: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + push_process.join(timeout=120) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(timeout=120) + if exists(aiFilePath) and getsize(aiFilePath) > 100: + ai_url = self.upload_video(base_dir, env, request_id, aiFilePath) + if ai_url is None: + logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + # 停止心跳线程 + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=1) + hb_thread.join(timeout=120) + if exists(aiFilePath): + logger.info("开始删除AI视频, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + os.remove(aiFilePath) + logger.info("删除AI视频成功, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + # 如果有异常, 检查是否有原视频和AI视频,有则上传,响应失败 + if ex: + code, msg = ex + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + ai_video_url=ai_url), timeout=2, is_ex=False) + else: + if ai_url is None or len(ai_url) == 0: + raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1]) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess, + ai_video_url=ai_url), timeout=2, is_ex=False) + + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, request_id) + exc = s.code, s.msg + except Exception: + logger.error("服务异常: {}, requestId: {},", format_exc(), request_id) + exc = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + push_process.join(timeout=120) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(timeout=120) + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=1) + hb_thread.join(timeout=120) + if exc: + code, msg = exc + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + ai_video_url=ai_url), timeout=2, is_ex=False) + self.clear_queue() + + +''' +图片识别 +''' + + +class PhotosIntelligentRecognitionProcess(Process): + __slots__ = ("_fb_queue", "_msg", "_analyse_type", "_context", "_image_queue") + + def __init__(self, *args): + super().__init__() + self._fb_queue, self._msg, self._analyse_type, self._context = args + self._image_queue = Queue() + put_queue(self._fb_queue, message_feedback(self._msg["request_id"], AnalysisStatus.WAITING.value, + self._analyse_type, progress=init_progess), timeout=2, is_ex=True) + self.build_logo(self._msg, self._context) + self._storage_source = self._context['service']['storage_source'] + + @staticmethod + def build_logo(msg, context): + logo = None + if context["video"]["video_add_water"]: + logo = msg.get("logo_url") + if logo is not None and len(logo) > 0: + logo = url2Array(logo, enable_ex=False) + if logo is None: + logo = cv2.imread(join(context['base_dir'], "image/logo.png"), -1) + context['logo'] = logo + + def epidemic_prevention(self, imageUrl, model, orc, request_id): + try: + # modeType, allowedList, new_device, model, par, img_type + model_conf, code = model + modeType, allowedList, new_device, model, par, img_type = model_conf + image = url2Array(imageUrl) + param = [image, new_device, model, par, img_type, request_id] + dataBack = MODEL_CONFIG[code][3](param) + if img_type == 'plate': + carCode = '' + if dataBack is None or dataBack.get("plateImage") is None or len(dataBack.get("plateImage")) == 0: + result = orc.license_plate_recognition(image, request_id) + score = '' + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + logger.error("车牌识别为空: {}", result) + carCode = '' + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + else: + result = orc.license_plate_recognition(dataBack.get("plateImage")[0], request_id) + score = dataBack.get("plateImage")[1] + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + result = orc.license_plate_recognition(image, request_id) + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + logger.error("车牌识别为空: {}", result) + carCode = '' + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + if len(carCode) > 0: + plate_result = {'type': str(3), 'modelCode': code, 'carUrl': imageUrl, + 'carCode': carCode, + 'score': score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(3), + plate_result), timeout=2, is_ex=True) + if img_type == 'code': + if dataBack is None or dataBack.get("type") is None: + return + # 行程码 + if dataBack.get("type") == 1 and 1 in allowedList: + # 手机号 + if dataBack.get("phoneNumberImage") is None or len(dataBack.get("phoneNumberImage")) == 0: + phoneNumberRecognition = '' + phone_score = '' + else: + phone = orc.universal_text_recognition(dataBack.get("phoneNumberImage")[0], request_id) + phone_score = dataBack.get("phoneNumberImage")[1] + if phone is None or phone.get("words_result") is None or len(phone.get("words_result")) == 0: + logger.error("手机号识别为空: {}", phone) + phoneNumberRecognition = '' + else: + phoneNumberRecognition = phone.get("words_result") + if dataBack.get("cityImage") is None or len(dataBack.get("cityImage")) == 0: + cityRecognition = '' + city_score = '' + else: + city = orc.universal_text_recognition(dataBack.get("cityImage")[0], request_id) + city_score = dataBack.get("cityImage")[1] + if city is None or city.get("words_result") is None or len(city.get("words_result")) == 0: + logger.error("城市识别为空: {}", city) + cityRecognition = '' + else: + cityRecognition = city.get("words_result") + if len(phoneNumberRecognition) > 0 or len(cityRecognition) > 0: + trip_result = {'type': str(1), + 'modelCode': code, + 'imageUrl': imageUrl, + 'phoneNumberRecognition': phoneNumberRecognition, + 'phone_sorce': phone_score, + 'cityRecognition': cityRecognition, + 'city_score': city_score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(1), + trip_result), timeout=2, is_ex=True) + if dataBack.get("type") == 2 and 2 in allowedList: + if dataBack.get("nameImage") is None or len(dataBack.get("nameImage")) == 0: + nameRecognition = '' + name_score = '' + else: + name = orc.universal_text_recognition(dataBack.get("nameImage")[0], request_id) + name_score = dataBack.get("nameImage")[1] + if name is None or name.get("words_result") is None or len(name.get("words_result")) == 0: + logger.error("名字识别为空: {}", name) + nameRecognition = '' + else: + nameRecognition = name.get("words_result") + + if dataBack.get("phoneNumberImage") is None or len(dataBack.get("phoneNumberImage")) == 0: + phoneNumberRecognition = '' + phone_score = '' + else: + phone = orc.universal_text_recognition(dataBack.get("phoneNumberImage")[0], request_id) + phone_score = dataBack.get("phoneNumberImage")[1] + if phone is None or phone.get("words_result") is None or len(phone.get("words_result")) == 0: + logger.error("手机号识别为空: {}", phone) + phoneNumberRecognition = '' + else: + phoneNumberRecognition = phone.get("words_result") + if dataBack.get("hsImage") is None or len(dataBack.get("hsImage")) == 0: + hsRecognition = '' + hs_score = '' + else: + hs = orc.universal_text_recognition(dataBack.get("hsImage")[0], request_id) + hs_score = dataBack.get("hsImage")[1] + if hs is None or hs.get("words_result") is None or len(hs.get("words_result")) == 0: + logger.error("核酸识别为空: {}", hs) + hsRecognition = '' + else: + hsRecognition = hs.get("words_result") + if len(nameRecognition) > 0 or len(phoneNumberRecognition) > 0 or len(hsRecognition) > 0: + healthy_result = {'type': str(2), + 'modelCode': code, + 'imageUrl': imageUrl, + 'color': dataBack.get("color"), + 'nameRecognition': nameRecognition, + 'name_score': name_score, + 'phoneNumberRecognition': phoneNumberRecognition, + 'phone_score': phone_score, + 'hsRecognition': hsRecognition, + 'hs_score': hs_score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(2), + healthy_result), timeout=2, is_ex=True) + except ServiceException as s: + raise s + except Exception as e: + logger.error("模型分析异常: {}, requestId: {}", format_exc(), request_id) + raise e + + ''' + # 防疫模型 + ''' + + def epidemicPrevention(self, imageUrls, model, base_dir, env, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + orc = OcrBaiduSdk(base_dir, env) + obj_list = [] + for imageUrl in imageUrls: + obj = t.submit(self.epidemic_prevention, imageUrl, model, orc, request_id) + obj_list.append(obj) + for r in obj_list: + r.result(60) + + def image_recognition(self, imageUrl, mod, image_queue, logo, request_id): + try: + model_conf, code = mod + model_param = model_conf[1] + image = url2Array(imageUrl) + MODEL_CONFIG[code][2](image.shape[1], image.shape[0], model_conf) + p_result = MODEL_CONFIG[code][3]([model_conf, image, request_id])[0] + #print(' line872:p_result[2]:',p_result[2] ) + if p_result is None or len(p_result) < 3 or p_result[2] is None or len(p_result[2]) == 0: + return + if logo: + image = add_water_pic(image, logo, request_id) + # (modeType, model_param, allowedList, names, rainbows) + allowedList = model_conf[2] + label_arraylist = model_param['label_arraylist'] + font_config = model_param['font_config'] + rainbows = model_conf[4] + det_xywh = {code: {}} + ai_result_list = p_result[2] + for ai_result in ai_result_list: + box, score, cls = xywh2xyxy2(ai_result) + # 如果检测目标在识别任务中,继续处理 + if cls in allowedList: + label_array = label_arraylist[cls] + color = rainbows[cls] + cd = det_xywh[code].get(cls) + 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]) + #print('ai_result_list:{},allowlist:{}'.format(ai_result_list,allowedList )) + if len(det_xywh) > 0: + put_queue(image_queue, (1, (det_xywh, imageUrl, image, font_config, "")), timeout=2, is_ex=False) + except ServiceException as s: + raise s + except Exception as e: + logger.error("模型分析异常: {}, requestId: {}", format_exc(), self._msg.get("request_id")) + raise e + + def publicIdentification(self, imageUrls, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + obj_list = [] + for imageUrl in imageUrls: + obj = t.submit(self.image_recognition, imageUrl, mod, image_queue, logo, request_id) + obj_list.append(obj) + for r in obj_list: + r.result(60) + + ''' + 1. imageUrls: 图片url数组,多张图片 + 2. mod: 模型对象 + 3. image_queue: 图片队列 + ''' + + def baiduRecognition(self, imageUrls, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + thread_result = [] + for imageUrl in imageUrls: + obj = t.submit(self.baidu_recognition, imageUrl, mod, image_queue, logo, request_id) + thread_result.append(obj) + for r in thread_result: + r.result(60) + + def baidu_recognition(self, imageUrl, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + try: + # modeType, aipImageClassifyClient, aipBodyAnalysisClient, allowedList, rainbows, + # vehicle_names, person_names, requestId + model_conf, code = mod + allowedList = model_conf[3] + rainbows = model_conf[4] + # 图片转数组 + img = url2Array(imageUrl) + vehicle_label_arrays, person_label_arrays, font_config = MODEL_CONFIG[code][2](img.shape[1], + img.shape[0], + model_conf) + obj_list = [] + for target in allowedList: + parm = [target, imageUrl, model_conf[1], model_conf[2], request_id] + reuslt = t.submit(self.baidu_method, code, parm, img, image_queue, vehicle_label_arrays, + person_label_arrays, font_config, rainbows, logo) + obj_list.append(reuslt) + for r in obj_list: + r.result(60) + except ServiceException as s: + raise s + except Exception as e: + logger.error("百度AI分析异常: {}, requestId: {}", format_exc(), request_id) + raise e + + @staticmethod + def baidu_method(code, parm, img, image_queue, vehicle_label_arrays, person_label_arrays, font_config, + rainbows, logo): + # [target, url, aipImageClassifyClient, aipBodyAnalysisClient, requestId] + request_id = parm[4] + target = parm[0] + image_url = parm[1] + result = MODEL_CONFIG[code][3](parm) + if target == BaiduModelTarget.VEHICLE_DETECTION.value[1] and result is not None: + vehicleInfo = result.get("vehicle_info") + if vehicleInfo is not None and len(vehicleInfo) > 0: + det_xywh = {code: {}} + copy_frame = img.copy() + for i, info in enumerate(vehicleInfo): + value = VehicleEnumVALUE.get(info.get("type")) + target_num = value.value[2] + label_array = vehicle_label_arrays[target_num] + color = rainbows[target_num] + if value is None: + logger.error("车辆识别出现未支持的目标类型!type:{}, requestId:{}", info.get("type"), request_id) + return + left_top = (int(info.get("location").get("left")), int(info.get("location").get("top"))) + right_top = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top"))) + right_bottom = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + left_bottom = (int(info.get("location").get("left")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + box = [left_top, right_top, right_bottom, left_bottom] + score = float("%.2f" % info.get("probability")) + if logo: + copy_frame = add_water_pic(copy_frame, logo, request_id) + if det_xywh[code].get(target) is None: + det_xywh[code][target] = [[target, box, score, label_array, color]] + else: + det_xywh[code][target].append([target, box, score, label_array, color]) + info["id"] = str(i) + if len(det_xywh[code]) > 0: + result["type"] = str(target) + result["modelCode"] = code + put_queue(image_queue, (1, (det_xywh, image_url, copy_frame, font_config, result)), timeout=2, + is_ex=True) + # 人体识别 + if target == BaiduModelTarget.HUMAN_DETECTION.value[1] and result is not None: + personInfo = result.get("person_info") + personNum = result.get("person_num") + if personNum is not None and personNum > 0 and personInfo is not None and len(personInfo) > 0: + det_xywh = {code: {}} + copy_frame = img.copy() + for i, info in enumerate(personInfo): + left_top = (int(info.get("location").get("left")), int(info.get("location").get("top"))) + right_top = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top"))) + right_bottom = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + left_bottom = (int(info.get("location").get("left")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + box = [left_top, right_top, right_bottom, left_bottom] + score = float("%.2f" % info.get("location").get("score")) + label_array = person_label_arrays[0] + color = rainbows[0] + if logo: + copy_frame = add_water_pic(copy_frame, logo, request_id) + if det_xywh[code].get(target) is None: + det_xywh[code][target] = [[target, box, score, label_array, color]] + else: + det_xywh[code][target].append([target, box, score, label_array, color]) + info["id"] = str(i) + if len(det_xywh[code]) > 0: + result["type"] = str(target) + result["modelCode"] = code + put_queue(image_queue, (1, (det_xywh, image_url, copy_frame, font_config, result)), timeout=2) + # 人流量 + if target == BaiduModelTarget.PEOPLE_COUNTING.value[1] and result is not None: + base64Image = result.get("image") + if base64Image is not None and len(base64Image) > 0: + baiduImage = base64.b64decode(base64Image) + result["type"] = str(target) + result["modelCode"] = code + del result["image"] + put_queue(image_queue, (1, (None, image_url, baiduImage, None, result)), timeout=2) + + @staticmethod + def start_File_upload(fb_queue, context, msg, image_queue, analyse_type): + image_thread = ImageTypeImageFileUpload(fb_queue, context, msg, image_queue, analyse_type) + image_thread.setDaemon(True) + image_thread.start() + return image_thread + + def run(self): + fb_queue, msg, analyse_type, context = self._fb_queue, self._msg, self._analyse_type, self._context + request_id, logo, image_queue = msg["request_id"], context['logo'], self._image_queue + base_dir, env = context["base_dir"], context["env"] + imageUrls = msg["image_urls"] + image_thread = None + with ThreadPoolExecutor(max_workers=2) as t: + try: + init_log(base_dir, env) + logger.info("开始启动图片识别进程, requestId: {}", request_id) + model_array = get_model(msg, context, analyse_type) + image_thread = self.start_File_upload(fb_queue, context, msg, image_queue, analyse_type) + task_list = [] + for model in model_array: + # 百度模型逻辑 + if model[1] == ModelType.BAIDU_MODEL.value[1]: + result = t.submit(self.baiduRecognition, imageUrls, model, image_queue, logo, request_id) + task_list.append(result) + # 防疫模型 + elif model[1] == ModelType.EPIDEMIC_PREVENTION_MODEL.value[1]: + result = t.submit(self.epidemicPrevention, imageUrls, model, base_dir, env, request_id) + task_list.append(result) + # 车牌模型 + elif model[1] == ModelType.PLATE_MODEL.value[1]: + result = t.submit(self.epidemicPrevention, imageUrls, model, base_dir, env, request_id) + task_list.append(result) + else: + result = t.submit(self.publicIdentification, imageUrls, model, image_queue, logo, request_id) + task_list.append(result) + for r in task_list: + r.result(60) + if image_thread and not image_thread.is_alive(): + raise Exception("图片识别图片上传线程异常停止!!!") + if image_thread and image_thread.is_alive(): + put_queue(image_queue, (2, 'stop'), timeout=2) + image_thread.join(120) + logger.info("图片进程任务完成,requestId:{}", request_id) + put_queue(fb_queue, message_feedback(request_id, + AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess), timeout=2, is_ex=True) + except ServiceException as s: + logger.error("图片分析异常,异常编号:{}, 异常描述:{}, requestId:{}", s.code, s.msg, request_id) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + s.code, + s.msg), timeout=2) + except Exception: + logger.error("图片分析异常: {}, requestId:{}", format_exc(), request_id) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]), timeout=2) + finally: + if image_thread and image_thread.is_alive(): + clear_queue(image_queue) + put_queue(image_queue, (2, 'stop'), timeout=2) + image_thread.join(120) + clear_queue(image_queue) + + +class ScreenRecordingProcess(Process): + __slots__ = ('_fb_queue', '_context', '_msg', '_analysisType', '_event_queue', '_hb_queue', '_analysisType') + + def __init__(self, *args): + super().__init__() + # 传参 + self._fb_queue, self._context, self._msg, self._analysisType = args + self._event_queue, self._hb_queue, self._pull_queue = Queue(), Queue(), Queue(10) + put_queue(self._fb_queue, + recording_feedback(self._msg["request_id"], RecordingStatus.RECORDING_WAITING.value[0]), + timeout=1, is_ex=True) + self._storage_source = self._context['service']['storage_source'] + def sendEvent(self, result): + put_queue(self._event_queue, result, timeout=2, is_ex=True) + + @staticmethod + def start_pull_stream_thread(msg, context, pull_queue, hb_queue, fb_queue, frame_num): + pullThread = RecordingPullStreamThread(msg, context, pull_queue, hb_queue, fb_queue, frame_num) + pullThread.setDaemon(True) + pullThread.start() + return pullThread + + @staticmethod + def start_hb_thread(fb_queue, hb_queue, request_id): + hb = RecordingHeartbeat(fb_queue, hb_queue, request_id) + hb.setDaemon(True) + hb.start() + return hb + + @staticmethod + def check(start_time, service_timeout, pull_thread, hb_thread, request_id): + 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 pull_thread and not pull_thread.is_alive(): + logger.info("录屏拉流线程停止异常, requestId: {}", request_id) + raise Exception("录屏拉流线程异常停止") + if hb_thread and not hb_thread.is_alive(): + logger.info("录屏心跳线程异常停止, requestId: {}", request_id) + raise Exception("录屏心跳线程异常停止") + + def run(self): + msg, context = self._msg, self._context + request_id, push_url = msg['request_id'], msg.get('push_url') + pull_queue, fb_queue, hb_queue, event_queue = self._pull_queue, self._fb_queue, self._hb_queue, \ + self._event_queue + base_dir, env, service_timeout = context['base_dir'], context['env'], int(context["service"]["timeout"]) + pre_path, end_path = '%s/%s%s' % (base_dir, context["video"]["file_path"], now_date_to_str(YMDHMSF)), \ + '%s%s' % (request_id, ".mp4") + orFilePath = '%s%s%s' % (pre_path, "_on_or_", end_path) + pull_thread, hb_thread = None, None + or_write_status, p_push_status = [0, 0], [0, 0] + or_video_file, push_p = None, None + ex = None + try: + # 初始化日志 + init_log(base_dir, env) + # 启动拉流线程 + pull_thread = self.start_pull_stream_thread(msg, context, pull_queue, hb_queue, fb_queue, 25) + hb_thread = self.start_hb_thread(fb_queue, hb_queue, request_id) + start_time = time() + with ThreadPoolExecutor(max_workers=2) as t: + while True: + # 检查拉流线程和心跳线程 + self.check(start_time, service_timeout, pull_thread, hb_thread, request_id) + # 判断是否需要停止录屏 + event_result = get_no_block_queue(event_queue) + if event_result is not None: + cmdStr = event_result.get("command") + # 接收到停止指令 + if 'stop' == cmdStr: + logger.info("录屏任务开始停止, requestId: {}", request_id) + pull_thread.sendEvent({"command": "stop"}) + pull_result = get_no_block_queue(pull_queue) + if pull_result is None: + sleep(1) + continue + if pull_result[0] == 1: + close_all_p(push_p, or_video_file, None, request_id) + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(180) + raise ServiceException(pull_result[1], pull_result[2]) + elif pull_result[0] == 2: + close_all_p(push_p, or_video_file, None, request_id) + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(180) + break + elif pull_result[0] == 4: + frame_list, frame_index_list, all_frames = pull_result[1] + if len(frame_list) > 0: + 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, {"progress": task_process}, timeout=1) + write_or_video_result = t.submit(write_or_video, frame, orFilePath, or_video_file, + or_write_status, request_id) + if push_url is not None and len(push_url) > 0: + push_p_result = t.submit(push_video_stream, frame, push_p, push_url, p_push_status, + request_id) + push_p = push_p_result.result() + or_video_file = write_or_video_result.result() + else: + raise Exception("未知拉流状态异常!") + logger.info("录屏线程任务完成,requestId:{}", self._msg.get("request_id")) + except ServiceException as s: + logger.error("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, self._msg.get("request_id")) + ex = s.code, s.msg + except Exception: + logger.error("服务异常: {}, requestId: {},", format_exc(), self._msg.get("request_id")) + ex = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + or_url = "" + exn = None + try: + # 关闭推流管道, 原视频写流客户端 + close_all_p(push_p, or_video_file, None, request_id) + # 关闭拉流线程 + if pull_thread and pull_thread.is_alive(): + pull_thread.sendEvent({"command": "stop_ex"}) + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(120) + # 判断是否需要上传视频 + if exists(orFilePath) and getsize(orFilePath) > 100: + or_url = self.upload_video(base_dir, env, request_id, orFilePath) + if or_url is None or len(or_url) == 0: + logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + # 停止心跳线程 + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=10, is_ex=False) + hb_thread.join(timeout=120) + if exists(orFilePath): + logger.info("开始删除原视频, orFilePath: {}, requestId: {}", orFilePath, request_id) + os.remove(orFilePath) + logger.info("删除原视频成功, orFilePath: {}, requestId: {}", orFilePath, request_id) + # 如果有异常, 检查是否有原视频和AI视频,有则上传,响应失败 + if ex: + code, msg = ex + put_queue(fb_queue, recording_feedback(request_id, RecordingStatus.RECORDING_FAILED.value[0], + error_code=code, + error_msg=msg, + video_url=or_url), timeout=10, is_ex=False) + else: + if or_url is None or len(or_url) == 0: + raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1]) + put_queue(fb_queue, recording_feedback(request_id, RecordingStatus.RECORDING_SUCCESS.value[0], + progress=success_progess, + video_url=or_url), timeout=10, is_ex=False) + except ServiceException as s: + exn = s.code, s.msg + except Exception: + logger.error("异常:{}, requestId: {}", format_exc(), request_id) + exn = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + if pull_thread and pull_thread.is_alive(): + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(120) + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=10, is_ex=False) + hb_thread.join(timeout=120) + self.clear_queue_end() + if exn: + code, msg = exn + put_queue(fb_queue, recording_feedback(request_id, RecordingStatus.RECORDING_FAILED.value[0], + error_code=code, + error_msg=msg, + video_url=or_url), timeout=10, is_ex=False) + + def clear_queue_end(self): + clear_queue(self._event_queue) + clear_queue(self._hb_queue) + clear_queue(self._pull_queue) + + + + + def upload_video(self,base_dir, env, request_id, orFilePath): + if self._storage_source==1: + minioSdk = MinioSdk(base_dir, env, request_id ) + upload_video_thread_ai = Common(minioSdk.put_object, aiFilePath, "%s/ai_online.mp4" % request_id) + else: + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + or_url = upload_video_thread_ai.get_result() + return or_url + ''' + @staticmethod + def upload_video(base_dir, env, request_id, orFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, orFilePath, "or_online_%s" % request_id) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + or_url = upload_video_thread_ai.get_result() + return or_url + ''' + +""" +"models": [{ + "code": "模型编号", + "categories":[{ + "id": "模型id", + "config": { + "k1": "v1", + "k2": "v2" + } + }] +}] +""" + + +def get_model(msg, context, analyse_type): + # 初始变量 + request_id, base_dir, gpu_name, env = msg["request_id"], context["base_dir"], context["gpu_name"], context["env"] + models, model_num_limit = msg["models"], context["service"]["model"]['limit'] + try: + # 实时、离线元组 + analyse_type_tuple = (AnalysisType.ONLINE.value, AnalysisType.OFFLINE.value) + # (实时、离线)检查模型组合, 目前只支持3个模型组合 + if analyse_type in analyse_type_tuple: + if len(models) > model_num_limit: + raise ServiceException(ExceptionType.MODEL_GROUP_LIMIT_EXCEPTION.value[0], + ExceptionType.MODEL_GROUP_LIMIT_EXCEPTION.value[1]) + modelArray, codeArray = [], set() + for model in models: + # 模型编码 + code = model["code"] + # 检验code是否重复 + if code in codeArray: + raise ServiceException(ExceptionType.MODEL_DUPLICATE_EXCEPTION.value[0], + ExceptionType.MODEL_DUPLICATE_EXCEPTION.value[1]) + codeArray.add(code) + # 检测目标数组 + needed_objectsIndex = list(set([int(category["id"]) for category in model["categories"]])) + logger.info("模型编号: {}, 检查目标: {}, requestId: {}", code, needed_objectsIndex, request_id) + model_method = MODEL_CONFIG.get(code) + if model_method is None: + logger.error("未匹配到对应的模型, requestId:{}", request_id) + raise ServiceException(ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[0], + ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[1]) + # 检查cpu资源、gpu资源 + check_cpu(base_dir, request_id) + gpu_ids = check_gpu_resource(request_id) + # 如果实时识别、离线识别 + if analyse_type in analyse_type_tuple: + if model["is_video"] == "1": + mod = model_method[0](gpu_ids[0], needed_objectsIndex, request_id, gpu_name, base_dir, env) + modelArray.append((mod.model_conf, code)) + else: + raise ServiceException(ExceptionType.MODEL_NOT_SUPPORT_VIDEO_EXCEPTION.value[0], + ExceptionType.MODEL_NOT_SUPPORT_VIDEO_EXCEPTION.value[1], + model_method[1].value[2]) + # 如果是图片识别 + if analyse_type == AnalysisType.IMAGE.value: + if model["is_image"] == "1": + mod = model_method[0](gpu_ids[0], needed_objectsIndex, request_id, gpu_name, base_dir, env) + modelArray.append((mod.model_conf, code)) + else: + raise ServiceException(ExceptionType.MODEL_NOT_SUPPORT_IMAGE_EXCEPTION.value[0], + ExceptionType.MODEL_NOT_SUPPORT_IMAGE_EXCEPTION.value[1], + model_method[1].value[2]) + if len(modelArray) == 0: + raise ServiceException(ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[0], + ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[1]) + return modelArray + except ServiceException as s: + raise s + except Exception: + logger.error("模型配置处理异常: {}, request_id: {}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) diff --git a/concurrency/Pull2PushStreamProcess.py b/concurrency/Pull2PushStreamProcess.py new file mode 100644 index 0000000..dd410d0 --- /dev/null +++ b/concurrency/Pull2PushStreamProcess.py @@ -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) diff --git a/concurrency/Pull2PushStreamThread.py b/concurrency/Pull2PushStreamThread.py new file mode 100644 index 0000000..2ccffed --- /dev/null +++ b/concurrency/Pull2PushStreamThread.py @@ -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) diff --git a/concurrency/PullMqttThread.py b/concurrency/PullMqttThread.py new file mode 100644 index 0000000..fe208fb --- /dev/null +++ b/concurrency/PullMqttThread.py @@ -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() + \ No newline at end of file diff --git a/concurrency/PullStreamThread.py b/concurrency/PullStreamThread.py new file mode 100644 index 0000000..29a8570 --- /dev/null +++ b/concurrency/PullStreamThread.py @@ -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) diff --git a/concurrency/PullVideoStreamProcess.py b/concurrency/PullVideoStreamProcess.py new file mode 100644 index 0000000..54fe030 --- /dev/null +++ b/concurrency/PullVideoStreamProcess.py @@ -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) diff --git a/concurrency/PullVideoStreamProcess2.py b/concurrency/PullVideoStreamProcess2.py new file mode 100644 index 0000000..39690b1 --- /dev/null +++ b/concurrency/PullVideoStreamProcess2.py @@ -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) diff --git a/concurrency/PushStreamThread.py b/concurrency/PushStreamThread.py new file mode 100644 index 0000000..1e395d9 --- /dev/null +++ b/concurrency/PushStreamThread.py @@ -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) \ No newline at end of file diff --git a/concurrency/PushStreamThread2.py b/concurrency/PushStreamThread2.py new file mode 100644 index 0000000..9b84882 --- /dev/null +++ b/concurrency/PushStreamThread2.py @@ -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) \ No newline at end of file diff --git a/concurrency/PushVideoStreamProcess.py b/concurrency/PushVideoStreamProcess.py new file mode 100644 index 0000000..2004da7 --- /dev/null +++ b/concurrency/PushVideoStreamProcess.py @@ -0,0 +1,486 @@ +#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, draw_name_joint + +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'] + + 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: + 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 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: + 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 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) diff --git a/concurrency/PushVideoStreamProcess2.py b/concurrency/PushVideoStreamProcess2.py new file mode 100644 index 0000000..8aac80b --- /dev/null +++ b/concurrency/PushVideoStreamProcess2.py @@ -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) diff --git a/concurrency/RecordingHeartbeatThread.py b/concurrency/RecordingHeartbeatThread.py new file mode 100644 index 0000000..614589c --- /dev/null +++ b/concurrency/RecordingHeartbeatThread.py @@ -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) diff --git a/concurrency/__init__.py b/concurrency/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/concurrency/__pycache__/CommonThread.cpython-38.pyc b/concurrency/__pycache__/CommonThread.cpython-38.pyc new file mode 100644 index 0000000..1a1ff99 Binary files /dev/null and b/concurrency/__pycache__/CommonThread.cpython-38.pyc differ diff --git a/concurrency/__pycache__/FeedbackThread.cpython-38.pyc b/concurrency/__pycache__/FeedbackThread.cpython-38.pyc new file mode 100644 index 0000000..ea9bb03 Binary files /dev/null and b/concurrency/__pycache__/FeedbackThread.cpython-38.pyc differ diff --git a/concurrency/__pycache__/FileUploadThread.cpython-38.pyc b/concurrency/__pycache__/FileUploadThread.cpython-38.pyc new file mode 100644 index 0000000..e00f621 Binary files /dev/null and b/concurrency/__pycache__/FileUploadThread.cpython-38.pyc differ diff --git a/concurrency/__pycache__/HeartbeatThread.cpython-38.pyc b/concurrency/__pycache__/HeartbeatThread.cpython-38.pyc new file mode 100644 index 0000000..0f848db Binary files /dev/null and b/concurrency/__pycache__/HeartbeatThread.cpython-38.pyc differ diff --git a/concurrency/__pycache__/IntelligentRecognitionProcess.cpython-38.pyc b/concurrency/__pycache__/IntelligentRecognitionProcess.cpython-38.pyc new file mode 100644 index 0000000..013cd6c Binary files /dev/null and b/concurrency/__pycache__/IntelligentRecognitionProcess.cpython-38.pyc differ diff --git a/concurrency/__pycache__/IntelligentRecognitionProcess2.cpython-38.pyc b/concurrency/__pycache__/IntelligentRecognitionProcess2.cpython-38.pyc new file mode 100644 index 0000000..ba056c0 Binary files /dev/null and b/concurrency/__pycache__/IntelligentRecognitionProcess2.cpython-38.pyc differ diff --git a/concurrency/__pycache__/Pull2PushStreamProcess.cpython-38.pyc b/concurrency/__pycache__/Pull2PushStreamProcess.cpython-38.pyc new file mode 100644 index 0000000..c312d3d Binary files /dev/null and b/concurrency/__pycache__/Pull2PushStreamProcess.cpython-38.pyc differ diff --git a/concurrency/__pycache__/Pull2PushStreamThread.cpython-38.pyc b/concurrency/__pycache__/Pull2PushStreamThread.cpython-38.pyc new file mode 100644 index 0000000..eb13c99 Binary files /dev/null and b/concurrency/__pycache__/Pull2PushStreamThread.cpython-38.pyc differ diff --git a/concurrency/__pycache__/PullMqttThread.cpython-38.pyc b/concurrency/__pycache__/PullMqttThread.cpython-38.pyc new file mode 100644 index 0000000..46040b3 Binary files /dev/null and b/concurrency/__pycache__/PullMqttThread.cpython-38.pyc differ diff --git a/concurrency/__pycache__/PullStreamThread.cpython-38.pyc b/concurrency/__pycache__/PullStreamThread.cpython-38.pyc new file mode 100644 index 0000000..f92df66 Binary files /dev/null and b/concurrency/__pycache__/PullStreamThread.cpython-38.pyc differ diff --git a/concurrency/__pycache__/PullVideoStreamProcess.cpython-38.pyc b/concurrency/__pycache__/PullVideoStreamProcess.cpython-38.pyc new file mode 100644 index 0000000..51d27cb Binary files /dev/null and b/concurrency/__pycache__/PullVideoStreamProcess.cpython-38.pyc differ diff --git a/concurrency/__pycache__/PullVideoStreamProcess2.cpython-38.pyc b/concurrency/__pycache__/PullVideoStreamProcess2.cpython-38.pyc new file mode 100644 index 0000000..bf5c126 Binary files /dev/null and b/concurrency/__pycache__/PullVideoStreamProcess2.cpython-38.pyc differ diff --git a/concurrency/__pycache__/PushStreamThread.cpython-38.pyc b/concurrency/__pycache__/PushStreamThread.cpython-38.pyc new file mode 100644 index 0000000..338c44f Binary files /dev/null and b/concurrency/__pycache__/PushStreamThread.cpython-38.pyc differ diff --git a/concurrency/__pycache__/PushStreamThread2.cpython-38.pyc b/concurrency/__pycache__/PushStreamThread2.cpython-38.pyc new file mode 100644 index 0000000..be48993 Binary files /dev/null and b/concurrency/__pycache__/PushStreamThread2.cpython-38.pyc differ diff --git a/concurrency/__pycache__/PushVideoStreamProcess.cpython-38.pyc b/concurrency/__pycache__/PushVideoStreamProcess.cpython-38.pyc new file mode 100644 index 0000000..27cbd8c Binary files /dev/null and b/concurrency/__pycache__/PushVideoStreamProcess.cpython-38.pyc differ diff --git a/concurrency/__pycache__/PushVideoStreamProcess2.cpython-38.pyc b/concurrency/__pycache__/PushVideoStreamProcess2.cpython-38.pyc new file mode 100644 index 0000000..dfc1775 Binary files /dev/null and b/concurrency/__pycache__/PushVideoStreamProcess2.cpython-38.pyc differ diff --git a/concurrency/__pycache__/RecordingHeartbeatThread.cpython-38.pyc b/concurrency/__pycache__/RecordingHeartbeatThread.cpython-38.pyc new file mode 100644 index 0000000..3c2c11f Binary files /dev/null and b/concurrency/__pycache__/RecordingHeartbeatThread.cpython-38.pyc differ diff --git a/concurrency/__pycache__/__init__.cpython-38.pyc b/concurrency/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..b963a8b Binary files /dev/null and b/concurrency/__pycache__/__init__.cpython-38.pyc differ diff --git a/concurrency/__pycache__/uploadGPU.cpython-38.pyc b/concurrency/__pycache__/uploadGPU.cpython-38.pyc new file mode 100644 index 0000000..0928cb6 Binary files /dev/null and b/concurrency/__pycache__/uploadGPU.cpython-38.pyc differ diff --git a/concurrency/uploadGPU.py b/concurrency/uploadGPU.py new file mode 100644 index 0000000..a85c0a7 --- /dev/null +++ b/concurrency/uploadGPU.py @@ -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("主线程退出") + + + + \ No newline at end of file diff --git a/config/aliyun/dsp_dev_aliyun.yml b/config/aliyun/dsp_dev_aliyun.yml new file mode 100644 index 0000000..680cbbf --- /dev/null +++ b/config/aliyun/dsp_dev_aliyun.yml @@ -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 diff --git a/config/aliyun/dsp_prod_aliyun.yml b/config/aliyun/dsp_prod_aliyun.yml new file mode 100644 index 0000000..a573884 --- /dev/null +++ b/config/aliyun/dsp_prod_aliyun.yml @@ -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 diff --git a/config/aliyun/dsp_test_aliyun.yml b/config/aliyun/dsp_test_aliyun.yml new file mode 100644 index 0000000..67d0aa5 --- /dev/null +++ b/config/aliyun/dsp_test_aliyun.yml @@ -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 + diff --git a/config/aliyun/dsp_test_aliyun.yml.bak b/config/aliyun/dsp_test_aliyun.yml.bak new file mode 100644 index 0000000..67d0aa5 --- /dev/null +++ b/config/aliyun/dsp_test_aliyun.yml.bak @@ -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 + diff --git a/config/baidu/dsp_dev_baidu.yml b/config/baidu/dsp_dev_baidu.yml new file mode 100644 index 0000000..249b70c --- /dev/null +++ b/config/baidu/dsp_dev_baidu.yml @@ -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" diff --git a/config/baidu/dsp_prod_baidu.yml b/config/baidu/dsp_prod_baidu.yml new file mode 100644 index 0000000..249b70c --- /dev/null +++ b/config/baidu/dsp_prod_baidu.yml @@ -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" diff --git a/config/baidu/dsp_test_baidu.yml b/config/baidu/dsp_test_baidu.yml new file mode 100644 index 0000000..249b70c --- /dev/null +++ b/config/baidu/dsp_test_baidu.yml @@ -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" diff --git a/config/kafka/dsp_dev_kafka.yml b/config/kafka/dsp_dev_kafka.yml new file mode 100644 index 0000000..2f9572d --- /dev/null +++ b/config/kafka/dsp_dev_kafka.yml @@ -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 + + + diff --git a/config/kafka/dsp_prod_kafka.yml b/config/kafka/dsp_prod_kafka.yml new file mode 100644 index 0000000..193048f --- /dev/null +++ b/config/kafka/dsp_prod_kafka.yml @@ -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 diff --git a/config/kafka/dsp_test_kafka.yml b/config/kafka/dsp_test_kafka.yml new file mode 100644 index 0000000..3ba39d8 --- /dev/null +++ b/config/kafka/dsp_test_kafka.yml @@ -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 + + diff --git a/config/logger/dsp_dev_logger.yml b/config/logger/dsp_dev_logger.yml new file mode 100644 index 0000000..697581d --- /dev/null +++ b/config/logger/dsp_dev_logger.yml @@ -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" + diff --git a/config/logger/dsp_prod_logger.yml b/config/logger/dsp_prod_logger.yml new file mode 100644 index 0000000..1e8baed --- /dev/null +++ b/config/logger/dsp_prod_logger.yml @@ -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" + diff --git a/config/logger/dsp_test_logger.yml b/config/logger/dsp_test_logger.yml new file mode 100644 index 0000000..2a2e706 --- /dev/null +++ b/config/logger/dsp_test_logger.yml @@ -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: "3 days" +encoding: "utf8" + diff --git a/config/minio/dsp_test_minio.yml b/config/minio/dsp_test_minio.yml new file mode 100644 index 0000000..50a912b --- /dev/null +++ b/config/minio/dsp_test_minio.yml @@ -0,0 +1,8 @@ +endpoint: 'minio.t-aaron.com' +domain: 'https://minio.t-aaron.com' +access_key: 'IKf3A0ZSXsR1m0oalMjV' +secret_key: 'yoC6qRo2hlyZu8Pdbt6eh9TVaTV4gD7KRudromrk' +secure: false +image_bucket: 'th-airport' +video_bucket: 'th-airport' +file_dir: 'testFile' diff --git a/config/minio/dsp_test_minio_OnDSJ.yml b/config/minio/dsp_test_minio_OnDSJ.yml new file mode 100644 index 0000000..d2f8aa3 --- /dev/null +++ b/config/minio/dsp_test_minio_OnDSJ.yml @@ -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' + diff --git a/config/mqtt/dsp_test_mqtt.yml b/config/mqtt/dsp_test_mqtt.yml new file mode 100644 index 0000000..a8e2310 --- /dev/null +++ b/config/mqtt/dsp_test_mqtt.yml @@ -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 + diff --git a/config/service/dsp_dev_service.yml b/config/service/dsp_dev_service.yml new file mode 100644 index 0000000..4c4150c --- /dev/null +++ b/config/service/dsp_dev_service.yml @@ -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 + + diff --git a/config/service/dsp_prod_service.yml b/config/service/dsp_prod_service.yml new file mode 100644 index 0000000..006c393 --- /dev/null +++ b/config/service/dsp_prod_service.yml @@ -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 + diff --git a/config/service/dsp_test_service.yml b/config/service/dsp_test_service.yml new file mode 100644 index 0000000..2c1b091 --- /dev/null +++ b/config/service/dsp_test_service.yml @@ -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: 1 + #是否启用mqtt,0--不用,1--启用 + mqtt_flag: 0 + #是否启用alg控制功能 + algSwitch: false + diff --git a/dsp_master.py b/dsp_master.py new file mode 100644 index 0000000..b83977f --- /dev/null +++ b/dsp_master.py @@ -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) diff --git a/entity/FeedBack.py b/entity/FeedBack.py new file mode 100644 index 0000000..0ce6cf8 --- /dev/null +++ b/entity/FeedBack.py @@ -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() + }} diff --git a/entity/PullStreamDto.py b/entity/PullStreamDto.py new file mode 100644 index 0000000..b3b3533 --- /dev/null +++ b/entity/PullStreamDto.py @@ -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 + diff --git a/entity/__init__.py b/entity/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/entity/__pycache__/FeedBack.cpython-38.pyc b/entity/__pycache__/FeedBack.cpython-38.pyc new file mode 100644 index 0000000..0785694 Binary files /dev/null and b/entity/__pycache__/FeedBack.cpython-38.pyc differ diff --git a/entity/__pycache__/__init__.cpython-38.pyc b/entity/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..40746d9 Binary files /dev/null and b/entity/__pycache__/__init__.cpython-38.pyc differ diff --git a/enums/AnalysisStatusEnum.py b/enums/AnalysisStatusEnum.py new file mode 100644 index 0000000..ac30040 --- /dev/null +++ b/enums/AnalysisStatusEnum.py @@ -0,0 +1,21 @@ +from enum import Enum, unique + + +# 分析状态枚举 +@unique +class AnalysisStatus(Enum): + + # 等待 + WAITING = "waiting" + + # 分析中 + RUNNING = "running" + + # 分析完成 + SUCCESS = "success" + + # 超时 + TIMEOUT = "timeout" + + # 失败 + FAILED = "failed" diff --git a/enums/AnalysisTypeEnum.py b/enums/AnalysisTypeEnum.py new file mode 100644 index 0000000..6172d2a --- /dev/null +++ b/enums/AnalysisTypeEnum.py @@ -0,0 +1,25 @@ +from enum import Enum, unique + + +# 分析类型枚举 +@unique +class AnalysisType(Enum): + # 在线 + ONLINE = "1" + + # 离线 + OFFLINE = "2" + + # 图片 + IMAGE = "3" + + # 录屏 + RECORDING = "9999" + + # 转推流 + PULLTOPUSH = "10000" + + + + + diff --git a/enums/BaiduSdkEnum.py b/enums/BaiduSdkEnum.py new file mode 100644 index 0000000..8ea05cd --- /dev/null +++ b/enums/BaiduSdkEnum.py @@ -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 ,建议长宽比3:1以内,图片请求格式支持:PNG、JPG、BMP", 1, 0) + + SDK_IMAGE_LENGTH_ERROR = ('SDK101', "image length error", "图片边长不符合要求,最短边至少50px,最长边最大4096px ,建议长宽比3:1以内", 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 +} \ No newline at end of file diff --git a/enums/ExceptionEnum.py b/enums/ExceptionEnum.py new file mode 100644 index 0000000..59859b7 --- /dev/null +++ b/enums/ExceptionEnum.py @@ -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", "系统内部异常!") diff --git a/enums/ModelTypeEnum.py b/enums/ModelTypeEnum.py new file mode 100644 index 0000000..e3d473a --- /dev/null +++ b/enums/ModelTypeEnum.py @@ -0,0 +1,812 @@ +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, + #车辆","垃圾","商贩","裸土","占道经营","违停"---> + #"车辆","垃圾","商贩","违停","占道经营","裸土" + 'classReindex':{ 0:0,1:1,2:2,3:5,4:4,5:3} + } + }, + '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],'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.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 diff --git a/enums/ModelTypeEnum2.py b/enums/ModelTypeEnum2.py new file mode 100644 index 0000000..7e796c0 --- /dev/null +++ b/enums/ModelTypeEnum2.py @@ -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 diff --git a/enums/RecordingStatusEnum.py b/enums/RecordingStatusEnum.py new file mode 100644 index 0000000..c7bcad7 --- /dev/null +++ b/enums/RecordingStatusEnum.py @@ -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", "录制失败") diff --git a/enums/StatusEnum.py b/enums/StatusEnum.py new file mode 100644 index 0000000..0a8c4b3 --- /dev/null +++ b/enums/StatusEnum.py @@ -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, "失败") diff --git a/enums/__init__.py b/enums/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/enums/__pycache__/AnalysisStatusEnum.cpython-38.pyc b/enums/__pycache__/AnalysisStatusEnum.cpython-38.pyc new file mode 100644 index 0000000..f571b45 Binary files /dev/null and b/enums/__pycache__/AnalysisStatusEnum.cpython-38.pyc differ diff --git a/enums/__pycache__/AnalysisTypeEnum.cpython-38.pyc b/enums/__pycache__/AnalysisTypeEnum.cpython-38.pyc new file mode 100644 index 0000000..2e06f47 Binary files /dev/null and b/enums/__pycache__/AnalysisTypeEnum.cpython-38.pyc differ diff --git a/enums/__pycache__/BaiduSdkEnum.cpython-310.pyc b/enums/__pycache__/BaiduSdkEnum.cpython-310.pyc new file mode 100644 index 0000000..d3391b0 Binary files /dev/null and b/enums/__pycache__/BaiduSdkEnum.cpython-310.pyc differ diff --git a/enums/__pycache__/BaiduSdkEnum.cpython-38.pyc b/enums/__pycache__/BaiduSdkEnum.cpython-38.pyc new file mode 100644 index 0000000..e79c754 Binary files /dev/null and b/enums/__pycache__/BaiduSdkEnum.cpython-38.pyc differ diff --git a/enums/__pycache__/ExceptionEnum.cpython-310.pyc b/enums/__pycache__/ExceptionEnum.cpython-310.pyc new file mode 100644 index 0000000..f05bf3b Binary files /dev/null and b/enums/__pycache__/ExceptionEnum.cpython-310.pyc differ diff --git a/enums/__pycache__/ExceptionEnum.cpython-38.pyc b/enums/__pycache__/ExceptionEnum.cpython-38.pyc new file mode 100644 index 0000000..e2126d1 Binary files /dev/null and b/enums/__pycache__/ExceptionEnum.cpython-38.pyc differ diff --git a/enums/__pycache__/ModelTypeEnum.cpython-38.pyc b/enums/__pycache__/ModelTypeEnum.cpython-38.pyc new file mode 100644 index 0000000..9dd09f3 Binary files /dev/null and b/enums/__pycache__/ModelTypeEnum.cpython-38.pyc differ diff --git a/enums/__pycache__/ModelTypeEnum2.cpython-38.pyc b/enums/__pycache__/ModelTypeEnum2.cpython-38.pyc new file mode 100644 index 0000000..b4815eb Binary files /dev/null and b/enums/__pycache__/ModelTypeEnum2.cpython-38.pyc differ diff --git a/enums/__pycache__/RecordingStatusEnum.cpython-38.pyc b/enums/__pycache__/RecordingStatusEnum.cpython-38.pyc new file mode 100644 index 0000000..b7c0f70 Binary files /dev/null and b/enums/__pycache__/RecordingStatusEnum.cpython-38.pyc differ diff --git a/enums/__pycache__/StatusEnum.cpython-38.pyc b/enums/__pycache__/StatusEnum.cpython-38.pyc new file mode 100644 index 0000000..ec5fb91 Binary files /dev/null and b/enums/__pycache__/StatusEnum.cpython-38.pyc differ diff --git a/enums/__pycache__/__init__.cpython-310.pyc b/enums/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..d0c53ad Binary files /dev/null and b/enums/__pycache__/__init__.cpython-310.pyc differ diff --git a/enums/__pycache__/__init__.cpython-38.pyc b/enums/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..17fbca0 Binary files /dev/null and b/enums/__pycache__/__init__.cpython-38.pyc differ diff --git a/exception/CustomerException.py b/exception/CustomerException.py new file mode 100644 index 0000000..08cab3b --- /dev/null +++ b/exception/CustomerException.py @@ -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) + + + diff --git a/exception/__init__.py b/exception/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/exception/__pycache__/CustomerException.cpython-310.pyc b/exception/__pycache__/CustomerException.cpython-310.pyc new file mode 100644 index 0000000..b3b91b5 Binary files /dev/null and b/exception/__pycache__/CustomerException.cpython-310.pyc differ diff --git a/exception/__pycache__/CustomerException.cpython-38.pyc b/exception/__pycache__/CustomerException.cpython-38.pyc new file mode 100644 index 0000000..473fc42 Binary files /dev/null and b/exception/__pycache__/CustomerException.cpython-38.pyc differ diff --git a/exception/__pycache__/__init__.cpython-310.pyc b/exception/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..80858e8 Binary files /dev/null and b/exception/__pycache__/__init__.cpython-310.pyc differ diff --git a/exception/__pycache__/__init__.cpython-38.pyc b/exception/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..5fb7efd Binary files /dev/null and b/exception/__pycache__/__init__.cpython-38.pyc differ diff --git a/font/__init__.py b/font/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/font/simsun.ttc b/font/simsun.ttc new file mode 100644 index 0000000..40e9693 Binary files /dev/null and b/font/simsun.ttc differ diff --git a/image/logo.png b/image/logo.png new file mode 100644 index 0000000..d91cba4 Binary files /dev/null and b/image/logo.png differ diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..e3c3122 --- /dev/null +++ b/readme.md @@ -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.04.26 + (1)代码更新路径到gitadmin diff --git a/scpCode.sh b/scpCode.sh new file mode 100644 index 0000000..a16c2f5 --- /dev/null +++ b/scpCode.sh @@ -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 diff --git a/service/Dispatcher.py b/service/Dispatcher.py new file mode 100644 index 0000000..0641c05 --- /dev/null +++ b/service/Dispatcher.py @@ -0,0 +1,482 @@ +# -*- 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): + 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"}) + + # 新增该函数用于,向子任务发送命令(algStart,algStop) + 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): + 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) + + ''' + 在线分析逻辑 + ''' + + 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 offline(self, message, analysisType): + 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", [])}) diff --git a/service/__init__.py b/service/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/service/__pycache__/Dispatcher.cpython-310.pyc b/service/__pycache__/Dispatcher.cpython-310.pyc new file mode 100644 index 0000000..060bc19 Binary files /dev/null and b/service/__pycache__/Dispatcher.cpython-310.pyc differ diff --git a/service/__pycache__/Dispatcher.cpython-38.pyc b/service/__pycache__/Dispatcher.cpython-38.pyc new file mode 100644 index 0000000..1919f51 Binary files /dev/null and b/service/__pycache__/Dispatcher.cpython-38.pyc differ diff --git a/service/__pycache__/__init__.cpython-310.pyc b/service/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..d0d3a66 Binary files /dev/null and b/service/__pycache__/__init__.cpython-310.pyc differ diff --git a/service/__pycache__/__init__.cpython-38.pyc b/service/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..a52c2a3 Binary files /dev/null and b/service/__pycache__/__init__.cpython-38.pyc differ diff --git a/start.sh b/start.sh new file mode 100644 index 0000000..606bd68 --- /dev/null +++ b/start.sh @@ -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 \ No newline at end of file diff --git a/stop.sh b/stop.sh new file mode 100644 index 0000000..5512a80 --- /dev/null +++ b/stop.sh @@ -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 \ No newline at end of file diff --git a/t.txt b/t.txt new file mode 100644 index 0000000..20a1df7 --- /dev/null +++ b/t.txt @@ -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 diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000..b346b0f --- /dev/null +++ b/test/__init__.py @@ -0,0 +1,3 @@ + +dd = {} +print(dd.get('name', 'aaa')) \ No newline at end of file diff --git a/test/__pycache__/__init__.cpython-38.pyc b/test/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..1335fd3 Binary files /dev/null and b/test/__pycache__/__init__.cpython-38.pyc differ diff --git a/test/aliyun/__init__.py b/test/aliyun/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/aliyun/aaa.jpeg b/test/aliyun/aaa.jpeg new file mode 100644 index 0000000..620fd55 Binary files /dev/null and b/test/aliyun/aaa.jpeg differ diff --git a/test/aliyun/ossdemo.py b/test/aliyun/ossdemo.py new file mode 100644 index 0000000..c22d771 --- /dev/null +++ b/test/aliyun/ossdemo.py @@ -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。 + 对于CentOS、RHEL、Fedora系统,请执行以下命令安装python-devel。 + sudo yum install python-devel + 对于Debian,Ubuntu系统,请执行以下命令安装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 + diff --git a/test/aliyun/vod.py b/test/aliyun/vod.py new file mode 100644 index 0000000..57733d5 --- /dev/null +++ b/test/aliyun/vod.py @@ -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('') + # 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('') +# # 标签 +# # 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) \ No newline at end of file diff --git a/test/aliyun/vodTest.py b/test/aliyun/vodTest.py new file mode 100644 index 0000000..903b050 --- /dev/null +++ b/test/aliyun/vodTest.py @@ -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('') + # 标签 + # 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)) \ No newline at end of file diff --git a/test/aliyun/voddemo.py b/test/aliyun/voddemo.py new file mode 100644 index 0000000..51378a8 --- /dev/null +++ b/test/aliyun/voddemo.py @@ -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) + + + diff --git a/test/aliyun/vodtest1.py b/test/aliyun/vodtest1.py new file mode 100644 index 0000000..2149c8e --- /dev/null +++ b/test/aliyun/vodtest1.py @@ -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"]) \ No newline at end of file diff --git a/test/aliyun/vodtest2.py b/test/aliyun/vodtest2.py new file mode 100644 index 0000000..f767f18 --- /dev/null +++ b/test/aliyun/vodtest2.py @@ -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()) \ No newline at end of file diff --git a/test/collections/ChainMap.py b/test/collections/ChainMap.py new file mode 100644 index 0000000..fb0d8ec --- /dev/null +++ b/test/collections/ChainMap.py @@ -0,0 +1,55 @@ + + + +""" +1、ChainMap是什么 +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) diff --git a/test/collections/Counter.py b/test/collections/Counter.py new file mode 100644 index 0000000..dd91abb --- /dev/null +++ b/test/collections/Counter.py @@ -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)) + +""" +1、elements() +描述:返回一个迭代器,其中每个元素将重复出现计数值所指定次。 元素会按首次出现的顺序返回。 如果一个元素的计数值小于1,elements() 将会忽略它。 +语法: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())) + +""" +2、most_common() +返回一个列表,其中包含n个最常见的元素及出现次数,按常见程度由高到低排序。 +如果n被省略或为None,most_common() 将返回计数器中的所有元素, +计数值相等的元素按首次出现的顺序排序,经常用来计算top词频的词语。 +""" +print(Counter('abracadabra').most_common(3)) +print(Counter('abracadabra').most_common(5)) + +""" +3、subtract() +从迭代对象或映射对象减去元素。像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) diff --git a/test/collections/OrderedDict.py b/test/collections/OrderedDict.py new file mode 100644 index 0000000..ffe5842 --- /dev/null +++ b/test/collections/OrderedDict.py @@ -0,0 +1,35 @@ +from collections import OrderedDict + + +""" +1、popitem +语法: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)) + +""" +2、move_to_end +""" +d = OrderedDict.fromkeys('abcde') +d.move_to_end('b') +print(d) +d.move_to_end('b', last=False) +print(d) + +""" +3、reversed() +相对于通常的映射方法,有序字典还另外提供了逆序迭代的支持,通过reversed()。 +""" +d = OrderedDict.fromkeys('acbde') +print(d) +print(list(reversed(d))) + +c = OrderedDict({'a': 1, 'c': 2, 'b': 3}) +print(c) \ No newline at end of file diff --git a/test/collections/__init__.py b/test/collections/__init__.py new file mode 100644 index 0000000..ecaf0a7 --- /dev/null +++ b/test/collections/__init__.py @@ -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] diff --git a/test/collections/defaultdict.py b/test/collections/defaultdict.py new file mode 100644 index 0000000..e6a6e09 --- /dev/null +++ b/test/collections/defaultdict.py @@ -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']) + diff --git a/test/collections/deque.py b/test/collections/deque.py new file mode 100644 index 0000000..1c98a64 --- /dev/null +++ b/test/collections/deque.py @@ -0,0 +1,148 @@ + +""" +deque +双端队列,可以快速的从另外一侧追加和推出对象,deque是一个双向链表, +针对list连续的数据结构插入和删除进行优化。它提供了两端都可以操作的序列, +这表示在序列的前后你都可以执行添加或删除操作。双向队列(deque)对象支持以下方法: +""" +from collections import deque + +""" +1、append() +添加 x 到右端。 +""" +d = deque('ghi') +d.append('j') +print(d) + +""" +2、appendleft() +添加 x 到左端。 +""" +d.appendleft('f') +print(d) + +""" +3、clear() +移除所有元素,使其长度为0. +""" +d = deque('ghi') +d.clear() +print(d) + +""" +4、copy() +创建一份浅拷贝。 +""" +d = deque('xiaoweuge') +y = d.copy() +print(y) + +""" +5、count() +计算 deque 中元素等于 x 的个数。 +""" +d = deque('xiaoweuge-shuai') +print(d.count('a')) + +""" +6、extend() +扩展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) + +""" +7、extendleft() +扩展deque的左侧,通过添加iterable参数中的元素。注意,左添加时,在结果中iterable参数中的顺序将被反过来添加。 +""" +a = deque('abc') +b = deque('cd') +a.extendleft(b) +print(a) + +""" +8、index() +返回 x 在 deque 中的位置(在索引 start 之后,索引 stop 之前)。 返回第一个匹配项,如果未找到则引发 ValueError。 +""" +d = deque('xiaoweuge') +print(d.index('w')) + +""" +9、insert() +在位置 i 插入 x 。 +如果插入会导致一个限长 deque 超出长度 maxlen 的话,就引发一个 IndexError。 +""" +a = deque('abc') +a.insert(1, 'X') +print(a) + +""" +10、pop() +移去并且返回一个元素,deque 最右侧的那一个。 如果没有元素的话,就引发一个 IndexError。 +""" +d = deque('abc') +print(d.pop()) + +""" +11、popleft() +移去并且返回一个元素,deque 最左侧的那一个。 如果没有元素的话,就引发 IndexError。 +""" +d = deque('abc') +print(d.popleft()) + +""" +12、remove(value) +移除找到的第一个 value。 如果没有的话就引发 ValueError。 +""" +a = deque('abca') +a.remove('a') +print(a) + +""" +13、reverse() +将deque逆序排列。返回 None 。 +""" +#逆序排列 +d = deque('ghi') # 创建一个deque +print(list(reversed(d))) + +""" +14、rotate(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) + +""" +15、maxlen +Deque的最大尺寸,如果没有限定的话就是 None 。 +""" +d=deque(maxlen=10) +for i in range(20): + d.append(i) +print(d) \ No newline at end of file diff --git a/test/collections/namedtuple.py b/test/collections/namedtuple.py new file mode 100644 index 0000000..884b79e --- /dev/null +++ b/test/collections/namedtuple.py @@ -0,0 +1,83 @@ + + +from collections import namedtuple + +""" +可命名元组-namedtuple +生成可以使用名字来访问元素内容的tuple子类,命名元组赋予每个位置一个含义,提供可读性和自文档性。 +它们可以用于任何普通元组,并添加了通过名字获取值的能力,通过索引值也是可以的。 +1、参数介绍 +namedtuple(typename,field_names,*,verbose=False, rename=False, module=None) +1)typename:该参数指定所创建的tuple子类的类名,相当于用户定义了一个新类。 +2)field_names:该参数是一个字符串序列,如 ['x','y']。此外,field_names 也可直接使用单个字符串代表所有字段名,多个字段名用空格、逗号隔开,如 'x y' 或 'x,y'。任何有效的 Python 标识符都可作为字段名(不能以下画线开头)。有效的标识符可由字母、数字、下画线组成,但不能以数字、下面线开头,也不能是关键字(如 return、global、pass、raise 等)。 +3)rename:如果将该参数设为 True,那么无效的字段名将会被自动替换为位置名。例如指定 ['abc','def','ghi','abc'],它将会被替换为 ['abc', '_1','ghi','_3'],这是因为 def 字段名是关键字,而 abc 字段名重复了。 +4)verbose:如果该参数被设为 True,那么当该子类被创建后,该类定义就被立即打印出来。 +5)module:如果设置了该参数,那么该类将位于该模块下,因此该自定义类的 __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')) \ No newline at end of file diff --git a/test/color/__init__.py b/test/color/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/color/color_test.py b/test/color/color_test.py new file mode 100644 index 0000000..f421c1e --- /dev/null +++ b/test/color/color_test.py @@ -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) diff --git a/test/color/platech.ttf b/test/color/platech.ttf new file mode 100644 index 0000000..d66a970 Binary files /dev/null and b/test/color/platech.ttf differ diff --git a/test/cpu/__init__.py b/test/cpu/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/cpu/test.py b/test/cpu/test.py new file mode 100644 index 0000000..8c8c080 --- /dev/null +++ b/test/cpu/test.py @@ -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())) + + diff --git a/test/cuda/__init__.py b/test/cuda/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/cuda/test.py b/test/cuda/test.py new file mode 100644 index 0000000..56de0cc --- /dev/null +++ b/test/cuda/test.py @@ -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) diff --git a/test/cuda/test1.py b/test/cuda/test1.py new file mode 100644 index 0000000..3613b74 --- /dev/null +++ b/test/cuda/test1.py @@ -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) \ No newline at end of file diff --git a/test/demo/__init__.py b/test/demo/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/demo/demo1.py b/test/demo/demo1.py new file mode 100644 index 0000000..0be8b68 --- /dev/null +++ b/test/demo/demo1.py @@ -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() + + + + + + diff --git a/test/demo/demo2.py b/test/demo/demo2.py new file mode 100644 index 0000000..1d37fed --- /dev/null +++ b/test/demo/demo2.py @@ -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() + + + + + diff --git a/test/demo/demo3.py b/test/demo/demo3.py new file mode 100644 index 0000000..c7e508a --- /dev/null +++ b/test/demo/demo3.py @@ -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)) \ No newline at end of file diff --git a/test/demo/demo4.py b/test/demo/demo4.py new file mode 100644 index 0000000..56d87f8 --- /dev/null +++ b/test/demo/demo4.py @@ -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) + diff --git a/test/demo/demo5.py b/test/demo/demo5.py new file mode 100644 index 0000000..e1ff745 --- /dev/null +++ b/test/demo/demo5.py @@ -0,0 +1,16 @@ +import multiprocessing as mp + + +def aa1(aa2): + print("1111111111", id(aa2), aa2) + + +aa = [1, 2, 3, 4, 5, 6] +print(id(aa)) +# num = mp.Array('i', aa) +p = mp.Process(target=aa1, args=(aa,)) +p1 = mp.Process(target=aa1, args=(aa,)) +p2 = mp.Process(target=aa1, args=(aa,)) +p.start() +p1.start() +p2.start() diff --git a/test/demo/demo6.py b/test/demo/demo6.py new file mode 100644 index 0000000..be70d1b --- /dev/null +++ b/test/demo/demo6.py @@ -0,0 +1,25 @@ +import multiprocessing +from multiprocessing import Process, Lock, Queue +import time +import sys; print('Python %s on %s' % (sys.version, sys.platform)) +sys.path.extend([r'D:\tuoheng\codenew\update\tuoheng_alg\test\demo\demo6.py']) +# 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() +def add_one(aaa): + aaa.put("111111111") + aaa.cancel_join_thread() + + +if __name__ == '__main__': + aa = Queue() + + p1 = Process(target=add_one, args=(aa,)) + p1.start() + time.sleep(2) + print(aa.get()) + + diff --git a/test/demo/demo7.py b/test/demo/demo7.py new file mode 100644 index 0000000..7ba29b8 --- /dev/null +++ b/test/demo/demo7.py @@ -0,0 +1,167 @@ +import multiprocessing as mp +import sys +import time +from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor, wait, ALL_COMPLETED +from multiprocessing import Queue + +import cv2 +import tensorrt as trt +sys.path.extend(['/home/th/tuo_heng/dev/tuoheng_alg', '/home/th/tuo_heng/dev/tuoheng_alg/util']) +from util.PlotsUtils import get_label_arrays +from util.TorchUtils import select_device + +sys.path.extend(['/home/th/tuo_heng/', '/home/th/tuo_heng/dev', '/home/th/tuo_heng/dev/AIlib2', '/home/th/tuo_heng/dev/AIlib2/segutils']) +from segutils.segmodel import SegModel +from models.experimental import attempt_load +from AI import AI_process +from utilsK.queRiver import riverDetSegMixProcess + +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]) +par = { + 'device': '0', + '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': "/home/th/tuo_heng/dev/AIlib2/weights/river/yolov5_2080Ti_fp16.engine", + 'Segweights': '/home/th/tuo_heng/dev/AIlib2/weights/river/stdc_360X640_2080Ti_fp16.engine' +} +mode, postPar, segPar = par.get('mode', 'others'), par.get('postPar'), par.get('segPar') +new_device = select_device(par.get('device')) +names = par['labelnames'] +half = new_device.type != 'cpu' +Detweights = par['Detweights'] +with open(Detweights, "rb") as f, trt.Runtime(trt.Logger(trt.Logger.ERROR)) as runtime: + model = runtime.deserialize_cuda_engine(f.read()) +Segweights = par['Segweights'] +if Segweights: + with open(Segweights, "rb") as f, trt.Runtime(trt.Logger(trt.Logger.ERROR)) as runtime: + segmodel = runtime.deserialize_cuda_engine(f.read()) +else: + segmodel = None +postFile = par['postFile'] +rainbows = postFile["rainbows"] +objectPar = { + 'half': half, + 'device': new_device, + 'conf_thres': postFile["conf_thres"], + 'ovlap_thres_crossCategory': postFile.get("ovlap_thres_crossCategory"), + 'iou_thres': postFile["iou_thres"], + 'allowedList': [], + 'segRegionCnt': par['segRegionCnt'], + 'trtFlag_det': par['trtFlag_det'], + 'trtFlag_seg': par['trtFlag_seg'] +} +Detweights = "/home/th/tuo_heng/dev/AIlib2/weights/river2/yolov5_2080Ti_fp16.engine" +with open(Detweights, "rb") as f, trt.Runtime(trt.Logger(trt.Logger.ERROR)) as runtime: + model = runtime.deserialize_cuda_engine(f.read()) +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()) + + +allowedList = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + + + +def one_label(width, height, model_param): + names = model_param[4] + rainbows = model_param[6] + digitFont, label_arraylist, font_config = get_label_arraylist(width, height, names, rainbows) + """ + font_config, frame, model, segmodel, names, label_arraylist, rainbows, objectPar, font, segPar, mode, postPar, + requestId + """ + model_param[5] = label_arraylist + model_param[8] = digitFont + model_param[0] = font_config + + +def get_label_arraylist(*args): + width, height, names, rainbows = args + # line = int(round(0.002 * (height + width) / 2) + 1) + line = int(width / 1920 * 3 - 1) + label = ' 0.95' + tf = max(line, 1) + fontScale = line * 0.33 + text_width, text_height = cv2.getTextSize(label, 0, fontScale=fontScale, thickness=tf)[0] + fontsize = int(width / 1920 * 40) + numFontSize = float(format(width / 1920 * 1.1, '.1f')) + digitFont = {'line_thickness': line, + 'boxLine_thickness': line, + 'fontSize': numFontSize, + 'waterLineColor': (0, 255, 255), + 'segLineShow': False, + 'waterLineWidth': line} + label_arraylist = get_label_arrays(names, rainbows, text_height, fontSize=fontsize, + fontPath="/home/th/tuo_heng/dev/AIlib2/conf/platech.ttf") + return digitFont, label_arraylist, (line, text_width, text_height, fontScale, tf) +image = cv2.imread("/home/th/tuo_heng/dev/ompv2fn94m_1687259193110.jpg") +start_time1 = time.time() +with ThreadPoolExecutor(max_workers=3) as t: + rs = [] + for i in range(500): + rr = t.submit(AI_process, [image], model, segmodel, names, None, rainbows, objectPar=objectPar, + font={'line_thickness': 1, + 'boxLine_thickness': 1, + 'fontSize': 1.1, + 'waterLineColor': (0, 255, 255), + 'segLineShow': False, + 'waterLineWidth': 1}, segPar=segPar, mode=mode, postPar=postPar) + rs.append(rr) + for i in rs: + i.result() +print(time.time() - start_time1) + +start_time = time.time() +for i in range(500): + AI_process([image], model, segmodel, names, None, rainbows, objectPar=objectPar, + font={'line_thickness': 1, + 'boxLine_thickness': 1, + 'fontSize': 1.1, + 'waterLineColor': (0, 255, 255), + 'segLineShow': False, + 'waterLineWidth': 1}, segPar=segPar, mode=mode, postPar=postPar) +print(time.time() - start_time) diff --git a/test/demo/demo8.py b/test/demo/demo8.py new file mode 100644 index 0000000..8d05ffa --- /dev/null +++ b/test/demo/demo8.py @@ -0,0 +1,10 @@ +import cv2 +from PIL import ImageFont + +label = ' 0.95' +# fontScale=fontScale, thickness=tf +text_width, text_height = cv2.getTextSize(label, 0, fontScale=1, thickness=1)[0] +print(text_height) +font = ImageFont.truetype("/home/th/tuo_heng/dev/AIlib2/conf/platech.ttf", 22, encoding='utf-8') +x, y, width, height = font.getbbox("植被") +print(x, y, width, height) \ No newline at end of file diff --git a/test/demo1.py b/test/demo1.py new file mode 100644 index 0000000..9ff5613 --- /dev/null +++ b/test/demo1.py @@ -0,0 +1,130 @@ +# -*- coding: utf-8 -*- +import datetime +import time + +import json + +from aliyunsdkcore.client import AcsClient +from aliyunsdkvod.request.v20170321 import GetPlayInfoRequest +from loguru import logger + +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 +5. 视频域名地址:https://vod.play.t-aaron.com/ +''' + + +class AliyunVodSdk: + + def __init__(self, requestId): + self.__client = None + self.__access_key = 'LTAI5tMiefafZ6br4zmrQWv9' + self.__access_secret = 'JgzQjSCkwZ7lefZO6egOArw38YH1Tk' + self.__regionId = "cn-shanghai" + self.__cateId = '1000468340' + self.__requestId = requestId + + def init_vod_client(self): + return AcsClient(self.__access_key, self.__access_secret, self.__regionId, auto_retry=True, max_retry_time=3, timeout=30) + + ''' + 根据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)): + logger.exception("获取视频地址失败: {}", e) + raise e + diff_time = current_time - start + if diff_time > 60 * 60 * 5: + logger.exception("获取视频地址失败超时异常: {},超时时间:{}", str(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, self.__requestId) + 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 Exception as e: + retry_count += 1 + time.sleep(1) + logger.error("vod视频上传失败,重试次数:{}", retry_count) + if retry_count >= MAX_RETRIES: + logger.exception("vod视频上传重试失败: {}", str(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\\111.mp4' + codClinet = AliyunVodSdk("1111111") + result = codClinet.upload_local_video(filePath, 'aiOnLineVideo') + print(result) + url = codClinet.get_play_info(result) + print(url) + + + + diff --git a/test/dsp/logs/dsp.log b/test/dsp/logs/dsp.log new file mode 100644 index 0000000..402e4f4 --- /dev/null +++ b/test/dsp/logs/dsp.log @@ -0,0 +1,7 @@ +2023-04-18 13:41:42.066 [ERROR][MainProcess-25160-MainThread-30168][16] Test- - 异常信息:division by zero +Traceback (most recent call last): + +> File "D:\tuoheng\codenew\tuoheng_alg\test\路径\Test.py", line 14, in + 2/0 + +ZeroDivisionError: division by zero diff --git a/test/editimage/__init__.py b/test/editimage/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/editimage/editImage.py b/test/editimage/editImage.py new file mode 100644 index 0000000..b8e0755 --- /dev/null +++ b/test/editimage/editImage.py @@ -0,0 +1,45 @@ +from io import BytesIO + +import cv2 +import matplotlib.pyplot as plt +import matplotlib.patches as pat +import numpy as np +import requests +from PIL import ImageDraw, Image + +from util.ImageUtils import url2Array + +url = "https://www.2008php.com/2015_Website_appreciate/2015-12-06/20151206234254.jpg" + +color= (255, 255, 0) +#( 蓝, 绿, 红) +# 红色 (0, 0, 255) +# 洋红色 (255, 0, 255) +# 青色 (255, 255, 0) +# 黑色 (0, 0, 0) +# 蓝色 (255, 0, 0) +# 绿色 (0, 255, 0) +# 黄色 (0, 255, 255) # 不考虑 +img = url2Array(url) +cv2.putText(img,"Hello World", (100,100), cv2.FONT_HERSHEY_SIMPLEX, 1.0,color, 1, cv2.LINE_AA) +# rectangle 坐标的参数格式为左上角(x1, y1),右下角(x2, y2), 颜色 , 粗细 +cv2.rectangle(img, (100, 110), (400, 310), color, 2) +cv2.imshow('img', img) +cv2.waitKey() + +# fig, ax = plt.subplots(1) +# ax.imshow(img) +# # Rectangle 坐标的参数格式为左上角(x, y),width, height。 +# rec = pat.Rectangle((386, 144), 1049, 760, linewidth=2, edgecolor='r', facecolor='None') +# ax.add_patch(rec) +# plt.imshow(img) +# plt.show() +# response = requests.get(url) +# image = Image.open(BytesIO(response.content)) +# a = ImageDraw.ImageDraw(image) +# # rectangle 坐标的参数格式为左上角(x1, y1),右下角(x2, y2)。 +# a.rectangle(((386, 144), (1435, 904)), fill=None, outline='red', width=2) +# image.show() + + + diff --git a/test/ffmpeg11/Test.py b/test/ffmpeg11/Test.py new file mode 100644 index 0000000..ee2e272 --- /dev/null +++ b/test/ffmpeg11/Test.py @@ -0,0 +1,843 @@ +import sys, yaml +from easydict import EasyDict as edict +from concurrent.futures import ThreadPoolExecutor + +sys.path.extend(['..','../AIlib2' ]) + +from AI import AI_process,AI_process_forest,get_postProcess_para,get_postProcess_para_dic,ocr_process,AI_det_track,AI_det_track_batch +import cv2,os,time +from segutils.segmodel import SegModel +from segutils.segmodel import SegModel +from segutils.trafficUtils import tracfficAccidentMixFunction +from models.experimental import attempt_load +from utils.torch_utils import select_device +from utilsK.queRiver import get_labelnames,get_label_arrays,save_problem_images,riverDetSegMixProcess +from ocrUtils.ocrUtils import CTCLabelConverter,AlignCollate +from trackUtils.sort import Sort,track_draw_boxAndTrace,track_draw_trace_boxes,moving_average_wang,drawBoxTraceSimplied +from trackUtils.sort_obb import OBB_Sort,obbTohbb,track_draw_all_boxes,track_draw_trace +from obbUtils.shipUtils import OBB_infer,OBB_tracker,draw_obb,OBB_tracker_batch +from utilsK.noParkingUtils import mixNoParking_road_postprocess +from obbUtils.load_obb_model import load_model_decoder_OBB +import numpy as np +import torch,glob +import tensorrt as trt +from utilsK.masterUtils import get_needed_objectsIndex +from copy import deepcopy +from scipy import interpolate +from utilsK.drownUtils import mixDrowing_water_postprocess +#import warnings +#warnings.filterwarnings("error") + +def view_bar(num, total,time1,prefix='prefix'): + rate = num / total + time_n=time.time() + rate_num = int(rate * 30) + rate_nums = np.round(rate * 100) + r = '\r %s %d / %d [%s%s] %.2f s'%(prefix,num,total, ">" * rate_num, " " * (30 - rate_num), time_n-time1 ) + sys.stdout.write(r) + sys.stdout.flush() + + +''' + 多线程 +''' + +def process_v1(frame): + #try: + print('demo.py beging to :',frame[8]) + time00 = time.time() + H,W,C = frame[0][0].shape + + p_result,timeOut = AI_process(frame[0],frame[1],frame[2],frame[3],frame[4],frame[5],objectPar=frame[6],font=frame[7],segPar=frame[9],mode=frame[10],postPar=frame[11]) + + time11 = time.time() + image_array = p_result[1] + + cv2.imwrite(os.path.join('images/results/',frame[8] ) ,image_array) + bname = frame[8].split('.')[0] + if len(p_result)==5: + image_mask = p_result[4] + cv2.imwrite(os.path.join('images/results/',bname+'_mask.png' ) , (image_mask).astype(np.uint8)) + + boxes=p_result[2] + with open( os.path.join('images/results/',bname+'.txt' ),'w' ) as fp: + for box in boxes: + box_str=[str(x) for x in box] + out_str=','.join(box_str)+'\n' + fp.write(out_str) + time22 = time.time() + print('%s,%d*%d,AI-process: %.1f,image save:%.1f , %s'%(frame[8],H,W, (time11 - time00) * 1000.0, (time22-time11)*1000.0,timeOut), boxes) + return 'success' + #except Exception as e: + # return 'failed:'+str(e) +def process_video(video,par0,mode='detSeg'): + cap=cv2.VideoCapture(video) + if not cap.isOpened(): + print('#####error url:',video) + return False + bname=os.path.basename(video).split('.')[0] + fps = int(cap.get(cv2.CAP_PROP_FPS)+0.5) + width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH )+0.5) + height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)+0.5) + framecnt=int(cap.get(7)+0.5) + save_path_AI = os.path.join(par0['outpth'],os.path.basename(video)) + problem_image_dir= os.path.join( par0['outpth'], 'probleImages' ) + os.makedirs(problem_image_dir,exist_ok=True) + vid_writer_AI = cv2.VideoWriter(save_path_AI, cv2.VideoWriter_fourcc(*'mp4v'), fps, (width,height)) + num=0 + iframe=0;post_results=[];fpsample=30*10 + + imgarray_list = []; iframe_list = [] + + patch_cnt = par0['trackPar']['patchCnt'] + ##windowsize 对逐帧插值后的结果做平滑,windowsize为平滑的长度,没隔det_cnt帧做一次跟踪。 + trackPar={'det_cnt':10,'windowsize':29 } + + + ##track_det_result_update= np.empty((0,8)) ###每100帧跑出来的结果,放在track_det_result_update,只保留当前100帧里有的tracker Id. + while cap.isOpened(): + ret, imgarray = cap.read() #读取摄像头画面 + iframe +=1 + if not ret:break + if mode=='detSeg': + p_result,timeOut = AI_process([imgarray],par0['model'],par0['segmodel'],par0['names'],par0['label_arraylist'],par0['rainbows'],objectPar=par0['objectPar'],font=par0['digitFont'],segPar=par0['segPar']) + elif mode == 'track': + #sampleCount=10 + imgarray_list.append( imgarray ) + iframe_list.append(iframe ) + if iframe%patch_cnt==0: + time_patch0 = time.time() + retResults,timeInfos = AI_det_track_batch(imgarray_list, iframe_list ,par0['modelPar'],par0['processPar'],par0['sort_tracker'] ,par0['trackPar'],segPar=par0['segPar']) + #print('###line111:',retResults[2]) + ###需要保存成一个二维list,每一个list是一帧检测结果。 + ###track_det_result 内容格式:x1, y1, x2, y2, conf, cls,iframe,trackId + time_patch2 = time.time() + frame_min = iframe_list[0];frame_max=iframe_list[-1] + for iiframe in range(frame_min,frame_max+1): + img_draw = imgarray_list[ iiframe- frame_min ] + img_draw = drawBoxTraceSimplied(retResults[1] ,iiframe, img_draw,rainbows=par0['drawPar']['rainbows'],boxFlag=True,traceFlag=True,names=par0['drawPar']['names'] ) + ret = vid_writer_AI.write(img_draw) + view_bar(iiframe, framecnt,time.time(),prefix=os.path.basename(video)) + imgarray_list=[];iframe_list=[] + elif mode =='obbTrack': + imgarray_list.append( imgarray ) + iframe_list.append(iframe ) + if iframe%patch_cnt==0: + time_patch0 = time.time() + + track_det_results, timeInfos = OBB_tracker_batch(imgarray_list,iframe_list,par0['modelPar'],par0['obbModelPar'],par0['sort_tracker'],par0['trackPar'],segPar=None) + print( timeInfos ) + + #对结果画图 + track_det_np = track_det_results[1] + frame_min = iframe_list[0];frame_max=iframe_list[-1] + for iiframe in range(frame_min,frame_max+1): + img_draw = imgarray_list[ iiframe- frame_min ] + + if len( track_det_results[2][ iiframe- frame_min]) > 0: + img_draw = draw_obb( track_det_results[2][iiframe- frame_min ] ,img_draw,par0['drawPar']) + if True: + frameIdex=12;trackIdex=13; + boxes_oneFrame = track_det_np[ track_det_np[:,frameIdex]==iiframe ] + + ###在某一帧上,画上轨迹 + track_ids = boxes_oneFrame[:,trackIdex].tolist() + boxes_before_oneFrame = track_det_np[ track_det_np[:,frameIdex]<=iiframe ] + for trackId in track_ids: + boxes_before_oneFrame_oneId = boxes_before_oneFrame[boxes_before_oneFrame[:,trackIdex]==trackId] + xcs = boxes_before_oneFrame_oneId[:,8] + ycs = boxes_before_oneFrame_oneId[:,9] + [cv2.line(img_draw, ( int(xcs[i]) , int(ycs[i]) ), + ( int(xcs[i+1]),int(ycs[i+1]) ),(255,0,0), thickness=2) + for i,_ in enumerate(xcs) if i < len(xcs)-1 ] + + ret = vid_writer_AI.write(img_draw) + + #sys.exit(0) + #print('vide writer ret:',ret) + imgarray_list=[];iframe_list=[] + + view_bar(iframe, framecnt,time.time(),prefix=os.path.basename(video)) + + else: + p_result,timeOut = AI_process_forest([imgarray],par0['model'],par0['segmodel'],par0['names'],par0['label_arraylist'],par0['rainbows'],par0['half'],par0['device'],par0['conf_thres'], par0['iou_thres'],par0['allowedList'],font=par0['digitFont'],trtFlag_det=par0['trtFlag_det']) + + + if mode not in [ 'track','obbTrack']: + image_array = p_result[1];num+=1 + ret = vid_writer_AI.write(image_array) + view_bar(num, framecnt,time.time(),prefix=os.path.basename(video)) + ##每隔 fpsample帧处理一次,如果有问题就保存图片 + if (iframe % fpsample == 0) and (len(post_results)>0) : + parImage=save_problem_images(post_results,iframe,par0['names'],streamName=bname,outImaDir=problem_image_dir,imageTxtFile=False) + post_results=[] + + if len(p_result[2] )>0: + post_results.append(p_result) + + vid_writer_AI.release(); + +def det_track_demo(business, videopaths): + ''' + 跟踪参数说明: + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100} + sort_max_age--跟踪链断裂时允许目标消失最大的次数。超过之后,会认为是新的目标。 + sort_min_hits--每隔目标连续出现的次数,超过这个次数才认为是一个目标。 + sort_iou_thresh--检测最小的置信度。 + det_cnt--每隔几次做一个跟踪和检测,默认10。 + windowsize--轨迹平滑长度,一定是奇数,表示每隔几帧做一平滑,默认29。 + patchCnt--每次送入图像的数量,不宜少于100帧。 + ''' + + ''' 以下是基于检测和分割的跟踪模型,分割用来修正检测的结果''' + ####河道巡检的跟踪模型参数 + if opt['business'] == 'river' or opt['business'] == 'river2' : + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/%s/labelnames.json"%(opt['business']), ###检测类别对照表 + 'gpuname':'2080Ti',###显卡名称 + 'max_workers':1, ###并行线程数 + 'half':True, + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出 + + 'seg_nclass':2,###分割模型类别数目,默认2类 + 'segRegionCnt':0,###分割模型结果需要保留的等值线数目 + + '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}} #分割和检测混合处理的函数 + }, + + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + + 'Segweights' : "../weights/%s/AIlib2/%s/stdc_360X640_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/%s/para.json'%( opt['business'] ),###后处理参数文件 + 'txtFontSize':80,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':1.0,'waterLineColor':(0,255,255),'waterLineWidth':3},###显示框、线设置 + #'testImgPath':'images/videos/river',###测试图像的位置 + 'testImgPath':'images/tt',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + + } + + if opt['business'] == 'highWay2': + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/%s/labelnames.json"%( opt['business'] ), ###检测类别对照表 + 'half':True, + 'gpuname':'3090',###显卡名称 + 'max_workers':1, ###并行线程数 + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + #'Detweights':"../AIlib2/weights/conf/highWay2/yolov5.pt", + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,5,6,7,8,9] ],###控制哪些检测类别显示、输出 + 'seg_nclass':3,###分割模型类别数目,默认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':tracfficAccidentMixFunction, + '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 } + } + }, + + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'mode':'highWay3.0', + 'Segweights' : "../weights/%s/AIlib2/%s/stdc_360X640_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/%s/para.json'%(opt['business'] ),###后处理参数文件 + 'txtFontSize':20,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':0.5,'waterLineColor':(0,255,255),'segLineShow':True,'waterLineWidth':2},###显示框、线设置 + #'testImgPath':'images/trafficAccident/8.png',###测试图像的位置 + 'testImgPath':'images/noParking/',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + } + par['segPar']['mixFunction']['pars']['modelSize'] = par['segPar']['modelSize'] + if opt['business'] == 'noParking': + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/%s/labelnames.json"%( opt['business'] ), ###检测类别对照表 + 'half':True, + 'gpuname':'3090',###显卡名称 + 'max_workers':1, ###并行线程数 + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + #'Detweights':"../AIlib2/weights/conf/highWay2/yolov5.pt", + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,5,6,7,8,9] ],###控制哪些检测类别显示、输出 + 'seg_nclass':4,###分割模型类别数目,默认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':mixNoParking_road_postprocess, + 'pars': + #{ 'roundness': 0.3, 'cls': 9, 'laneArea': 10, 'laneAngleCha': 5 ,'RoadArea': 16000, } + + {'RoadArea': 16000, 'roadVehicleAngle': 15,'radius': 50, 'distanceFlag': False, 'vehicleFlag': False} + } + }, + + + + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'mode':'highWay3.0', + 'Segweights' : "../weights/%s/AIlib2/%s/stdc_360X640_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/%s/para.json'%('highWay2' ),###后处理参数文件 + 'txtFontSize':20,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':1.0,'waterLineColor':(0,255,255),'segLineShow':True,'waterLineWidth':2},###显示框、线设置 + 'testImgPath':'images/noParking/',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + } + par['segPar']['mixFunction']['pars']['modelSize'] = par['segPar']['modelSize'] + if opt['business'] == 'drowning': + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/%s/labelnames.json"%( opt['business'] ), ###检测类别对照表 + 'half':True, + 'gpuname':'3090',###显卡名称 + 'max_workers':1, ###并行线程数 + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + #'Detweights':"../AIlib2/weights/conf/highWay2/yolov5.pt", + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,5,6,7,8,9] ],###控制哪些检测类别显示、输出 + 'seg_nclass':2,###分割模型类别数目,默认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':{ } + } + }, + + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'Segweights' : "../weights/%s/AIlib2/%s/stdc_360X640_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/%s/para.json'%('highWay2' ),###后处理参数文件 + 'txtFontSize':20,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':1.0,'waterLineColor':(0,255,255),'segLineShow':True,'waterLineWidth':2},###显示框、线设置 + 'testImgPath':'images/drowning/',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + } + par['segPar']['mixFunction']['pars']['modelSize'] = par['segPar']['modelSize'] + + + ''' 以下是基于检测的跟踪模型,只有检测没有分割 ''' + if opt['business'] == 'forest2': + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/forest2/labelnames.json", ###检测类别对照表 + 'gpuname':opt['gpu'],###显卡名称 + 'max_workers':1, ###并行线程数 + 'half':True, + 'trtFlag_det':True,###检测模型是否采用TRT + 'trtFlag_seg':False,###分割模型是否采用TRT + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + #'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出 + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [] ], + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'seg_nclass':2,###分割模型类别数目,默认2类 + 'segRegionCnt':0,###分割模型结果需要保留的等值线数目 + 'segPar':None,###分割模型预处理参数 + 'Segweights' : None,###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/forest/para.json',###后处理参数文件 + 'txtFontSize':80,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':1.0,'waterLineColor':(0,255,255),'waterLineWidth':3},###显示框、线设置 + 'testImgPath':'../AIdemo2/images/forest2/',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + } + + ###车辆巡检参数 + if opt['business'] == 'vehicle': + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/vehicle/labelnames.json", ###检测类别对照表 + 'gpuname':'2080T',###显卡名称 + 'half':True, + 'max_workers':1, ###并行线程数 + 'trtFlag_det':True,###检测模型是否采用TRT + 'trtFlag_seg':False,###分割模型是否采用TRT + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出 + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'seg_nclass':2,###分割模型类别数目,默认2类 + 'segRegionCnt':0,###分割模型结果需要保留的等值线数目 + 'segPar':None,###分割模型预处理参数 + 'Segweights' : None,###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/vehicle/para.json',###后处理参数文件 + 'txtFontSize':40,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':1.0,'waterLineColor':(0,255,255),'waterLineWidth':3},###显示框、线设置 + 'testImgPath':'images/videos/vehicle/',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + } + ###行人检测模型 + if opt['business'] == 'pedestrian': + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/pedestrian/labelnames.json", ###检测类别对照表 + 'gpuname':'2080T',###显卡名称 + 'half':True, + 'max_workers':1, ###并行线程数 + 'trtFlag_det':True,###检测模型是否采用TRT + 'trtFlag_seg':False,###分割模型是否采用TRT + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出 + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'seg_nclass':2,###分割模型类别数目,默认2类 + 'segRegionCnt':0,###分割模型结果需要保留的等值线数目 + 'segPar':None,###分割模型预处理参数 + 'Segweights' : None,###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/pedestrian/para.json',###后处理参数文件 + 'txtFontSize':40,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':1.0,'waterLineColor':(0,255,255),'waterLineWidth':3},###显示框、线设置 + 'testImgPath':'../AIdemo2/images/pedestrian/',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + } + if opt['business'] == 'smogfire': + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/smogfire/labelnames.json", ###检测类别对照表 + 'gpuname':'2080T',###显卡名称 + 'half':True, + 'max_workers':1, ###并行线程数 + 'trtFlag_det':True,###检测模型是否采用TRT + 'trtFlag_seg':False,###分割模型是否采用TRT + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出 + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'seg_nclass':2,###没有分割模型,此处不用 + 'segRegionCnt':0,###没有分割模型,此处不用 + 'segPar':None,###分割模型预处理参数 + 'Segweights' : None,###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/smogfire/para.json',###后处理参数文件 + 'txtFontSize':40,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':1.0,'waterLineColor':(0,255,255),'waterLineWidth':3},###显示框、线设置 + 'testImgPath':'../AIdemo2/images/smogfire/',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + } + ###钓鱼游泳检测 + if opt['business'] == 'AnglerSwimmer': + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/AnglerSwimmer/labelnames.json", ###检测类别对照表 + 'gpuname':'2080T',###显卡名称 + 'half':True, + 'max_workers':1, ###并行线程数 + 'trtFlag_det':True,###检测模型是否采用TRT + 'trtFlag_seg':False,###分割模型是否采用TRT + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出 + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'seg_nclass':2,###没有分割模型,此处不用 + 'segRegionCnt':0,###没有分割模型,此处不用 + 'segPar':None,###分割模型预处理参数 + 'Segweights' : None,###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/AnglerSwimmer/para.json',###后处理参数文件 + 'txtFontSize':40,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':1.0,'waterLineColor':(0,255,255),'waterLineWidth':3},###显示框、线设置 + 'testImgPath':'../AIdemo2/images/AnglerSwimmer/',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + } + ###航道应急,做落水人员检测, channelEmergency + if opt['business'] == 'channelEmergency': + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/channelEmergency/labelnames.json", ###检测类别对照表 + 'gpuname':'2080T',###显卡名称 + 'half':True, + 'max_workers':1, ###并行线程数 + 'trtFlag_det':True,###检测模型是否采用TRT + 'trtFlag_seg':False,###分割模型是否采用TRT + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + #'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出 + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [] ],###控制哪些检测类别显示、输出 + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'seg_nclass':2,###没有分割模型,此处不用 + 'segRegionCnt':0,###没有分割模型,此处不用 + 'segPar':None,###分割模型预处理参数 + 'Segweights' : None,###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/channelEmergency/para.json',###后处理参数文件 + 'txtFontSize':40,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':1.0,'waterLineColor':(0,255,255),'waterLineWidth':3},###显示框、线设置 + 'testImgPath':'../AIdemo2/images/channelEmergency/',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + } + + ###乡村路违法种植 + if opt['business'] == 'countryRoad': + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/countryRoad/labelnames.json", ###检测类别对照表 + 'gpuname':'2080T',###显卡名称 + 'half':True, + 'max_workers':1, ###并行线程数 + 'trtFlag_det':True,###检测模型是否采用TRT + 'trtFlag_seg':False,###分割模型是否采用TRT + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出 + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'seg_nclass':2,###没有分割模型,此处不用 + 'segRegionCnt':0,###没有分割模型,此处不用 + 'segPar':None,###分割模型预处理参数 + 'Segweights' : None,###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/countryRoad/para.json',###后处理参数文件 + 'txtFontSize':40,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':1.0,'waterLineColor':(0,255,255),'waterLineWidth':3},###显示框、线设置 + 'testImgPath':'../AIdemo2/images/countryRoad/',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + } + + ###城管项目,检测城市垃圾和车辆 + if opt['business'] == 'cityMangement': + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/%s/labelnames.json"%(opt['business']), ###检测类别对照表 + 'gpuname':'2080Ti',###显卡名称 + 'half':True, + 'max_workers':1, ###并行线程数 + 'trtFlag_det':True,###检测模型是否采用TRT + 'trtFlag_seg':False,###分割模型是否采用TRT + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出 + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'seg_nclass':2,###没有分割模型,此处不用 + 'segRegionCnt':0,###没有分割模型,此处不用 + 'segPar':None,###分割模型预处理参数 + 'Segweights' : None,###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/%s/para.json'%(opt['business']),###后处理参数文件 + 'txtFontSize':40,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':1.0,'waterLineColor':(0,255,255),'waterLineWidth':3},###显示框、线设置 + 'testImgPath':'images/cityMangement',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + } + + + + par['trtFlag_det']=True if par['Detweights'].endswith('.engine') else False + if par['Segweights']: + par['segPar']['trtFlag_seg']=True if par['Segweights'].endswith('.engine') else False + + ##使用森林,道路模型,business 控制['forest','road'] + ##预先设置的参数 + gpuname=par['gpuname']#如果用trt就需要此参数,只能是"3090" "2080Ti" + device_=par['device'] ##选定模型,可选 cpu,'0','1' + + + device = select_device(device_) + half = device.type != 'cpu' # half precision only supported on CUDA + trtFlag_det=par['trtFlag_det'] ###是否采用TRT模型加速 + + ##以下参数目前不可改 + imageW=1080 ####道路模型 + digitFont= par['digitFont'] + + + ####加载检测模型 + if trtFlag_det: + Detweights=par['Detweights'] + logger = trt.Logger(trt.Logger.ERROR) + with open(Detweights, "rb") as f, trt.Runtime(logger) as runtime: + model=runtime.deserialize_cuda_engine(f.read())# 输入trt本地文件,返回ICudaEngine对象 + print('####load TRT model :%s'%(Detweights)) + else: + Detweights=par['Detweights'] + model = attempt_load(Detweights, map_location=device) # load FP32 model + if half: model.half() + + ####加载分割模型 + seg_nclass = par['seg_nclass'] + segPar=par['segPar'] + if par['Segweights']: + if par['segPar']['trtFlag_seg']: + Segweights = par['Segweights'] + logger = trt.Logger(trt.Logger.ERROR) + with open(Segweights, "rb") as f, trt.Runtime(logger) as runtime: + segmodel=runtime.deserialize_cuda_engine(f.read())# 输入trt本地文件,返回ICudaEngine对象 + print('############locad seg model trt success: ',Segweights) + else: + Segweights = par['Segweights'] + segmodel = SegModel(nclass=seg_nclass,weights=Segweights,device=device) + print('############locad seg model pth success:',Segweights) + else: + segmodel=None + + + trackPar=par['trackPar'] + sort_tracker = Sort(max_age=trackPar['sort_max_age'], + min_hits=trackPar['sort_min_hits'], + iou_threshold=trackPar['sort_iou_thresh']) + + + labelnames = par['labelnames'] + postFile= par['postFile'] + print( Detweights,labelnames ) + conf_thres,iou_thres,classes,rainbows=get_postProcess_para(postFile) + + detPostPar = get_postProcess_para_dic(postFile) + conf_thres,iou_thres,classes,rainbows = detPostPar["conf_thres"],detPostPar["iou_thres"],detPostPar["classes"],detPostPar["rainbows"] + if 'ovlap_thres_crossCategory' in detPostPar.keys(): iou2nd=detPostPar['ovlap_thres_crossCategory'] + else:iou2nd = None + + + ####模型选择参数用如下: + mode_paras=par['detModelpara'] + + allowedList,allowedList_string=get_needed_objectsIndex(mode_paras) + #slopeIndex = par['slopeIndex'] + ##只加载检测模型,准备好显示字符 + + names=get_labelnames(labelnames) + #imageW=4915;###默认是1920,在森林巡检的高清图像中是4920 + outfontsize=int(imageW/1920*40);### + label_arraylist = get_label_arrays(names,rainbows,outfontsize=par['txtFontSize'],fontpath="../AIlib2/conf/platech.ttf") + + + + + ##图像测试和视频 + outpth = par['testOutPath'] + impth = par['testImgPath'] + imgpaths=[]###获取文件里所有的图像 + videopaths=videopaths###获取文件里所有的视频 + img_postfixs = ['.jpg','.JPG','.PNG','.png']; + vides_postfixs= ['.MP4','.mp4','.avi'] + if os.path.isdir(impth): + for postfix in img_postfixs: + imgpaths.extend(glob.glob('%s/*%s'%(impth,postfix )) ) + for postfix in ['.MP4','.mp4','.avi']: + videopaths.extend(glob.glob('%s/*%s'%(impth,postfix )) ) + else: + postfix = os.path.splitext(impth)[-1] + if postfix in img_postfixs: imgpaths=[ impth ] + if postfix in vides_postfixs: videopaths = [impth ] + + + + + imgpaths.sort() + + + modelPar={ 'det_Model': model,'seg_Model':segmodel } + + processPar={'half':par['half'],'device':device,'conf_thres':conf_thres,'iou_thres':iou_thres,'trtFlag_det':trtFlag_det,'iou2nd':iou2nd} + drawPar={'names':names,'label_arraylist':label_arraylist,'rainbows':rainbows,'font': par['digitFont'],'allowedList':allowedList} + + for i in range(len(imgpaths)): + #for i in range(2): + #imgpath = os.path.join(impth, folders[i]) + imgpath = imgpaths[i] + bname = os.path.basename(imgpath ) + im0s=[cv2.imread(imgpath)] + time00 = time.time() + retResults,timeOut = AI_det_track_batch(im0s, [i] ,modelPar,processPar,sort_tracker ,trackPar,segPar) + #print('###line627:',retResults[2]) + #retResults,timeInfos = AI_det_track_batch(imgarray_list, iframe_list ,par0['modelPar'],par0['processPar'],par0['sort_tracker'] ,par0['trackPar'],segPar=par0['segPar']) + if len(retResults[1])>0: + retResults[0][0] = drawBoxTraceSimplied(retResults[1],i, retResults[0][0],rainbows=rainbows,boxFlag=True,traceFlag=False,names=drawPar['names']) + time11 = time.time() + image_array = retResults[0][0] + ''' + + 返回值retResults[2] --list,其中每一个元素为一个list,表示每一帧的检测结果,每一个结果是由多个list构成,每个list表示一个框,格式为[ cls , x0 ,y0 ,x1 ,y1 ,conf,ifrmae,trackId ] + --etc. retResults[2][j][k]表示第j帧的第k个框。 + ''' + cv2.imwrite( os.path.join( outpth,bname ) ,image_array ) + + print('----image:%s, process:%s ( %s ),save:%s'%(bname,(time11-time00) * 1000, timeOut,(time.time() - time11) * 1000) ) + + ##process video + + print('##begin to process videos, total %d videos'%( len(videopaths))) + for i,video in enumerate(videopaths): + print('process video%d :%s '%(i,video)) + par0={'modelPar':modelPar,'processPar':processPar,'drawPar':drawPar,'outpth':par['testOutPath'], 'sort_tracker':sort_tracker,'trackPar':trackPar,'segPar':segPar} + process_video(video,par0,mode='track') + + + +def OCR_demo2(opt): + from ocrUtils2 import crnn_model + from ocrUtils2.ocrUtils import get_cfg,recognition_ocr,strLabelConverter + + if opt['business'] == 'ocr2': + par={ + 'image_dir':'images/ocr_en', + 'outtxt':'images/results', + 'weights':'../AIlib2/weights/conf/ocr2/crnn_448X32.pth', + + #'weights':'../weights/2080Ti/AIlib2/ocr2/crnn_2080Ti_fp16_448X32.engine', + 'device':'cuda:0', + 'cfg':'../AIlib2/weights/conf/ocr2/360CC_config.yaml', + + 'char_file':'../AIlib2/weights/conf/ocr2/chars.txt', + 'imgH':32, + 'imgW':448, + 'workers':1 + + + } + image_dir=par['image_dir'] + outtxt=par['outtxt'] + workers=par['workers'] + weights= par['weights'] + device=par['device'] + + char_file=par['char_file'] + imgH=par['imgH'] + imgW=par['imgW'] + cfg = par['cfg'] + + + + config = get_cfg(cfg, char_file) + + + par['contextFlag']=False + device = torch.device('cuda:0') if torch.cuda.is_available() else torch.device('cpu') + if weights.endswith('.pth'): + model = crnn_model.get_crnn(config,weights=weights).to(device) + par['model_mode']='pth' + else: + logger = trt.Logger(trt.Logger.ERROR) + with open(weights, "rb") as f, trt.Runtime(logger) as runtime: + model = runtime.deserialize_cuda_engine(f.read())# 输入trt本地文件,返回ICudaEngine对象 + print('#####load TRT file:',weights,'success #####') + context = model.create_execution_context() + par['model_mode']='trt';par['contextFlag']=context + + converter = strLabelConverter(config.DATASET.ALPHABETS) + + img_urls=glob.glob('%s/*.jpg'%( image_dir )) + img_urls.extend( glob.glob('%s/*.png'%( image_dir )) ) + cnt=len(img_urls) + print('%s has %d images'%(image_dir ,len(img_urls) ) ) + # 准备数据 + parList=[] + for i in range(cnt): + img_patch=cv2.imread( img_urls[i] , cv2.IMREAD_GRAYSCALE) + started = time.time() + img = cv2.imread(img_urls[i]) + sim_pred = recognition_ocr(config, img, model, converter, device,par=par) + finished = time.time() + print('{0}: elapsed time: {1} prd:{2} '.format( os.path.basename( img_urls[i] ), finished - started, sim_pred )) + + + + + +def OBB_track_demo(opt): + ###倾斜框(OBB)的ship目标检测 + ''' + par={ + 'model_size':(608,608), #width,height + 'K':100, #Maximum of objects' + 'conf_thresh':0.18,##Confidence threshold, 0.1 for general evaluation + 'device':"cuda:0", + + 'down_ratio':4,'num_classes':15, + #'weights':'../AIlib2/weights/conf/ship2/obb_608X608.engine', + 'weights':'../weights/%s/AIlib2/%s/obb_608X608_%s_fp16.engine'%(opt['gpu'],opt['business'],opt['gpu']), + 'dataset':'dota', + 'test_dir': '/mnt/thsw2/DSP2/videos/obbShips', + 'outpth': 'images/results', + 'half': False, + 'mean':(0.5, 0.5, 0.5), + 'std':(1, 1, 1), + 'model_size':(608,608),##width,height + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'heads': {'hm': None,'wh': 10,'reg': 2,'cls_theta': 1}, + 'decoder':None, + 'test_flag':True, + 'postFile': '../AIlib2/weights/conf/%s/para.json'%(opt['business'] ),###后处理参数文件 + 'drawBox':True,#####是否画框 + 'digitWordFont': { 'line_thickness':2,'boxLine_thickness':1,'wordSize':40, 'fontSize':1.0,'label_location':'leftTop'}, + 'labelnames':"../AIlib2/weights/conf/%s/labelnames.json"%(opt['business'] ), ###检测类别对照表 + } + ''' + par={ + + 'obbModelPar':{ + '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,'decoder':None, + 'weights':'../weights/%s/AIlib2/%s/obb_608X608_%s_fp16.engine'%(opt['gpu'],opt['business'],opt['gpu']), + + }, + 'outpth': 'images/results', + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'device':"cuda:0", + + #'test_dir': '/mnt/thsw2/DSP2/videos/obbShips/DJI_20230208110806_0001_W_6M.MP4', + 'test_dir':'/mnt/thsw2/DSP2/videos/obbShips/freighter2.mp4', + + 'test_flag':True, + 'postFile': '../AIlib2/weights/conf/%s/para.json'%(opt['business'] ),###后处理参数文件 + 'drawBox':True,#####是否画框 + 'drawPar': { 'digitWordFont' :{'line_thickness':2,'boxLine_thickness':1,'wordSize':40, 'fontSize':1.0,'label_location':'leftTop'}} , + 'labelnames':"../AIlib2/weights/conf/%s/labelnames.json"%(opt['business'] ), ###检测类别对照表 + } + #par['model_size'],par['mean'],par['std'],par['half'],par['saveType'],par['heads'],par['labelnames'],par['decoder'],par['down_ratio'],par['drawBox'] + #par['rainbows'],par['label_array'],par['digitWordFont'] + + obbModelPar = par['obbModelPar'] + ####加载模型 + model,decoder2=load_model_decoder_OBB(obbModelPar) + obbModelPar['decoder']=decoder2 + + names=get_labelnames(par['labelnames']);obbModelPar['labelnames']=names + + _,_,_,rainbows=get_postProcess_para(par['postFile']);par['drawPar']['rainbows']=rainbows + + + label_arraylist = get_label_arrays(names,rainbows,outfontsize=par['drawPar']['digitWordFont']['wordSize'],fontpath="../AIlib2/conf/platech.ttf") + #par['label_array']=label_arraylist + + trackPar=par['trackPar'] + sort_tracker = OBB_Sort(max_age=trackPar['sort_max_age'], + min_hits=trackPar['sort_min_hits'], + iou_threshold=trackPar['sort_iou_thresh']) + + + ##图像测试和视频 + impth = par['test_dir'] + img_urls=[]###获取文件里所有的图像 + video_urls=[]###获取文件里所有的视频 + img_postfixs = ['.jpg','.JPG','.PNG','.png']; + vides_postfixs= ['.MP4','.mp4','.avi'] + if os.path.isdir(impth): + for postfix in img_postfixs: + img_urls.extend(glob.glob('%s/*%s'%(impth,postfix )) ) + for postfix in ['.MP4','.mp4','.avi']: + video_urls.extend(glob.glob('%s/*%s'%(impth,postfix )) ) + else: + postfix = os.path.splitext(impth)[-1] + if postfix in img_postfixs: img_urls=[ impth ] + if postfix in vides_postfixs: video_urls = [impth ] + + parIn = {'obbModelPar':obbModelPar,'modelPar':{'obbmodel': model},'sort_tracker':sort_tracker,'outpth':par['outpth'],'trackPar':trackPar,'drawPar':par['drawPar']} + par['drawPar']['label_array']=label_arraylist + for img_url in img_urls: + #print(img_url) + ori_image=cv2.imread(img_url) + + #ori_image_list,infos = OBB_infer(model,ori_image,obbModelPar) + + ori_image_list,infos = OBB_tracker_batch([ori_image],[0],parIn['modelPar'],parIn['obbModelPar'],None,parIn['trackPar'],None) + + ori_image_list[1] = draw_obb(ori_image_list[2] ,ori_image_list[1],par['drawPar']) + + imgName = os.path.basename(img_url) + saveFile = os.path.join(par['outpth'], imgName) + ret=cv2.imwrite(saveFile, ori_image_list[1]) + if not ret: + print(saveFile, ' not created ') + print( os.path.basename(img_url),':',infos,ori_image_list[2]) + + ###处理视频 + + for video_url in video_urls: + process_video(video_url, parIn ,mode='obbTrack') + +if __name__=="__main__": + + #jkm_demo() + #businessAll=['river', 'river2','highWay2','noParking','drowning','forest2','vehicle','pedestrian','smogfire' , 'AnglerSwimmer','channelEmergency', 'countryRoad','cityMangement','ship2'] + businessAll = ['river2'] + videopaths = ['/home/th/tuo_heng/dev/DJI_20211229100908_0002_S.mp4'] + for busi in businessAll: + print('-'*40,'beg to test:',busi,'-'*40) + opt={'gpu':'2080Ti','business':busi} + if busi in ['ship2']: + OBB_track_demo(opt) + else: + #if opt['business'] in ['river','highWay2','noParking','drowning','']: + det_track_demo(opt, videopaths) \ No newline at end of file diff --git a/test/ffmpeg11/__init__.py b/test/ffmpeg11/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/ffmpeg11/aa.py b/test/ffmpeg11/aa.py new file mode 100644 index 0000000..8662965 --- /dev/null +++ b/test/ffmpeg11/aa.py @@ -0,0 +1,175 @@ +import json +import time +import subprocess as sp +import ffmpeg +import cv2 +import sys + +import numpy as np + + + +""" +获取视频基本信息 +""" + + +def get_video_info(in_file): + try: + probe = ffmpeg.probe('https://vod.play.t-aaron.com/customerTrans/edc96ea2115a0723a003730956208134/55547af9-184f0827dae-0004-f90c-f2c-7ec68.mp4') + # format = probe['format'] + # size = int(format['size'])/1024/1024 + video_stream = next((stream for stream in probe['streams'] if stream['codec_type'] == 'video'), None) + if video_stream is None: + print('No video stream found', file=sys.stderr) + return + width = int(video_stream['width']) + height = int(video_stream['height']) + num_frames = int(video_stream['nb_frames']) + up, down = str(video_stream['r_frame_rate']).split('/') + fps = eval(up) / eval(down) + print("fbs:", fps) + # duration = float(video_stream['duration']) + bit_rate = int(video_stream['bit_rate'])/1000 + print('width: {}'.format(width)) + print('height: {}'.format(height)) + # print('num_frames: {}'.format(num_frames)) + print('bit_rate: {}k'.format(bit_rate)) + # print('fps: {}'.format(fps)) + # print('size: {}MB'.format(size)) + # print('duration: {}'.format(duration)) + return video_stream + + + + except Exception as err: + if isinstance(err, ffmpeg._run.Error): + print(err.stderr.decode(encoding = 'utf-8')) + raise err + + +if __name__ == '__main__': + file_path = r'D:\shipin\777.mp4' + video_info = get_video_info(file_path) + print(json.dumps(video_info)) + # total_frames = int(video_info['nb_frames']) + # print('总帧数:' + str(total_frames)) + # random_frame = random.randint(1, total_frames) + # print('随机帧:' + str(random_frame)) + # out = read_frame_as_jpeg(file_path, i) + # image_array = numpy.asarray(bytearray(out), dtype="uint8") + # image = cv2.imdecode(image_array, cv2.IMREAD_COLOR) + # kwargs={'fflags': 'nobuffer', 'flags': 'low_delay'} + width = int(video_info['width']) + height = int(video_info['height']) + width_2_1 = int(width/2) + height_2_1 = int(height/2) + print("长:", width, "宽:", height) + text = '' + command = ['ffmpeg', + # '-hwaccel', 'cuvid', + '-c:v', 'h264_cuvid', + # '-hwaccel_output_format', 'cuda', + # '-resize', '%sx%s' % (width_2_1, height_2_1), + '-i', file_path, + # '-c:v', 'hevc_nvenc', + # '-pix_fmt', 'yuv420p', + '-f', 'rawvideo', + '-pix_fmt', 'bgr24', + '-an', + '-'] + p = sp.Popen(command, stdout=sp.PIPE) + # for line in p.stderr: + # # print(line.strip()) + # for line in p.stdout: + # print(text) + + command1 = ['ffmpeg', + '-report', + # '-loglevel', 'debug', + '-y', # 不经过确认,输出时直接覆盖同名文件。 + '-f', 'rawvideo', + '-vcodec', 'rawvideo', + '-pix_fmt', 'bgr24', + # '-hwaccel', 'cuvid', + # '-c:v', 'h264_cuvid', + # '-hwaccel_output_format', 'cuda', + # '-s', "{}x{}".format(self.width * 2, self.height), + '-s', "{}x{}".format(width, height), + '-r', str(25), + '-i', '-', # 指定输入文件 + '-g', str(5), + # '-maxrate', '15000k', + # '-profile:v', 'high', + # '-b:v', '4000k', + # '-crf', '18', + '-rc:v', 'vbr', + '-cq:v', '30', + '-qmin', '30', + '-qmax', '30', + '-bufsize', '1', + '-c:v', 'h264_nvenc', # + + # '-c:v', 'libx264', # 指定视频编码器 + # '-tune', 'zerolatency', # 加速编码速度 + # '-sc_threshold', '0', + '-pix_fmt', 'yuv420p', + "-an", + # '-flvflags', 'no_duration_filesize', + '-preset', 'fast', + # '-f', 'flv',ags', 'no_duration_filesize', + # '-preset', 'fast', # 指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, + # superfast, veryfast, faster, fast, medium, slow, slower, veryslow。 + '-f', 'flv', + 'rtmp://live.push.t-aaron.com/live/THSAr'] + + # # 管道配置 + p1 = sp.Popen(command1, stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE, ) + start1 = time.time() + num = 0 + while True: + + # num += 1 + # # if num ==100: + # # print(time.time()-start1) + # # break + # start = time.time() + in_bytes = p.stdout.read(int(width * height*3)) + # # print(type(in_bytes)) + img = (np.frombuffer(in_bytes, np.uint8)).reshape((height, width, 3)) + # # result = cv2.cvtColor(img, cv2.COLOR_YUV2BGR_NV12) + # # result = cv2.resize(result, (int(width / 2), int(height / 2)), interpolation=cv2.INTER_LINEAR) + # # result = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) + + for line in iter(p1.stdout.readline, b''): + print(line) + # if in_bytes: + # p1.stdin.write(img.tostring()) + # print(p1.stderr.read().decode('utf-8')) + # for line in iter(p1.std + # + # + # out.readline, ''): + # line = line.decode('utf-8') + # print(line) + # print(num) + # time.sleep(0.001) + + # p1.stdin.write(in_frame.tostring()) + # frame + # .astype(np.uint8) + # .tobytes() + # frame = cv2.resize(in_frame, (1280, 720)) # 改变图片尺寸 + # frame = cv2.cvtColor(in_frame, cv2.COLOR_RGB2BGR) # 转成BGR + # i += 1 + # print(round(time.time()-start, 5)) + # + # ai_video_file.write(in_frame) + # if time.time() - start1 > 60: + # ai_video_file.release() + # p.stdout.close() + # p.wait() + # break + # cv2.imshow('frame', frame) + # time.sleep(1111) + # p.kill() \ No newline at end of file diff --git a/test/ffmpeg11/cv2test.py b/test/ffmpeg11/cv2test.py new file mode 100644 index 0000000..b52157f --- /dev/null +++ b/test/ffmpeg11/cv2test.py @@ -0,0 +1,107 @@ +# import cv2,os +# import time +# import subprocess as sp +# # 图片合并 +# # def readImage(): +# # p1 = cv2.imread("C:/Users/chenyukun/Pictures/Camera Roll/a.jpg") +# # p2 = cv2.imread("C:/Users/chenyukun/Pictures/Camera Roll/b.jpg") +# # ret = cv2.add(p1, p2) +# # cv2.imwrite(r"C:\Users\chenyukun\Pictures\Camera Roll\aa.jpg", ret) +# # +# # readImage() +# # https://opencv.apachecn.org/#/docs/4.0.0/2.1-tutorial_py_image_display +# if __name__ == "__main__": +# # print(cv2.__version__) +# # # 读取图像 +# # p1 = cv2.imread("C:/Users/chenyukun/Pictures/Camera Roll/a.jpg", 0) # 以灰度模式加载图像 +# # p2 = cv2.imread("C:/Users/chenyukun/Pictures/Camera Roll/b.jpg", 1) # **cv.IMREAD_COLOR**:加载彩色图像,任何图像的透明度都会被忽略,它是默认标志 +# # p3 = cv2.imread("C:/Users/chenyukun/Pictures/Camera Roll/b.jpg", -1) # 加载图像,包括 alpha 通道 +# # p4 = cv2.imread("C:/Users/chenyukun/Pictures/Camera Roll/a.jpg") +# # p5 = cv2.imread("C:/Users/chenyukun/Pictures/Camera Roll/c.jpg") +# # print(type(p5)) +# # ret = cv2.add(p4, p5) +# # # 显示图像 +# # cv2.imshow('frame', p1) +# # cv2.imshow('frame1', p2) +# # cv2.imshow('frame2', p3) +# # # 对显示窗口做调整,WINDOW_AUTOSIZE不可调整,WINDOW_NORMAL可调整窗口大小 +# # cv2.namedWindow('frame3', cv2.WINDOW_AUTOSIZE) +# # cv2.imshow('frame3', ret) +# # # 等待时间 按下任务键 +# # k = cv2.waitKey(1) & 0xFF +# # if k == 27: #ESC退出 +# # cv2.destroyAllWindows() +# # elif k == ord('s'): # 's' 保存退出 +# # # 保存图像 +# # cv2.imwrite("C:/Users/chenyukun/Pictures/Camera Roll/d.jpg", ret) +# # cv2.destroyAllWindows() +# +# +# +# # 视频入门 +# try: +# cap = cv2.VideoCapture("rtmp://live.play.t-aaron.com/live/THSAf_hd") # 0:表示连接一台摄像机 +# print(cap.isOpened()) +# print(cap) +# except Exception as e: +# print(e) +# raise e +# print("aaaa") +# # 有时,cap 可能没有初始化 capture。在这种情况下,此代码显示错误。你可以通过该方法 cap.isOpened() 检查它是否初始化。 +# # 如果它是 True,那么是好的,否则用 cap.open() 打开在使用。 +# fps = int(cap.get(cv2.CAP_PROP_FPS)) +# width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) +# height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) +# print(fps,width,height) +# # # 设置宽 +# # print(cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320)) +# # # 设置高 +# # print(cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240)) +# +# # 声明编码器和创建 VideoWrite 对象 +# fourcc = cv2.VideoWriter_fourcc(*'mp4v') +# out = cv2.VideoWriter('/home/DATA/dsp/ai/video/eee.mp4',fourcc, fps, (width, height)) +# command=['/usr/bin/ffmpeg', +# '-y', # 覆盖输出文件 +# '-f', 'rawvideo', # 强迫采用格式fmt +# '-vcodec','rawvideo', +# '-pix_fmt', 'bgr24', +# '-s', "{}x{}".format(640, 480),# 图片分辨率 +# '-r', str(25.0),# 视频帧率 +# '-i', '-', +# '-c:v', 'libx264', +# '-pix_fmt', 'yuv420p', +# '-preset', 'ultrafast', +# '-f', 'flv', +# "rtmp://live.push.t-aaron.com/live/THSAb"] +# # p = sp.Popen(command, stdin=sp.PIPE) +# start = time.time() +# while True: +# +# try: +# if not cap.isOpened(): +# cap = cv2.VideoCapture("rtmp://live.play.t-aaron.com/live/THSAf_hd") +# continue +# # 一帧一帧捕捉 +# ret, frame = cap.read() # 返回一个 bool 值(True/False)。如果加载成功,它会返回True +# if not ret: +# cap = cv2.VideoCapture("rtmp://live.play.t-aaron.com/live/THSAf_hd") +# continue +# # print(ret) #True +# # # 我们对帧的操作在这里 +# # gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) +# end = time.time() +# print("bbbbbbbbb") +# # p.stdin.write(frame.tostring()) +# # print("aaaaa") +# out.write(frame) +# except Exception as e: +# raise e +# # # 显示返回的每帧 +# # cv2.imshow('frame',gray) +# # if cv2.waitKey(1) & 0xFF == ord('q'): +# # break +# # 当所有事完成,释放 VideoCapture 对象 +# cap.release() +# out.release() +# cv2.destroyAllWindows() diff --git a/test/ffmpeg11/cv2test1.py b/test/ffmpeg11/cv2test1.py new file mode 100644 index 0000000..99fc97b --- /dev/null +++ b/test/ffmpeg11/cv2test1.py @@ -0,0 +1,103 @@ +import time +import cv2 +import subprocess as sp +# 推流 +import ffmpeg +import numpy as np + +if __name__== "__main__": + + + # with open(str(cv2.__file__),"r") as f: + # print (f.read()) + + # cap = cv2.VideoCapture("rtmp://live.play.t-aaron.com/live/THSAs") + # # Get video information + # fps = int(cap.get(cv2.CAP_PROP_FPS)) + # print(fps) + # width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + # print(width) + # height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + # print(height) + # fourcc = int(cap.get(cv2.CAP_PROP_FOURCC)) + # print(fourcc) + # # print(cv2.getBuildInformation()) + # # cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920) + # # cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080) + # # cap.set(cv2.CAP_PROP_FPS, 60) + # # cap.setExceptionMode(True) + # print(cap.getExceptionMode()) + + + # ffmpeg command + # command = ['ffmpeg', + # '-y', # 不经过确认,输出时直接覆盖同名文件。 + # '-f', 'rawvideo', + # '-vcodec','rawvideo', + # '-pix_fmt', 'bgr24', + # '-s', "{}x{}".format(1920, 1080), + # # '-s', "{}x{}".format(1280, 720), + # '-i', '-', # 指定输入文件 + # '-c:v', 'libx264', # 指定视频编码器 + # '-pix_fmt', 'yuv420p', + # '-g', '5', + # "-an", + # '-b:v', '3000k', + # '-preset', 'ultrafast', # 指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, + # # superfast, veryfast, faster, fast, medium, slow, slower, veryslow。 + # '-f', 'flv', + # "rtmp://live.push.t-aaron.com/live/THSAk"] + kwargs = {'format': 'rawvideo', + 'vcodec': 'rawvideo', + 'pix_fmt': 'bgr24', + 's': '{}x{}'.format(int(1920), int(1080))} + out = { + 'g': str(25), + 'b:v': '6000k', + # '-bufsize': '3000k', + 'tune': 'zerolatency', # 加速编码速度 + 'c:v': 'libx264', # 指定视频编码器 + 'sc_threshold': '0', + 'pix_fmt': 'yuv420p', + 'flvflags': 'no_duration_filesize', + 'preset': 'ultrafast', # 指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, + # superfast, veryfast, faster, fast, medium, slow, slower, veryslow。 + 'format': 'flv'} + # 管道配置 + process2 = ( + ffmpeg + .input('pipe:', **kwargs) + .output('rtmp://live.push.t-aaron.com/live/THSAk', **out) + .global_args('-y', '-an') + .overwrite_output() + .run_async(pipe_stdin=True) + ) + # 管道配置 + # p = sp.Popen(command, stdin=sp.PIPE, shell=False) + + process = ( + ffmpeg + .input('rtmp://221.226.114.142:19350/rlive/stream_4?sign=PZIGmXvw') + .output('pipe:', format='rawvideo', pix_fmt='bgr24') + .overwrite_output() + .global_args('-an') + .run_async(pipe_stdout=True) + ) + # while(cap.isOpened()): + while True: + start =time.time() + # ret, frame = cap.read() + # print(cap.grab()) + in_bytes = process.stdout.read(1920 * 1080 * 3) + # print("aaaaaaaaaaaaaaa", time.time()-start) + # print("aaaaaaaaaaaaaa", time.time()-start) + # start =time.time() + # a,b = cap.retrieve() + if not in_bytes: + print("Opening camera is failed") + break + frame = (np.frombuffer(in_bytes, np.uint8).reshape([1080, 1920, 3])) + print("ccccccccccccccc", time.time()-start) + # process2.stdin.write(frame.tostring()) + # print("bbbbbbbbbbbbbb", time.time()-start) + diff --git a/test/ffmpeg11/ffmpeg11.py b/test/ffmpeg11/ffmpeg11.py new file mode 100644 index 0000000..9f2b5c7 --- /dev/null +++ b/test/ffmpeg11/ffmpeg11.py @@ -0,0 +1,144 @@ +import json +import time +import subprocess as sp +import ffmpeg +import cv2 +import sys +import random + +import numpy as np + + +def read_frame_as_jpeg(in_file, frame_num): + """ + 指定帧数读取任意帧 + """ + out, err = ( + ffmpeg.input(in_file) + .filter('select', 'gte(n,{})'.format(frame_num)) + .output('pipe:', vframes=1, format='image2', vcodec='mjpeg') + .run(capture_stdout=True) + ) + return out + + +""" +获取视频基本信息 +""" + + +def get_video_info(in_file): + try: + probe = ffmpeg.probe(in_file) + # format = probe['format'] + # size = int(format['size'])/1024/1024 + video_stream = next((stream for stream in probe['streams'] if stream['codec_type'] == 'video'), None) + if video_stream is None: + print('No video stream found', file=sys.stderr) + return + width = int(video_stream['width']) + height = int(video_stream['height']) + # num_frames = int(video_stream['nb_frames']) + # up, down = str(video_stream['r_frame_rate']).split('/') + # fps = eval(up) / eval(down) + # duration = float(video_stream['duration']) + bit_rate = int(video_stream['bit_rate'])/1000 + print('width: {}'.format(width)) + print('height: {}'.format(height)) + # print('num_frames: {}'.format(num_frames)) + print('bit_rate: {}k'.format(bit_rate)) + # print('fps: {}'.format(fps)) + # print('size: {}MB'.format(size)) + # print('duration: {}'.format(duration)) + return video_stream + + + + except Exception as err: + print("aaaaaaaaaaaaaaaaaaaa", err) + + +if __name__ == '__main__': + #file_path = 'https://vod.play.t-aaron.com/0bc905ef5651439da2bfba8427fe467e/a76a7ebb6e3b44ef9c0c7820c7e9c574-f2d7ee90cba11aa91971d58e06d295d2-4k.mp4' + file_path = 'https://vod.play.t-aaron.com/customerTrans/edc96ea2115a0723a003730956208134/55547af9-184f0827dae-0004-f90c-f2c-7ec68.mp4' + #file_path = 'https://vod.play.t-aaron.com/customerTrans/edc96ea2115a0723a003730956208134/40b416f7-183b57f6be0-0004-f90c-f2c-7ec68.mp4' + #file_path = 'https://vod.play.t-aaron.com/3301fc8e166f45be88f2214e7a8f4a9d/e29535365b54434d9ed2e8c3b0a175da-fba35541b31a1049ca05b145a283c33a-hd.mp4' + video_info = get_video_info(file_path) + print(json.dumps(video_info)) + # total_frames = int(video_info['nb_frames']) + # print('总帧数:' + str(total_frames)) + # random_frame = random.randint(1, total_frames) + # print('随机帧:' + str(random_frame)) +# out = read_frame_as_jpeg(file_path, i) +# image_array = numpy.asarray(bytearray(out), dtype="uint8") +# image = cv2.imdecode(image_array, cv2.IMREAD_COLOR) +# kwargs={'fflags': 'nobuffer', 'flags': 'low_delay'} + kwargs={ + # "hwaccel": "nvdec", + # "vcodec": "h264_cuvid", + # "c:v": "h264_cuvid" + } + output_args = { + # "vcodec": "hevc_nvenc", + # "c:v": "hevc_nvenc", + # "preset": "fast", + } + # i = 1 + # process1 = ( + # ffmpeg + # .input(file_path, **kwargs) + # .output('pipe:', format='rawvideo', pix_fmt='rgb24', **output_args) + # # .global_args("-an") + # .overwrite_output() + # .run_async(pipe_stdout=True, pipe_stderr=True) + # ) + width = int(video_info['width']) + height = int(video_info['height']) + command = ['ffmpeg', + '-hwaccel cuda', + '-c:v', 'h264_cuvid', + '-resize', '1920x1080', + # '-hwaccel_output_format', 'bgr24', + '-i', file_path, + # '-vf', "hwdownload,format=bgr24", + # "-vcodec", "h264_nvenc", # hevc_nvenc h264_nvenc + '-f', 'rawvideo', + # '-g', '5', + # '-pix_fmt', 'bgr24', + # '-hwaccel_output_format', 'bgr24', + # '-an', + '-'] + p = sp.Popen(command, stdout=sp.PIPE) + # ai_video_file = cv2.VideoWriter(r"C:\Users\chenyukun\Desktop\shipin\aa.mp4", cv2.VideoWriter_fourcc(*'mp4v'), 30, + # (width, height)) + start1 = time.time() + while True: + start = time.time() + # in_bytes = p.stdout.read() + in_bytes = p.stdout.read(int(width * height * 3 // 8)) + # in_bytes = p.stdout.read(int(width * height * 3/4)) + if not in_bytes: + print(in_bytes) + # ai_video_file.release() + p.stdout.close() + p.wait() + break + # 转成ndarray + img = (np.frombuffer(in_bytes, np.uint8)).reshape((int(height/2 * 3 // 2), int(width/2))) + bgr_img = cv2.cvtColor(img, cv2.COLOR_YUV2BGR_NV12) + # in_frame = (np.frombuffer(in_bytes, np.uint8).reshape([int(height/2), int(width/2), 3])) + # print("拉流时间:", time.time() - start) + # frame = cv2.resize(in_frame, (1280, 720)) # 改变图片尺寸 + # i += 1 + # print(round(time.time()-start, 5)) + # + # ai_video_file.write(in_frame) + # if time.time() - start1 > 60: + # ai_video_file.release() + # p.stdout.close() + # p.wait() + # break + # cv2.imshow('frame', bgr_img) + # cv2.waitKey(1) + # time.sleep(1111) + p.kill() diff --git a/test/ffmpeg11/ffmpeg12.py b/test/ffmpeg11/ffmpeg12.py new file mode 100644 index 0000000..f9aa087 --- /dev/null +++ b/test/ffmpeg11/ffmpeg12.py @@ -0,0 +1,101 @@ +import json +import time +import subprocess as sp +import ffmpeg +import cv2 +import sys +import random + +import numpy as np + +""" +获取视频基本信息 +""" + + +def get_video_info(in_file): + try: + probe = ffmpeg.probe(in_file) + # format = probe['format'] + # size = int(format['size'])/1024/1024 + video_stream = next((stream for stream in probe['streams'] if stream['codec_type'] == 'video'), None) + if video_stream is None: + print('No video stream found', file=sys.stderr) + return + width = int(video_stream['width']) + height = int(video_stream['height']) + # num_frames = int(video_stream['nb_frames']) + up, down = str(video_stream['r_frame_rate']).split('/') + video_stream['fps']=eval(up) / eval(down) + # duration = float(video_stream['duration']) + # bit_rate = int(video_stream['bit_rate'])/1000 + print('width: {}'.format(width)) + print('height: {}'.format(height)) + # print('num_frames: {}'.format(num_frames)) + # print('bit_rate: {}k'.format(bit_rate)) + # print('fps: {}'.format(fps)) + # print('size: {}MB'.format(size)) + # print('duration: {}'.format(duration)) + return video_stream + + + + except Exception as err: + print("aaaaaaaaaaaaaaaaaaaa", err) + return None + + +if __name__ == '__main__': + file_path = "rtmp://live.play.t-aaron.com/live/THSAa" + while True: + video_info = get_video_info(file_path) + print(json.dumps(video_info)) + if video_info is None: + time.sleep(2) + continue + else: + break + command = ['ffmpeg', + # '-re', + '-y', + '-c:v', 'h264_cuvid', + '-i', file_path, + '-pix_fmt', 'bgr24', + '-f', 'rawvideo', + '-an', + '-'] + width = int(video_info['width']) + height = int(video_info['height']) + fps = int(video_info['fps']) + p = sp.Popen(command, stdout=sp.PIPE) + ai_video_file = cv2.VideoWriter(r"C:\Users\chenyukun\Desktop\shipin\aaaa.mp4", cv2.VideoWriter_fourcc(*'mp4v'), fps, + (width, height)) + start1 = time.time() + while True: + start = time.time() + in_bytes = p.stdout.read(int(width * height * 3)) + if not in_bytes: + print(in_bytes) + p.stdout.close() + p.wait() + break + # img = (np.frombuffer(in_bytes, np.uint8)).reshape((int(height), int(width))) + # bgr_img = cv2.cvtColor(img, cv2.COLOR_YUV2BGR_NV12) + in_frame = (np.frombuffer(in_bytes, np.uint8).reshape([int(height), int(width), 3])) + # print("拉流时间:", time.time() - start) + # frame = cv2.resize(in_frame, (1280, 720)) # 改变图片尺寸 + # i += 1 + # print(round(time.time()-start, 5)) + # + ai_video_file.write(in_frame) + # if time.time() - start1 > 60: + # ai_video_file.release() + # p.stdout.close() + # p.wait() + # break + # cv2.imshow('frame', in_frame) + # cv2.waitKey(1) + # time.sleep(1111) + p.stdout.close() + p.wait() + p.kill() \ No newline at end of file diff --git a/test/ffmpeg11/ffmpeg13.py b/test/ffmpeg11/ffmpeg13.py new file mode 100644 index 0000000..acbbb32 --- /dev/null +++ b/test/ffmpeg11/ffmpeg13.py @@ -0,0 +1,20 @@ +import json +import time +import subprocess as sp +import ffmpeg +import cv2 +import sys +import random + +import numpy as np + + + +if __name__ == '__main__': + + command = ["ffmpeg", + "-f", "concat", + "-i", r"C:\Users\chenyukun\Desktop\shipin\aaa.txt", + "-c", "copy", + r"C:\Users\chenyukun\Desktop\shipin\aaaa.mp4"] + p = sp.Popen(command, stdout=sp.PIPE) \ No newline at end of file diff --git a/test/ffmpeg11/ffmpeg2.py b/test/ffmpeg11/ffmpeg2.py new file mode 100644 index 0000000..f74ce8e --- /dev/null +++ b/test/ffmpeg11/ffmpeg2.py @@ -0,0 +1,292 @@ +import copy +from enum import Enum, unique +from PIL import Image + +import sys +sys.path.extend(['..','../AIlib' ]) + +from AI import AI_process, AI_process_forest, get_postProcess_para +import cv2,os,time +from segutils.segmodel import SegModel +from models.experimental import attempt_load +from utils.torch_utils import select_device +from utilsK.queRiver import get_labelnames,get_label_arrays +import numpy as np + + + + + +# 异常枚举 +@unique +class ModelType(Enum): + + WATER_SURFACE_MODEL = ("1", "001", "水面模型") + + FOREST_FARM_MODEL = ("2", "002", "森林模型") + + TRAFFIC_FARM_MODEL = ("3", "003", "交通模型") + + def checkCode(code): + for model in ModelType: + if model.value[1] == code: + return True + return False +class ModelConfig(): + def __init__(self): + postFile = '../AIlib/conf/para.json' + self.conf_thres, self.iou_thres, self.classes, self.rainbows = get_postProcess_para(postFile) + + +class SZModelConfig(ModelConfig): + + def __init__(self): + super(SZModelConfig, self).__init__() + labelnames = "../AIlib/weights/yolov5/class8/labelnames.json" ##对应类别表 + self.names = get_labelnames(labelnames) + self.label_arraylist = get_label_arrays(self.names, self.rainbows, outfontsize=40, + fontpath="../AIlib/conf/platech.ttf") + + +class LCModelConfig(ModelConfig): + def __init__(self): + super(LCModelConfig, self).__init__() + labelnames = "../AIlib/weights/forest/labelnames.json" + self.names = get_labelnames(labelnames) + self.label_arraylist = get_label_arrays(self.names, self.rainbows, outfontsize=40, fontpath="../AIlib/conf/platech.ttf") + + +class RFModelConfig(ModelConfig): + def __init__(self): + super(RFModelConfig, self).__init__() + labelnames = "../AIlib/weights/road/labelnames.json" + self.names = get_labelnames(labelnames) + imageW = 1536 + outfontsize=int(imageW/1920*40) + self.label_arraylist = get_label_arrays(self.names, self.rainbows, outfontsize=outfontsize, fontpath="../AIlib/conf/platech.ttf") + +class Model(): + def __init__(self, device, allowedList=None): + ##预先设置的参数 + self.device_ = device ##选定模型,可选 cpu,'0','1' + self.allowedList = allowedList + + +# 水面模型 +class SZModel(Model): + def __init__(self, device, allowedList=None): + super().__init__(device, allowedList) + + self.device = select_device(self.device_) + self.half = self.device.type != 'cpu' + self.model = attempt_load("../AIlib/weights/yolov5/class8/bestcao.pt", map_location=self.device) + if self.half: + self.model.half() + self.segmodel = SegModel(nclass=2, weights='../AIlib/weights/STDC/model_maxmIOU75_1720_0.946_360640.pth', + device=self.device) + + # names, label_arraylist, rainbows, conf_thres, iou_thres + def process(self, frame, config): + return AI_process([frame], self.model, self.segmodel, config[0], config[1], + config[2], self.half, self.device, config[3], config[4], + self.allowedList) + + +# 森林模型 +class LCModel(Model): + def __init__(self, device, allowedList=None): + super().__init__(device, allowedList) + self.device = select_device(self.device_) + self.half = self.device.type != 'cpu' # half precision only supported on CUDA + self.model = attempt_load("../AIlib/weights/forest/best.pt", map_location=self.device) # load FP32 model + if self.half: + self.model.half() + self.segmodel = None + + # names, label_arraylist, rainbows, conf_thres, iou_thres + def process(self, frame, config): + return AI_process_forest([frame], self.model, self.segmodel, config[0], config[1], config[2], + self.half, self.device, config[3], config[4], self.allowedList) + +# 交通模型 +class RFModel(Model): + def __init__(self, device, allowedList=None): + super().__init__(device, allowedList) + self.device = select_device(self.device_) + self.half = self.device.type != 'cpu' # half precision only supported on CUDA + self.model = attempt_load("../AIlib/weights/road/best.pt", map_location=self.device) # load FP32 model + if self.half: + self.model.half() + self.segmodel = None + + # names, label_arraylist, rainbows, conf_thres, iou_thres + def process(self, frame, config): + return AI_process_forest([frame], self.model, self.segmodel, config[0], config[1], config[2], + self.half, self.device, config[3], config[4], self.allowedList) + +def get_model(args): + for model in args[2]: + try: + code = '001' + needed_objectsIndex = [int(category.get("id")) for category in model.get("categories")] + if code == ModelType.WATER_SURFACE_MODEL.value[1]: + return SZModel(args[1], needed_objectsIndex), code, args[0].get("sz") + elif code == ModelType.FOREST_FARM_MODEL.value[1]: + return LCModel(args[1], needed_objectsIndex), code, args[0].get("lc") + elif code == ModelType.TRAFFIC_FARM_MODEL.value[1]: + return RFModel(args[1], needed_objectsIndex), code, args[0].get("rf") + else: + raise Exception("11111") + except Exception as e: + raise Exception("22222") +class PictureWaterMark(): + + def common_water(self, image, logo): + width, height = image.shape[1], image.shape[0] + mark_width, mark_height = logo.shape[1], logo.shape[0] + rate = int(width * 0.2) / mark_width + logo_new = cv2.resize(logo, None, fx=rate, fy=rate, interpolation=cv2.INTER_NEAREST) + position = (int(width * 0.95 - logo_new.shape[1]), int(height * 0.95 - logo_new.shape[0])) + b = Image.new('RGBA', (width, height), (0, 0, 0, 0)) # 创建新图像:透明' + a = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) + watermark = Image.fromarray(cv2.cvtColor(logo_new, cv2.COLOR_BGRA2RGBA)) + # 图片旋转 + # watermark = watermark.rotate(45) + b.paste(a, (0, 0)) + b.paste(watermark, position, mask=watermark) + return cv2.cvtColor(np.asarray(b), cv2.COLOR_BGR2RGB) + + def common_water_1(self, image, logo, alpha=1): + h, w = image.shape[0], image.shape[1] + if w >= h: + rate = int(w * 0.1) / logo.shape[1] + else: + rate = int(h * 0.1) / logo.shape[0] + mask = cv2.resize(logo, None, fx=rate, fy=rate, interpolation=cv2.INTER_NEAREST) + mask_h, mask_w = mask.shape[0], mask.shape[1] + mask_channels = cv2.split(mask) + dst_channels = cv2.split(image) + # b, g, r, a = cv2.split(mask) + # 计算mask在图片的坐标 + ul_points = (int(h * 0.95) - mask_h, int(w - h * 0.05 - mask_w)) + dr_points = (int(h * 0.95), int(w - h * 0.05)) + for i in range(3): + dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] = dst_channels[i][ + ul_points[0]: dr_points[0], + ul_points[1]: dr_points[1]] * ( + 255.0 - mask_channels[3] * alpha) / 255 + dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] += np.array( + mask_channels[i] * (mask_channels[3] * alpha / 255), dtype=np.uint8) + dst_img = cv2.merge(dst_channels) + return dst_img +def video_merge(frame1, frame2, width, height): + frameLeft = cv2.resize(frame1, (width, height), interpolation=cv2.INTER_LINEAR) + frameRight = cv2.resize(frame2, (width, height), interpolation=cv2.INTER_LINEAR) + frame_merge = np.hstack((frameLeft, frameRight)) + # frame_merge = np.hstack((frame1, frame2)) + return frame_merge +cap = cv2.VideoCapture("/home/DATA/chenyukun/3.mp4") + +# Get video information +fps = int(cap.get(cv2.CAP_PROP_FPS)) +print(fps) +width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) +print(width) +height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) +print(height) +# command = ['ffmpeg', +# '-y', # 不经过确认,输出时直接覆盖同名文件。 +# '-f', 'rawvideo', +# '-vcodec', 'rawvideo', +# '-pix_fmt', 'bgr24', +# # '-s', "{}x{}".format(self.width * 2, self.height), +# '-s', "{}x{}".format(width, height), +# '-r', str(15), +# '-i', '-', # 指定输入文件 +# '-g', '15', +# '-sc_threshold', '0', # 使得GOP的插入更加均匀 +# '-b:v', '3000k', # 指定码率 +# '-tune', 'zerolatency', # 加速编码速度 +# '-c:v', 'libx264', # 指定视频编码器 +# '-pix_fmt', 'yuv420p', +# "-an", +# '-preset', 'ultrafast', # 指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, +# # superfast, veryfast, faster, fast, medium, slow, slower, veryslow。 +# '-f', 'flv', +# "rtmp://live.push.t-aaron.com/live/THSAk"] +# +# # 管道配置 +# p = sp.Popen(command, stdin=sp.PIPE, shell=False) + +sz = SZModelConfig() +lc = LCModelConfig() +rf = RFModelConfig() +config = { + "sz": (sz.names, sz.label_arraylist, sz.rainbows, sz.conf_thres, sz.iou_thres), + "lc": (lc.names, lc.label_arraylist, lc.rainbows, lc.conf_thres, lc.iou_thres), + "rf": (rf.names, rf.label_arraylist, rf.rainbows, rf.conf_thres, rf.iou_thres), +} +model = { + "models": [ + { + "code": "001", + "categories": [ + { + "id": "0", + "config": {} + }, + { + "id": "1", + "config": {} + }, + { + "id": "2", + "config": {} + }, + { + "id": "3", + "config": {} + }, + { + "id": "4", + "config": {} + }, + { + "id": "5", + "config": {} + }, + { + "id": "6", + "config": {} + }, + { + "id": "7", + "config": {} + } + ] + }] +} + +mod, model_type_code, modelConfig = get_model((config, str(1), model.get("models"))) +pic = PictureWaterMark() +logo = cv2.imread("./image/logo.png", -1) +ai_video_file = cv2.VideoWriter("/home/DATA/chenyukun/aa/1.mp4", cv2.VideoWriter_fourcc(*'mp4v'), fps, (width*2, height)) +while(cap.isOpened()): + start =time.time() + ret, frame = cap.read() + # cap.grab() + if not ret: + print("Opening camera is failed") + break + p_result, timeOut = mod.process(copy.deepcopy(frame), modelConfig) + frame = pic.common_water_1(frame, logo) + p_result[1] = pic.common_water_1(p_result[1], logo) + frame_merge = video_merge(frame, p_result[1], width, height) + ai_video_file.write(frame_merge) + print(time.time()-start) +ai_video_file.release() +cap.release() + + + + diff --git a/test/ffmpeg11/ffmpeg3.py b/test/ffmpeg11/ffmpeg3.py new file mode 100644 index 0000000..4acfae1 --- /dev/null +++ b/test/ffmpeg11/ffmpeg3.py @@ -0,0 +1,297 @@ +import copy +import subprocess as sp +from enum import Enum, unique +from PIL import Image +import time +import cv2 + +import sys +sys.path.extend(['..','../AIlib' ]) + +from AI import AI_process, AI_process_forest, get_postProcess_para +import cv2,os,time +from segutils.segmodel import SegModel +from models.experimental import attempt_load +from utils.torch_utils import select_device +from utilsK.queRiver import get_labelnames,get_label_arrays +import numpy as np +import torch +from utilsK.masterUtils import get_needed_objectsIndex + + + + + +# 异常枚举 +@unique +class ModelType(Enum): + + WATER_SURFACE_MODEL = ("1", "001", "水面模型") + + FOREST_FARM_MODEL = ("2", "002", "森林模型") + + TRAFFIC_FARM_MODEL = ("3", "003", "交通模型") + + def checkCode(code): + for model in ModelType: + if model.value[1] == code: + return True + return False +class ModelConfig(): + def __init__(self): + postFile = '../AIlib/conf/para.json' + self.conf_thres, self.iou_thres, self.classes, self.rainbows = get_postProcess_para(postFile) + + +class SZModelConfig(ModelConfig): + + def __init__(self): + super(SZModelConfig, self).__init__() + labelnames = "../AIlib/weights/yolov5/class8/labelnames.json" ##对应类别表 + self.names = get_labelnames(labelnames) + self.label_arraylist = get_label_arrays(self.names, self.rainbows, outfontsize=40, + fontpath="../AIlib/conf/platech.ttf") + + +class LCModelConfig(ModelConfig): + def __init__(self): + super(LCModelConfig, self).__init__() + labelnames = "../AIlib/weights/forest/labelnames.json" + self.names = get_labelnames(labelnames) + self.label_arraylist = get_label_arrays(self.names, self.rainbows, outfontsize=40, fontpath="../AIlib/conf/platech.ttf") + + +class RFModelConfig(ModelConfig): + def __init__(self): + super(RFModelConfig, self).__init__() + labelnames = "../AIlib/weights/road/labelnames.json" + self.names = get_labelnames(labelnames) + imageW = 1536 + outfontsize=int(imageW/1920*40) + self.label_arraylist = get_label_arrays(self.names, self.rainbows, outfontsize=outfontsize, fontpath="../AIlib/conf/platech.ttf") + +class Model(): + def __init__(self, device, allowedList=None): + ##预先设置的参数 + self.device_ = device ##选定模型,可选 cpu,'0','1' + self.allowedList = allowedList + + +# 水面模型 +class SZModel(Model): + def __init__(self, device, allowedList=None): + super().__init__(device, allowedList) + + self.device = select_device(self.device_) + self.half = self.device.type != 'cpu' + self.model = attempt_load("../AIlib/weights/yolov5/class8/bestcao.pt", map_location=self.device) + if self.half: + self.model.half() + self.segmodel = SegModel(nclass=2, weights='../AIlib/weights/STDC/model_maxmIOU75_1720_0.946_360640.pth', + device=self.device) + + # names, label_arraylist, rainbows, conf_thres, iou_thres + def process(self, frame, config): + return AI_process([frame], self.model, self.segmodel, config[0], config[1], + config[2], self.half, self.device, config[3], config[4], + self.allowedList) + + +# 森林模型 +class LCModel(Model): + def __init__(self, device, allowedList=None): + super().__init__(device, allowedList) + self.device = select_device(self.device_) + self.half = self.device.type != 'cpu' # half precision only supported on CUDA + self.model = attempt_load("../AIlib/weights/forest/best.pt", map_location=self.device) # load FP32 model + if self.half: + self.model.half() + self.segmodel = None + + # names, label_arraylist, rainbows, conf_thres, iou_thres + def process(self, frame, config): + return AI_process_forest([frame], self.model, self.segmodel, config[0], config[1], config[2], + self.half, self.device, config[3], config[4], self.allowedList) + +# 交通模型 +class RFModel(Model): + def __init__(self, device, allowedList=None): + super().__init__(device, allowedList) + self.device = select_device(self.device_) + self.half = self.device.type != 'cpu' # half precision only supported on CUDA + self.model = attempt_load("../AIlib/weights/road/best.pt", map_location=self.device) # load FP32 model + if self.half: + self.model.half() + self.segmodel = None + + # names, label_arraylist, rainbows, conf_thres, iou_thres + def process(self, frame, config): + return AI_process_forest([frame], self.model, self.segmodel, config[0], config[1], config[2], + self.half, self.device, config[3], config[4], self.allowedList) + +def get_model(args): + for model in args[2]: + try: + code = '001' + needed_objectsIndex = [int(category.get("id")) for category in model.get("categories")] + if code == ModelType.WATER_SURFACE_MODEL.value[1]: + return SZModel(args[1], needed_objectsIndex), code, args[0].get("sz") + elif code == ModelType.FOREST_FARM_MODEL.value[1]: + return LCModel(args[1], needed_objectsIndex), code, args[0].get("lc") + elif code == ModelType.TRAFFIC_FARM_MODEL.value[1]: + return RFModel(args[1], needed_objectsIndex), code, args[0].get("rf") + else: + raise Exception("11111") + except Exception as e: + raise Exception("22222") +class PictureWaterMark(): + + def common_water(self, image, logo): + width, height = image.shape[1], image.shape[0] + mark_width, mark_height = logo.shape[1], logo.shape[0] + rate = int(width * 0.2) / mark_width + logo_new = cv2.resize(logo, None, fx=rate, fy=rate, interpolation=cv2.INTER_NEAREST) + position = (int(width * 0.95 - logo_new.shape[1]), int(height * 0.95 - logo_new.shape[0])) + b = Image.new('RGBA', (width, height), (0, 0, 0, 0)) # 创建新图像:透明' + a = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) + watermark = Image.fromarray(cv2.cvtColor(logo_new, cv2.COLOR_BGRA2RGBA)) + # 图片旋转 + # watermark = watermark.rotate(45) + b.paste(a, (0, 0)) + b.paste(watermark, position, mask=watermark) + return cv2.cvtColor(np.asarray(b), cv2.COLOR_BGR2RGB) + + def common_water_1(self, image, logo, alpha=1): + h, w = image.shape[0], image.shape[1] + if w >= h: + rate = int(w * 0.1) / logo.shape[1] + else: + rate = int(h * 0.1) / logo.shape[0] + mask = cv2.resize(logo, None, fx=rate, fy=rate, interpolation=cv2.INTER_NEAREST) + mask_h, mask_w = mask.shape[0], mask.shape[1] + mask_channels = cv2.split(mask) + dst_channels = cv2.split(image) + # b, g, r, a = cv2.split(mask) + # 计算mask在图片的坐标 + ul_points = (int(h * 0.95) - mask_h, int(w - h * 0.05 - mask_w)) + dr_points = (int(h * 0.95), int(w - h * 0.05)) + for i in range(3): + dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] = dst_channels[i][ + ul_points[0]: dr_points[0], + ul_points[1]: dr_points[1]] * ( + 255.0 - mask_channels[3] * alpha) / 255 + dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] += np.array( + mask_channels[i] * (mask_channels[3] * alpha / 255), dtype=np.uint8) + dst_img = cv2.merge(dst_channels) + return dst_img +def video_merge(frame1, frame2, width, height): + frameLeft = cv2.resize(frame1, (width, height), interpolation=cv2.INTER_LINEAR) + frameRight = cv2.resize(frame2, (width, height), interpolation=cv2.INTER_LINEAR) + frame_merge = np.hstack((frameLeft, frameRight)) + # frame_merge = np.hstack((frame1, frame2)) + return frame_merge +cap = cv2.VideoCapture("/home/DATA/chenyukun/4.mp4") + +# Get video information +fps = int(cap.get(cv2.CAP_PROP_FPS)) +print(fps) +width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) +print(width) +height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) +print(height) +# command = ['ffmpeg', +# '-y', # 不经过确认,输出时直接覆盖同名文件。 +# '-f', 'rawvideo', +# '-vcodec', 'rawvideo', +# '-pix_fmt', 'bgr24', +# # '-s', "{}x{}".format(self.width * 2, self.height), +# '-s', "{}x{}".format(width, height), +# '-r', str(15), +# '-i', '-', # 指定输入文件 +# '-g', '15', +# '-sc_threshold', '0', # 使得GOP的插入更加均匀 +# '-b:v', '3000k', # 指定码率 +# '-tune', 'zerolatency', # 加速编码速度 +# '-c:v', 'libx264', # 指定视频编码器 +# '-pix_fmt', 'yuv420p', +# "-an", +# '-preset', 'ultrafast', # 指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, +# # superfast, veryfast, faster, fast, medium, slow, slower, veryslow。 +# '-f', 'flv', +# "rtmp://live.push.t-aaron.com/live/THSAk"] +# +# # 管道配置 +# p = sp.Popen(command, stdin=sp.PIPE, shell=False) + +sz = SZModelConfig() +lc = LCModelConfig() +rf = RFModelConfig() +config = { + "sz": (sz.names, sz.label_arraylist, sz.rainbows, sz.conf_thres, sz.iou_thres), + "lc": (lc.names, lc.label_arraylist, lc.rainbows, lc.conf_thres, lc.iou_thres), + "rf": (rf.names, rf.label_arraylist, rf.rainbows, rf.conf_thres, rf.iou_thres), +} +model = { + "models": [ + { + "code": "001", + "categories": [ + { + "id": "0", + "config": {} + }, + { + "id": "1", + "config": {} + }, + { + "id": "2", + "config": {} + }, + { + "id": "3", + "config": {} + }, + { + "id": "4", + "config": {} + }, + { + "id": "5", + "config": {} + }, + { + "id": "6", + "config": {} + }, + { + "id": "7", + "config": {} + } + ] + }] +} + +mod, model_type_code, modelConfig = get_model((config, str(0), model.get("models"))) +pic = PictureWaterMark() +logo = cv2.imread("./image/logo.png", -1) +ai_video_file = cv2.VideoWriter("/home/DATA/chenyukun/aa/2.mp4", cv2.VideoWriter_fourcc(*'mp4v'), fps, (width*2, height)) +while(cap.isOpened()): + start =time.time() + ret, frame = cap.read() + # cap.grab() + if not ret: + print("Opening camera is failed") + break + p_result, timeOut = mod.process(copy.deepcopy(frame), modelConfig) + frame = pic.common_water_1(frame, logo) + p_result[1] = pic.common_water_1(p_result[1], logo) + frame_merge = video_merge(frame, p_result[1], width, height) + ai_video_file.write(frame_merge) + print(time.time()-start) +ai_video_file.release() +cap.release() + + + + diff --git a/test/ffmpeg11/ffmpeg33.py b/test/ffmpeg11/ffmpeg33.py new file mode 100644 index 0000000..4089f52 --- /dev/null +++ b/test/ffmpeg11/ffmpeg33.py @@ -0,0 +1,79 @@ +import subprocess as sp +import time +import cv2 +import ffmpeg +# 推流 +import numpy as np + +if __name__== "__main__": + + + # with open(str(cv2.__file__),"r") as f: + # print (f.read()) + # aa = {'loglevel': 'error'} + # process = ( + # ffmpeg + # .input("http://cmgw-vpc.lechange.com:8888/LCO/8D0B355PAN8B3B3/0/0/20221019T130437/eabfe43d95971e0ae03de28dad4fd4ce.m3u8", **aa) + # .output('pipe:', format='rawvideo', pix_fmt='bgr24', loglevel='error')# , bufsize='1000000k' + # .overwrite_output() + # .global_args('-an') + # .run_async(pipe_stdout=True) + # ) + # self.pull_p = sp.Popen(command, stdout=sp.PIPE, stderr=sp.PIPE) + cap = cv2.VideoCapture("https://vod.play.t-aaron.com/customerTrans/edc96ea2115a0723a003730956208134/55547af9-184f0827dae-0004-f90c-f2c-7ec68.mp4") + fps = int(cap.get(cv2.CAP_PROP_FPS)) + print(fps) + width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + print(width) + height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + print(height) + fourcc = int(cap.get(cv2.CAP_PROP_FOURCC)) + print(fourcc) + print(cap.get(7)) + # print(cv2.getBuildInformation()) + # cap.setExceptionMode(True) + # print(cap.getExceptionMode()) + # cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920) + # cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080) + # cap.set(cv2.CAP_PROP_FPS, 25) + # command = ['ffmpeg', + # '-y', # 不经过确认,输出时直接覆盖同名文件。 + # '-f', 'rawvideo', + # '-vcodec','rawvideo', + # '-pix_fmt', 'bgr24', + # # '-r', str(13), + # '-s', "{}x{}".format(width, height), + # # '-s', "{}x{}".format(1280, 720), + # '-i', '-', # 指定输入文件 + # '-c:v', 'libx264', # 指定视频编码器 + # '-pix_fmt', 'yuv420p', + # "-an", + # # '-b:v', '3000k', + # '-preset', 'ultrafast', # 指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, + # # superfast, veryfast, faster, fast, medium, slow, slower, veryslow。 + # '-f', 'flv', + # "rtmp://live.push.t-aaron.com/live/THSAq"] + # + # # # 管道配置 + # p = sp.Popen(command, stdin=sp.PIPE) + # # while(cap.isOpened()): + # while True: + # start =time.time() + # # in_bytes = process.stdout.read(1920 * 1080 * 3) + # # result = (np.frombuffer(in_bytes, np.uint8).reshape([1080, 1920, 3])) + # # time.sleep(0.04) + # ret, frame = cap.read() + # # print(cap.grab()) + # # print("aaaaaaaaaaaaaa", time.time()-start) + # # start =time.time() + # # a,b = cap.retrieve() + # # print("bbbbbbbbbbbbbb", time.time()-start) + # # if not ret: + # # print("Opening camera is failed") + # # break + # # cv2.namedWindow('picture',0) + # # cv2.resizeWindow("picture", 1980, 1080) + # # cv2.imshow('picture', result) + # # cv2.waitKey(1) & 0xFF == ord('q') + # p.stdin.write(frame.tostring()) + diff --git a/test/ffmpeg11/test1.py b/test/ffmpeg11/test1.py new file mode 100644 index 0000000..05557e7 --- /dev/null +++ b/test/ffmpeg11/test1.py @@ -0,0 +1,122 @@ +import json +import time +import subprocess as sp +from concurrent.futures import ThreadPoolExecutor +from traceback import format_exc + +import ffmpeg +import sys + +import numpy as np + +""" +获取视频基本信息 +""" + + +def get_video_info(in_file): + try: + probe = ffmpeg.probe( + 'https://vod.play.t-aaron.com/customerTrans/edc96ea2115a0723a003730956208134/55547af9-184f0827dae-0004-f90c-f2c-7ec68.mp4') + # format = probe['format'] + # size = int(format['size'])/1024/1024 + video_stream = next((stream for stream in probe['streams'] if stream['codec_type'] == 'video'), None) + if video_stream is None: + print('No video stream found', file=sys.stderr) + return + width = int(video_stream['width']) + height = int(video_stream['height']) + num_frames = int(video_stream['nb_frames']) + up, down = str(video_stream['r_frame_rate']).split('/') + fps = eval(up) / eval(down) + print("fbs:", fps) + # duration = float(video_stream['duration']) + bit_rate = int(video_stream['bit_rate']) / 1000 + print('width: {}'.format(width)) + print('height: {}'.format(height)) + # print('num_frames: {}'.format(num_frames)) + print('bit_rate: {}k'.format(bit_rate)) + # print('fps: {}'.format(fps)) + # print('size: {}MB'.format(size)) + # print('duration: {}'.format(duration)) + return video_stream + + + + except Exception as err: + if isinstance(err, ffmpeg._run.Error): + print(err.stderr.decode(encoding='utf-8')) + raise err + +def aa(p1, in_bytes): + try: + p1.stdin.write(in_bytes) + except Exception: + print(format_exc()) + +if __name__ == '__main__': + file_path = 'rtsp://localhost:8554/live' + command = ['ffmpeg', + '-c:v', 'h264_cuvid', + '-i', file_path, + '-f', 'rawvideo', + '-pix_fmt', 'bgr24', + '-an', + '-'] + p = sp.Popen(command, stdout=sp.PIPE) + command1 = ['ffmpeg', + '-y', + "-an", + '-f', 'rawvideo', + '-vcodec', 'rawvideo', + '-pix_fmt', 'bgr24', + '-thread_queue_size', '1024', + '-s', "{}x{}".format(1280, 720), + '-i', '-', # 指定输入文件 + '-r', str(25), + '-g', str(25), + '-maxrate', '6000k', + '-b:v', '4000k', + '-c:v', 'h264_nvenc', # + '-bufsize', '4000k', + '-pix_fmt', 'yuv420p', + '-preset', 'p6', + '-tune', 'll', + '-f', 'flv', + "rtmp://192.168.10.101:19350/rlive/stream_124?sign=YJ8aBPFp"] + # # 管道配置 + p1 = sp.Popen(command1, stdin=sp.PIPE, shell=False) + command2 = ['ffmpeg', + '-y', + "-an", + '-f', 'rawvideo', + '-vcodec', 'rawvideo', + '-pix_fmt', 'bgr24', + '-thread_queue_size', '1024', + '-s', "{}x{}".format(1280, 720), + '-i', '-', # 指定输入文件 + '-r', str(25), + '-g', str(25), + '-maxrate', '6000k', + '-b:v', '4000k', + '-c:v', 'h264_nvenc', # + '-bufsize', '4000k', + '-pix_fmt', 'yuv420p', + '-preset', 'p6', + '-tune', 'll', + '-f', 'flv', + "rtmp://192.168.10.101:19350/rlive/stream_125?sign=uMdRHj9R"] + # # 管道配置 + p2 = sp.Popen(command1, stdin=sp.PIPE, shell=False) + start1 = time.time() + num = 0 + with ThreadPoolExecutor(max_workers=100) as t: + while True: + in_bytes = p.stdout.read(1280 * 720 * 3) + if in_bytes: + img = (np.frombuffer(in_bytes, np.uint8)).reshape((720, 1280, 3)) + for i in range(1): + t.submit(aa, p1, in_bytes) + t.submit(aa, p2, in_bytes) + else: + break diff --git a/test/ffmpeg11/test222.py b/test/ffmpeg11/test222.py new file mode 100644 index 0000000..2ab2617 --- /dev/null +++ b/test/ffmpeg11/test222.py @@ -0,0 +1,80 @@ +from traceback import format_exc + +import cv2 +import numpy as np +from loguru import logger +import subprocess as sp +from common import Constant +from enums.ExceptionEnum import ExceptionType +from exception.CustomerException import ServiceException +from util.Cv2Utils import push_video_stream, clear_pull_p + +pull_p = None +push_p =None +p_push_status=[0,0] + +def start_pull_p(pull_url, requestId): + try: + command = ['ffmpeg'] + # if pull_url.startswith("rtsp://"): + # command.extend(['-timeout', '20000000', '-rtsp_transport', 'tcp']) + # if pull_url.startswith("http") or pull_url.startswith("rtmp"): + # command.extend(['-rw_timeout', '20000000']) + command.extend(['-re', + '-y', + '-an', + # '-hwaccel', 'cuda', cuvid + '-c:v', 'h264_cuvid', + # '-resize', self.wah, + '-i', pull_url, + '-f', 'rawvideo', + # '-pix_fmt', 'bgr24', + '-r', '25', + '-']) + return sp.Popen(command, stdout=sp.PIPE) + except ServiceException as s: + logger.error("构建拉流管道异常: {}, requestId:{}", s.msg, requestId) + raise s + except Exception as e: + logger.error("构建拉流管道异常:{}, requestId:{}", format_exc(), requestId) + raise e + +def pull_read_video_stream(pull_p, pull_url, width, height, width_height_3, w_2, h_2, requestId): + result = None + try: + if pull_p is None: + pull_p = start_pull_p(pull_url, requestId) + in_bytes = pull_p.stdout.read(width_height_3) + if in_bytes is not None and len(in_bytes) > 0: + try: + # result = (np.frombuffer(in_bytes, np.uint8).reshape([height * 3 // 2, width, 3])) + # ValueError: cannot reshape array of size 3110400 into shape (1080,1920) + result = (np.frombuffer(in_bytes, np.uint8)).reshape((height, width)) + result = cv2.cvtColor(result, cv2.COLOR_YUV2BGR_NV12) + # result = cv2.cvtColor(result, cv2.COLOR_RGB2BGR) + if result.shape[1] > Constant.width: + result = cv2.resize(result, (result.shape[1] // 2, result.shape[0] // 2), interpolation=cv2.INTER_LINEAR) + except Exception: + logger.error("视频格式异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.VIDEO_RESOLUTION_EXCEPTION.value[0], + ExceptionType.VIDEO_RESOLUTION_EXCEPTION.value[1]) + except ServiceException as s: + clear_pull_p(pull_p, requestId) + raise s + except Exception: + clear_pull_p(pull_p, requestId) + pull_p = None + width = None + height = None + width_height_3 = None + logger.error("读流异常:{}, requestId:{}", format_exc(), requestId) + return result, pull_p, width, height, width_height_3 + +while True: + frame, pull_p, width, height, width_height_3 = pull_read_video_stream(pull_p, 'rtmp://live.play.t-aaron.com/live/THSAr', 1920, + 1080*3//2, 1920*1080*3//2, 960, 540, + '111') + if frame is not None: + push_p = push_video_stream(frame, push_p, 'rtmp://live.push.t-aaron.com/live/THSAs', p_push_status, '11') +clear_pull_p(pull_p, "11111") +close_all_p(push_p, None, None, "11111") \ No newline at end of file diff --git a/test/gpu/__init__.py b/test/gpu/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/gpu/gputest.py b/test/gpu/gputest.py new file mode 100644 index 0000000..67dd379 --- /dev/null +++ b/test/gpu/gputest.py @@ -0,0 +1,7 @@ + +import tensorflow as tf +import torch + +if __name__ == '__main__': + gpu_name = torch.cuda.get_device_name(0) + print(gpu_name) \ No newline at end of file diff --git a/test/gpu/gputest1.py b/test/gpu/gputest1.py new file mode 100644 index 0000000..2b1a116 --- /dev/null +++ b/test/gpu/gputest1.py @@ -0,0 +1,54 @@ +import GPUtil +import json +# 网址:https://github.com/anderskm/gputil +GPUtil.showUtilization() +#返回可用 GPU 的列表 ID。 +# order- 确定返回可用 GPU 设备 ID 的顺序。order应指定为以下字符串之一: +# 'first'- 按升序排列可用的 GPU 设备 ID(默认) +# 'last'- 按 id 降序排列可用的 GPU 设备 id +# 'random'- 随机订购可用的 GPU 设备 ID +# 'load'- 按负载递增排序可用的 GPU 设备 ID +# 'memory'- 通过升序内存使用来排序可用的 GPU 设备 ID +# limit- 将返回的 GPU 设备 ID 数量限制为指定数量。必须是正整数。(默认 = 1) +# maxLoad- 被认为可用的 GPU 的最大当前相对负载。负载大于 的 GPUmaxLoad不会返回。(默认 = 0.5) +# maxMemory- 被视为可用的 GPU 的最大当前相对内存使用量。maxMemory不返回当前内存使用量大于的 GPU 。(默认 = 0.5) +# includeNan- 真/假标志,指示是否包括负载或内存使用为 NaN 的 GPU(指示无法检索使用情况)。(默认 = 假) +# excludeID- ID 列表,应从可用 GPU 列表中排除。见GPU类描述。(默认 = []) +# excludeUUIDexcludeID-除了它使用 UUID 之外,其他相同。(默认 = []) +# 输出 +# deviceIDs - 所有可用 GPU 设备 ID 的列表。如果当前负载和内存使用量分别小于maxLoad和maxMemory,则认为 GPU 可用。该列表是根据 排序的order。返回的设备 ID 的最大数量由 限制limit。 +deviceIDs = GPUtil.getAvailable(order = 'memory', limit = 1, maxLoad = 0.8, maxMemory = 0.8, includeNan=False, excludeID=[], excludeUUID=[]) +print(deviceIDs) +# 返回第一个可用的 GPU。可用性是根据当前的内存使用和负载确定的,排序由指定的顺序确定。如果找不到可用的 GPU,则会引发错误。使用默认值时,与getAvailable(order = 'first', limit = 1, maxLoad = 0.5, maxMemory = 0.5) +# 输入 +# order- 见描述GPUtil.getAvailable(...) +# maxLoad- 被认为可用的 GPU 的最大当前相对负载。负载大于 的 GPUmaxLoad不会返回。(默认 = 0.5) +# maxMemory- 被视为可用的 GPU 的最大当前相对内存使用量。maxMemory不返回当前内存使用量大于的 GPU 。(默认 = 0.5) +# attempts- 在放弃寻找可用 GPU 之前,该函数应进行的尝试次数。(默认 = 1) +# interval- 每次尝试查找可用 GPU 的时间间隔(以秒为单位)。(默认 = 900 --> 15 分钟) +# verbose- 如果True是,则在每次尝试之前打印尝试次数,如果找到可用的,则打印 GPU id。 +# includeNan- 见说明GPUtil.getAvailable(...)。(默认 = 假) +# excludeID- 见说明GPUtil.getAvailable(...)。(默认 = []) +# excludeUUID- 见说明GPUtil.getAvailable(...)。(默认 = []) +# 输出 +# deviceID - 包含 1 个元素的列表,其中包含第一个可用的 GPU 设备 ID。如果当前负载和内存使用量分别小于maxLoad和maxMemory,则认为 GPU 可用。顺序和限制分别固定为'first'和1。 +deviceID = GPUtil.getFirstAvailable(order = 'first', maxLoad=0.5, maxMemory=0.5, attempts=1, interval=900, verbose=False) +print(deviceID) +GPUtil.showUtilization(all=True, attrList=None, useOldCode=True) +# 打印所有 GPU 的当前状态(id、内存使用情况、uuid 负载) +# 输入 +# all- 真/假标志,指示是否应显示 GPU 上的所有信息。覆盖attrList。 +# attrListGPU-要显示的属性列表列表。有关更多信息/示例,请参见代码。 +# useOldCode- 真/假标志,指示是否应使用显示 GPU 利用率的旧代码。 +# 输出 +# 没有任何 + +GPUs = GPUtil.getGPUs() +for gpu in GPUs: + print(gpu.id) +# 输入 +# 没有任何 +# 输出 +# GPUs- 所有 GPU 的列表。每个GPU对应于计算机中的一个 GPU,并包含一个设备 ID、相对负载和相对内存使用情况。 +if __name__ == "___main__": + pass \ No newline at end of file diff --git a/test/image/1.jpg b/test/image/1.jpg new file mode 100644 index 0000000..7129dda Binary files /dev/null and b/test/image/1.jpg differ diff --git a/test/image/11.jpg b/test/image/11.jpg new file mode 100644 index 0000000..b559e91 Binary files /dev/null and b/test/image/11.jpg differ diff --git a/test/image/2.jpg b/test/image/2.jpg new file mode 100644 index 0000000..4ec90ec Binary files /dev/null and b/test/image/2.jpg differ diff --git a/test/image/22.jpg b/test/image/22.jpg new file mode 100644 index 0000000..fadfacb Binary files /dev/null and b/test/image/22.jpg differ diff --git a/test/ip/__init__.py b/test/ip/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/ip/test.py b/test/ip/test.py new file mode 100644 index 0000000..d3156a3 --- /dev/null +++ b/test/ip/test.py @@ -0,0 +1,34 @@ +import socket + +# def get_local_ip(): +# client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +# # 连接谷歌的dns服务器 +# client.connect(("8.8.8.8", 80)) +# ip, _ = client.getsockname() # 获取套接字自己的地址,返回元组,ip地址和端口号 +# client.close() +# return ip +# +# +# if __name__ == '__main__': +# print(get_local_ip()) + + +import socket +from concurrent.futures import wait, ALL_COMPLETED, ThreadPoolExecutor + + +def getport(port): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(1) + state = sock.connect_ex(("192.168.11.8", port)) + if 0 == state: + print("port: {} is open".format(port)) + sock.close() + + +with ThreadPoolExecutor(max_workers=100) as t: + task_array = [] + for port in range(1, 65535): + task = t.submit(getport, port) + task_array.append(task) + wait(task_array, return_when=ALL_COMPLETED) diff --git a/test/kafka/__init__.py b/test/kafka/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/kafka/producer_start.py b/test/kafka/producer_start.py new file mode 100644 index 0000000..16dc59c --- /dev/null +++ b/test/kafka/producer_start.py @@ -0,0 +1,148 @@ +# import sys +# sys.path.extend(["..", "../util"]) +# from util.AliyunSdk import AliyunVodSdk +# from concurrency.CommonThread import Common +from kafka import KafkaProducer +import json +import threading + +topicName = 'dsp-alg-online-tasks' +# eBody = { +# "request_id": "d4c909912ac741ce81ccef03fd1b2ec45", +# "models": [ +# { +# "code": "001", +# "categories": [{ +# "id": "0", +# "config": {} +# }, +# { +# "id": "1", +# "config": {} +# }, +# { +# "id": "2", +# "config": {} +# }, +# { +# "id": "3", +# "config": {} +# }, +# { +# "id": "4", +# "config": {} +# }, +# { +# "id": "5", +# "config": {} +# } +# ] +# }], +# "command": "start", +# "pull_url": "rtmp://live.play.t-aaron.com/live/THSAr", +# "push_url": "rtmp://live.push.t-aaron.com/live/THSAs", +# "results_base_dir": "P20220802133841159" +# } +# producer = KafkaProducer(bootstrap_servers=['192.168.11.242:9092'], +# value_serializer=lambda m: json.dumps(m).encode('utf-8')) +# future = producer.send(topicName, key=b'd4c909912ac741ce81ccef03fd1b2ec45', value=eBody) +# result = future.get(timeout=10) +# print(result) + +# topicName = 'dsp-alg-image-tasks' +eBody = { + "request_id": "d4c909912ac741ce81ccef03fd1b2ec46", + "models": [ + { + "code": "001", + "categories": [ + { + "id": "0", + "config": {} + }, + { + "id": "1", + "config": {} + }, + { + "id": "2", + "config": {} + }, + { + "id": "3", + "config": {} + }, + { + "id": "4", + "config": {} + }, + { + "id": "5", + "config": {} + }, + { + "id": "6", + "config": {} + }, + { + "id": "7", + "config": {} + } + ] + }], + "command": "start", + "image_urls": ["https://ta-tech-image.oss-cn-shanghai.aliyuncs.com/imagedir/cmn5kvdl23l_1669862645395.bmp"], + "results_base_dir": "P20220802133841159" +} +# topicName = 'dsp-alg-offline-tasks' +# eBody = { +# "request_id": "d4c909912ac741ce81ccef03fd1b2ec46", +# "models": [ +# { +# "code": "001", +# "categories": [ +# { +# "id": "0", +# "config": {} +# }, +# { +# "id": "1", +# "config": {} +# }, +# { +# "id": "2", +# "config": {} +# }, +# { +# "id": "3", +# "config": {} +# }, +# { +# "id": "4", +# "config": {} +# }, +# { +# "id": "5", +# "config": {} +# }, +# { +# "id": "6", +# "config": {} +# }, +# { +# "id": "7", +# "config": {} +# } +# ] +# }], +# "command": "start", +# "original_url": "https://vod.play.t-aaron.com/0bc905ef5651439da2bfba8427fe467e/a76a7ebb6e3b44ef9c0c7820c7e9c574-f2d7ee90cba11aa91971d58e06d295d2-4k.mp4", +# "original_type": ".mp4", +# "push_url": "rtmp://live.push.t-aaron.com/live/THSAr", +# "results_base_dir": "P20220802133841159" +# } +producer = KafkaProducer(bootstrap_servers=['101.132.127.1:19094','101.132.127.1:29094','101.132.127.1:39094'], + value_serializer=lambda m: json.dumps(m).encode('utf-8')) +future = producer.send(topicName, key=b'd4c909912ac741ce81ccef03fd1b2ec46', value=eBody) +result = future.get(timeout=10) +# print(result) \ No newline at end of file diff --git a/test/kafka/producer_stop.py b/test/kafka/producer_stop.py new file mode 100644 index 0000000..f6839ab --- /dev/null +++ b/test/kafka/producer_stop.py @@ -0,0 +1,18 @@ +# import sys +# sys.path.extend(["..", "../util"]) +# from util.AliyunSdk import AliyunVodSdk +# from concurrency.CommonThread import Common +from kafka import KafkaProducer +import json +import threading + +topicName = 'dsp-alg-online-tasks' +eBody = { + "request_id": "d4c909912ac741ce81ccef03fd1b2ec45", + "command": "stop" +} +producer = KafkaProducer(bootstrap_servers=['192.168.11.242:9092'], + value_serializer=lambda m: json.dumps(m).encode('utf-8')) +future = producer.send(topicName, key=b'd4c909912ac741ce81ccef03fd1b2ec45', value=eBody) +result = future.get(timeout=10) +print(result) \ No newline at end of file diff --git a/test/minio1/__pycache__/minio_test.cpython-310.pyc b/test/minio1/__pycache__/minio_test.cpython-310.pyc new file mode 100644 index 0000000..ede1742 Binary files /dev/null and b/test/minio1/__pycache__/minio_test.cpython-310.pyc differ diff --git a/test/minio1/minio_test.py b/test/minio1/minio_test.py new file mode 100644 index 0000000..1696b38 --- /dev/null +++ b/test/minio1/minio_test.py @@ -0,0 +1,31 @@ +import io +import json + +import cv2 +import urllib3 +from minio import Minio + +# MinIO + +minioClient = Minio('192.168.12.5:9000', + access_key='RoZc1NbZ6oAC4lTV', + secret_key='wC01Lup6SIoahwfSrYcoF2gSF3mPy6gJ', + secure=False) +aa = r'C:\Users\chenyukun\Desktop\shipin\DJI_20211229100908_0001_S.mp4' +# # 创建存储桶 +# img = cv2.imread(r"D:\work\alg\tuoheng_alg\test\image\1.jpg") +# ai_result, ai_image = cv2.imencode(".jpg", img) +# # minioClient.make_bucket("test/bb") +# print(len(ai_image)) +# minioClient.put_object('test', '1.jpg', io.BytesIO(ai_image.tobytes()), len(ai_image)) +result = minioClient.fput_object("test", "aa3.mp4", aa) +print(result.__dict__) +# 查看桶信息 +# buckets = minioClient.list_buckets() +# for bucket in buckets: +# print(bucket.name, bucket.creation_date) +# 判断桶是否存在 +if minioClient.bucket_exists("my-bucket"): + print("my-bucket exists") +else: + print("my-bucket does not exist") \ No newline at end of file diff --git a/test/numpy/__init__.py b/test/numpy/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/numpy/numpy_test.py b/test/numpy/numpy_test.py new file mode 100644 index 0000000..ce127d1 --- /dev/null +++ b/test/numpy/numpy_test.py @@ -0,0 +1,108 @@ + + +import numpy as np +# # 使用标量类型 +# dt = np.dtype(np.int32) +# print(dt) +# +# # int8, int16, int32, int64 四种数据类型可以使用字符串 'i1', 'i2','i4','i8' 代替 +# dt = np.dtype('i4') +# print(dt) +# +# # 字节顺序标注 +# dt = np.dtype(' 色彩的饱和度 +(3) Lab: 有国际照明委员会建立。 L: 整张图到的明亮度 a\b: 负责颜色的多少 +""" +import cv2 +import numpy as np +from matplotlib import pyplot as plt + +# img = cv2.imread(r'C:\Users\chenyukun\Pictures\R.png') +# cv2.imshow("img", img) + +# HSV +# hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) +# cv2.imshow("hsv", hsv) + +# YUV +# yuv = cv2.cvtColor(img, cv2.COLOR_BGR2YUV) +# cv2.imshow("yuv", yuv) + +# LAB +# lab = cv2.cvtColor(img, cv2.COLOR_BGR2Lab) +# cv2.imshow("lab", lab) + +# 分离颜色通道 +# print(img) +# b, g, r = cv2.split(img) +# h, w = np.shape(b) +# # 建立空白数组 +# hest = np.zeros([256], dtype=np.int32) +# print(hest) +# # 遍历图片 +# for i in [b, g, r]: +# for row in range(h): +# for col in range(w): +# pv = i[row, col] +# hest[pv] += 1 +# plt.plot(hest, color='r') +# plt.show() +# cv2.waitKey(100000) + +# array1 = np.random.randint(0, 255, (300, 150, 3), dtype=np.uint8) +# array2 = np.random.randint(200, 255, (300, 150, 3), dtype=np.uint8) +# new_array = np.hstack([array1, array2]) +# cv2.imshow("new_array", new_array) +# cv2.waitKey(100000) + +# 彩色图片 -> BGR +# 查看B +# img_B = img.copy() +# img_B[:, :, 1] = 0 +# img_B[:, :, 2] = 0 +# cv2.imshow("img_B", img_B) +# cv2.waitKey(100000) + +# 查看G +# img_G = img.copy() +# img_G[:, :, 0] = 0 +# img_G[:, :, 2] = 0 +# cv2.imshow("img_G", img_G) +# cv2.waitKey(100000) + +# 查看G +# img_R = img.copy() +# img_R[:, :, 0] = 0 +# img_R[:, :, 1] = 0 +# cv2.imshow("img_R", img_R) +# cv2.waitKey(100000) + +# 深入研究图片的读取 +""" +cv2.imread(path, way) +0: 读取灰度图片 +1: 读取彩色图片 +-1: 读取图片,加载Alpha通道 +Alpha通道: +指一张图片的透明与不透明度 +""" +img_color = cv2.imread(r'C:\Users\chenyukun\Pictures\R.png') + +img_gray = cv2.imread(r'C:\Users\chenyukun\Pictures\R.png', 0) + +img_transparent = cv2.imread(r'C:\Users\chenyukun\Pictures\R.png', -1) + +""" +彩色图像:三维 B G R -> (373*490) +灰度图像:二维:-> (373*490) +推断出的公式: Y = (B+G+R)/3 +官方给出的公式: Y = 0.299R + 0.587G + 0.114B +cv.imshow() -> 不仅仅是array()必须是uint8这种类型的。 +""" + +# 三通道分离 +# b, g, r = cv2.split(img_color) +# new_img = (b+g+r)/3 +# new_img = 0.299*r + 0.587*g + 0.114*b +# new_img = new_img.astype('uint8') +# cv2.imshow('new_img', new_img) + +# 官方的填充方式: 以初始的灰度二维矩阵进行RGB通道的填充 +# new_image = cv2.merge([img_gray,img_gray,img_gray]) +# cv2.imshow('new_img', new_image) +# cv2.waitKey(100000) + +# 图像的加法 -> 矩阵 + +# 加法 【前提:必须是一样大小的矩阵:对应的元素求和】 +""" +像素点: [0,255]超过255怎么办?【取余】 +150+150=300 +300%255 +""" + +""" +图片融合 +addWeighted(src1, alpha, src2, beta, gamma) +src1\src2: 第一张和第二张图片 +alpha\beta: 第一张图片的权重、第二张图片的权重 +gamma: 亮度的调节 +""" +# result = cv2.addWeighted(img_color, 0.6, img_color, 0.3, 0) +# cv2.imshow('new_img', result) +# cv2.waitKey(100000) +# +# # 图像的类型转换 +# # 原始图片BGR -> RGB +# cv2.cvtColor(img_color, cv2.COLOR_BGR2RGB) + +""" +1.沿着x轴进行翻转 +2.沿着y轴进行翻转 +3.同时沿着x轴和y进行翻转 +cv2.flip(src, flipCode) +src: 源图像 +flipCode: 翻转形式 +0:沿着x轴进行翻转 +1(大于等于1): 沿着y轴进行翻转 +-1(小于等于-1): 同时沿着x轴和y进行翻转 +""" + +""" +图像阈值化处理 +ret, dst = cv2.threshold(src, thresh, maxval, type) +ret: 阈值返回值(阈值设定的是多少) +dst: 输出的图像 +src: 源图像 需要阈值化处理的图像 +thresh: 人为指定的阈值 +maxval: 当像素超过了阈值,(小于等于阈值)所赋予的值,否则取0 +type: +(1) cv2.THRESH_BINARY: 当像素点大于阈值时,取指定255,小于等于阈值时,取0 +(2) cv2.THRESH_BINARY_INV: 当像素点大于阈值时,取0。小于等于阈值时,取255 +(3) cv2.THRESH_TRUNC: 超过阈值取阈值,低于阈值取自身 +(4) cv2.THRESH_TOZERO: 超过阈值不变,低于阈值取0 +(5) cv2.THRESH_TOZERO_INV: 超过阈值变为0, 低于阈值不变 +注意:当阈值处理彩色图像时,出现粉色等颜色的原因在于: BGR三通道的叠加 +""" +# ret, dst = cv2.threshold(img_color, 127, 255, cv2.THRESH_BINARY) +# cv2.imshow('new_img', dst) +# cv2.waitKey(100000) + +""" +均值滤波 +cv2.blur(src, kernel) +src: 源图像 +kernel: 大小(选择多大的矩阵进行平移[3*3最常见]) +""" +# new_img = cv2.blur(img_color, (3, 3)) +# cv2.imshow('new_img', new_img) +# cv2.waitKey(100000) +""" +方框滤波 +cv2.boxFilter(src,depth, ksize, normalize) +src: 源图像 +depth: 图像的深度 填-1就ok, 表示与源图像深度相同 +ksize: 核大小(3*3)(5*5) +normalize: 是否进行归一化 +0:false 不进行归一下(求和,像素点溢出,超过255取255) +1:True 进行归一化,也就是均值滤波 +""" +""" +高斯滤波【考虑了权重问题】 +cv2.GaussianBlur(src, ksize, sigmaX, sigmaY) +src:源图像 +ksize: (3*3)(5*5) 必须为奇数 +sigmaX, sigmaY: 高斯核函数在x或y方向上的标准偏差【控制权重】 +sigmaX = 0, sigmaX = 0.3 * ((ksize -1) * 0.5 -1) + 0.8 +""" +''' +中值滤波 +cv2.medianBlur(src, ksize) +src: 源图像 +ksize:核大小, 只能传递int(1,3,5,7,9)【(3, 3)(5, 5)】 +''' +new_img = cv2.medianBlur(img_color, 5) +cv2.imshow('new_img', new_img) +cv2.waitKey(100000) \ No newline at end of file diff --git a/test/os/__init__.py b/test/os/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/os/test.py b/test/os/test.py new file mode 100644 index 0000000..5a2471b --- /dev/null +++ b/test/os/test.py @@ -0,0 +1,15 @@ +""" +1.os.rename(原文件名,新的文件名) ——文件重命名 +2.os.remove(文件名) ——删除文件 + 如果不说明路径,则在源代码所在文件夹下寻找,寻找不到会报错。 + 若想删除指定文件夹下的文件,文件名则需要具体路径,例如 os.remove(r"D:\test_1\文件名"), r防止斜杠发生转义 +3.os.mkdir(文件夹名) ——创建文件夹 +4.os.rmdir(文件夹名) ——删除文件夹 +5.os.getced() ——获取当前目录 +6.os.chdir(目录) ——切换目录 +7.os.listdir(目录) ——获取当前文件夹下所有的文件或者文件夹,返回一个列表 + os.listdir("aa") #获取aa文件夹下的所有文件或文件夹,返回一个列表 + + +""" +import os \ No newline at end of file diff --git a/test/pachong/__init__.py b/test/pachong/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/pachong/pa.py b/test/pachong/pa.py new file mode 100644 index 0000000..3398783 --- /dev/null +++ b/test/pachong/pa.py @@ -0,0 +1,24 @@ +import requests +# url = 'https://www.baidu.com' +# response = requests.get(url) +# print(response) +# print(type(response)) +# # 返回的页面是requests库猜测的编码方式,有误 +# print(response.text) +# content = response.content.decode('utf-8') +# print(content) + +url = 'https://www.baidu.com/s' +kw = {"wd": "猫"} +headers = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36" +} +response = requests.get(url, params=kw, headers=headers) +# 打印requests库猜测的解码方式 +print(response.encoding) +content = response.content.decode('utf-8') +print(content) +# 查看状态码 +print(response.status_code) + + diff --git a/test/str/test.py b/test/str/test.py new file mode 100644 index 0000000..62c58c9 --- /dev/null +++ b/test/str/test.py @@ -0,0 +1,26 @@ + + + +# aaa={"1":"1","2":"2","3":"3","4": {"1": "4"}} +# for i,v in aaa.items(): +# if i =="4": +# v["1"] = "5" +# +# print(aaa) +# class base(object): +# __slots__=('x') +# var=8 +# def __init__(self): +# pass +# +# def aa(self): +# print("aa") +# +# b=base() +# b.x=88 +# print(b.aa()) +aa = [1,2,3] +a,b,c = aa +print(a) +print(b) +print(c) diff --git a/test/test_minio.py b/test/test_minio.py new file mode 100644 index 0000000..7511dfd --- /dev/null +++ b/test/test_minio.py @@ -0,0 +1,11 @@ +from minio import Minio +minioClient = Minio('minio-jndsj.t-aaron.com:2443', + access_key='PJM0c2qlauoXv5TMEHm2', + secret_key='Wr69Dm3ZH39M3GCSeyB3eFLynLPuGCKYfphixZuI', + secure=True) +try: + #minioClient.fput_object('default', 'demo1.mp4', '/home/th/WJ/data/XunHe/ai_online_avc1.mp4',content_type='video/mp4') + #'/home/th/WJ/DSP2/AIdemo2/images/cityRoad/DJI_0019_142.jpg' + minioClient.fput_object('default','t2.jpg','/home/th/WJ/DSP2/AIdemo2/images/cityRoad/DJI_0019_142.jpg') +except Exception as err: + print(err) diff --git a/test/test_push_stream.py b/test/test_push_stream.py new file mode 100644 index 0000000..af3300f --- /dev/null +++ b/test/test_push_stream.py @@ -0,0 +1,42 @@ +from util.Cv2Utils import video_conjuncing, write_or_video, write_ai_video, push_video_stream, close_all_p,pull_read_video_stream +import inspect +import psutil + +def check_cpu(current_line_number): + cpu_use = psutil.cpu_percent() + cpu_mem = psutil.virtual_memory().percent + cpu_swap = psutil.swap_memory().percent + mem = psutil.virtual_memory() + + # 已经使用的内存量(包括缓存和缓冲区) + used_mem = mem.used/(1024**2) + #current_line_number = inspect.currentframe().f_lineno + print( '---line:{} ,CPU 使用率:{}, 内存使用:{},{:4.0f}M, SWAP内存使用率:{}'.format(current_line_number,cpu_use, cpu_mem,used_mem,cpu_swap) ) +if __name__=='__main__': + width=1920;height=1620;width_height_3=3110400;all_frames=3687; w_2=960;h_2=540 + request_id='11111111111111' + pull_p=None + #pull_url='https://vod.play.t-aaron.com/customerTrans/edc96ea2115a0723a003730956208134/4b773ace-18f56a8ed7d-0004-f90c-f2c-7ec68.mp4' + pull_url='https://vod.play.t-aaron.com/customerTrans/edc96ea2115a0723a003730956208134/55547af9-184f0827dae-0004-f90c-f2c-7ec68.mp4' + + + push_p=None + #push_url='rtmp://live.push.t-aaron.com/live/prod33' + push_url='rtmp://live.push.t-aaron.com/live/innertest32' + check_cpu(inspect.currentframe().f_lineno) + #测试拉流OK + while True: + check_cpu(inspect.currentframe().f_lineno) + 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: + break + + check_cpu(inspect.currentframe().f_lineno) + #测试推流 + + push_p=push_video_stream(frame, push_p, push_url, [1,1], '2222222222222222222') + check_cpu(inspect.currentframe().f_lineno) + + print('noth') + \ No newline at end of file diff --git a/test/test_video.py b/test/test_video.py new file mode 100644 index 0000000..a1478ad --- /dev/null +++ b/test/test_video.py @@ -0,0 +1,32 @@ +import cv2 +import ffmpeg + +vformat='X264'#mp4v,X264,H264 +inUrl='/home/th/WJ/data/XunHe/ai_online.mp4' +outUrl='/home/th/WJ/data/XunHe/ai_%s.avi'%(vformat) +# 打开输入视频文件 +input_video = cv2.VideoCapture(inUrl) + +# 获取视频的帧率和帧大小 +fps = input_video.get(cv2.CAP_PROP_FPS) +frame_width = int(input_video.get(cv2.CAP_PROP_FRAME_WIDTH)) +frame_height = int(input_video.get(cv2.CAP_PROP_FRAME_HEIGHT)) + +# 定义输出视频的编解码器和创建 VideoWriter 对象 +#fourcc = cv2.VideoWriter_fourcc(*'%s'%(vformat) ) +output_video = cv2.VideoWriter(outUrl, fourcc, fps, (frame_width, frame_height)) +#output_video = ffmpeg.VideoWriter(outUrl, vformat, fps, (frame_width, frame_height)) +# 逐帧读取视频 +iframe=0 +while input_video.isOpened(): + ret, frame = input_video.read() + if not ret: + break + if iframe>1000: break + iframe+=1 + # 将帧写入输出视频 + ret2=output_video.write(frame) + print(iframe,ret,ret2) +# 释放 VideoCapture 和 VideoWriter 对象 +input_video.release() +output_video.release() diff --git a/test/test_video2.py b/test/test_video2.py new file mode 100644 index 0000000..b32003a --- /dev/null +++ b/test/test_video2.py @@ -0,0 +1,26 @@ + +import cv2 +import numpy as np + +# 定义编码器并创建VideoWriter对象 +#fourcc = cv2.VideoWriter_fourcc(*'acv1') +fourcc = cv2.VideoWriter_fourcc(*'avc1') +output_video = 'output.mp4' +frame_width = 1920 +frame_height = 1080 +fps = 30 +out = cv2.VideoWriter(output_video, fourcc, fps, (frame_width, frame_height)) + +# 创建视频帧(使用黑色作为示例) +frame = np.zeros((frame_height, frame_width, 3), np.uint8) + +# 写入视频帧 +for i in range(60): # 假设我们只写入60帧 + # 这里可以替换为你的处理过程,比如添加文本或者处理帧 + # ... + + # 将帧写入视频 + out.write(frame) + +# 释放VideoWriter对象 +out.release() diff --git a/test/validate/Test.py b/test/validate/Test.py new file mode 100644 index 0000000..31b44e1 --- /dev/null +++ b/test/validate/Test.py @@ -0,0 +1,139 @@ + +import re +from cerberus import Validator +# pattern = re.compile('^[a-zA-Z0-9]{1,36}$') # 用于匹配至少一个数字 +# m = pattern.match('111aaa3213213123123213123a222') +# print(m) +# +# schema = { +# 'name': {'type': 'string', 'required': True}, +# 'age': {'type': 'integer', 'required': True, 'min': 18}, +# 'email': {'type': 'string', 'required': True, 'regex': r'\w+@\w+\.\w+'} +# } +# v = Validator(schema) +# print(v.validate({ 'name': '11', 'age': 20, 'email': '764784960@qq.com'})) +# aa = str({ 'name': '11', 'age': 20, 'email': '764784960@qq.com'}) +# print(isinstance(aa, dict)) + +# schema = {'name': {'type': 'string'}} +# v = Validator(schema) +# document = {'name1': 'john doe'} +# print(v.validate(document)) +# print(v.validate(document, schema)) + +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'] + }, + 'pull_url': { + 'type': 'string', + 'required': False, + 'nullable': True, + 'maxlength': 255 + }, + 'push_url': { + 'type': 'string', + 'required': False, + 'nullable': True, + 'maxlength': 255 + }, + 'original_url': { + 'type': 'string', + 'required': False, + 'nullable': True, + 'maxlength': 255 + }, + 'original_type': { + 'type': 'string', + 'required': False, + 'nullable': True, + 'maxlength': 255 + }, + 'image_urls': { + 'type': 'list', + 'required': False, + 'schema': { + 'type': 'string', + 'empty': False, + 'maxlength': 5000 + } + }, + 'results_base_dir': { + 'type': 'string', + 'required': False, + 'nullable': True, + 'regex': r'^[a-zA-Z0-9]{0,36}$' + }, + 'models': { + 'type': 'list', + 'required': False, + 'schema': { + 'type': 'dict', + 'required': False, + 'schema': { + 'code': { + 'type': 'string', + 'required': True, + 'empty': False, + 'dependencies': 'categories', + 'regex': r'^[a-zA-Z0-9]{1,255}$' + }, + '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', + } + } + } + } + } + } + } +} + +v = Validator(schema, allow_unknown=True) +aa={ + 'request_id': "111", + 'command': 'start', + 'pull_url': None, + 'push_url': None, + 'original_url': '', + 'original_type': '', + 'image_urls': ['1','1'], + 'results_base_dir': '111', + 'models': [ + # { + # 'code': '1', + # 'categories': [ + # # { + # # 'id': '1', + # # 'config': {} + # # } + # ] + # } + ] +} + +print(v.validate(aa)) +print(v.errors) \ No newline at end of file diff --git a/test/validate/__init__.py b/test/validate/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/video.py b/test/video.py new file mode 100644 index 0000000..cb1c8ea --- /dev/null +++ b/test/video.py @@ -0,0 +1,51 @@ +import time +from multiprocessing import Queue +from os import getpid + +import cv2 +import psutil +import requests +from moviepy.editor import VideoFileClip +from pymediainfo import MediaInfo + +# aa = time.time() +# try: +# clip = VideoFileClip("rtmp://192.168.10.101:19350/rlive/stream_107?sign=NQe66OXS") +# print("分辨率:", clip.size) +# print("帧率:", clip.fps) +# print("持续时间:", clip.duration) +# except: +# pass +# print(time.time() - aa) +# aa = time.time() +# cap = cv2.VideoCapture("rtmp://192.168.10.101:19350/rlive/stream_123?sign=w6RNKsFF") +# width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) +# height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) +# total_frames = int(cap.get(7)) +# fps = cap.get(cv2.CAP_PROP_FPS) +# duration = cap.get(cv2.CAP_PROP_POS_MSEC) / 1000 +# cap.release() +# print("分辨率:", (width, height)) +# print("帧率:", fps) +# print("持续时间:", duration) +# print("总帧数:", total_frames) +# print(time.time() - aa) +# aa = Queue() +# for i in range(1000): +# aa.put("1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +# "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +# "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111") +# aa.cancel_join_thread() +# aa.cancel_join_thread() +# aa.close() +# aa.cancel_join_thread() +# aa.cancel_join_thread() +# aa.close() +# aa.cancel_join_thread() +# aa.cancel_join_thread() +# aa.get() +# aa = time.time() +# psutil.Process(getpid()).ppid() +# print(time.time()-aa) + + diff --git a/test/webrtc/__init__.py b/test/webrtc/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/webrtc/test.py b/test/webrtc/test.py new file mode 100644 index 0000000..d2f59e3 --- /dev/null +++ b/test/webrtc/test.py @@ -0,0 +1,19 @@ +import cv2 +import numpy as np +# 创建VideoCapture对象并打开WebRTC视频流 +cap = cv2.VideoCapture('webrtc://221.230.150.241:10800/rtc/stream_14') +while True: + print(cap.isOpened()) + # 读取视频流的一帧 + ret, frame = cap.read() + if ret: + # 在这里进行帧处理 + # 例如,可以对每一帧进行图像处理、对象检测等操作 + # 显示处理后的帧 + cv2.imshow('Frame', frame) + # 按下'q'键退出循环 + if cv2.waitKey(1) & 0xFF == ord('q'): + break +# 释放VideoCapture对象和窗口 +cap.release() +cv2.destroyAllWindows() \ No newline at end of file diff --git a/test/while/__init__.py b/test/while/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/while/test.py b/test/while/test.py new file mode 100644 index 0000000..07f1cbe --- /dev/null +++ b/test/while/test.py @@ -0,0 +1,24 @@ +import time + +# def aa(): +# while True: +# +# print("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") +# return True +# +# +# # aa() +# +# aa = 810*3/2 +# aa_1 = 810*3//2 +# print(aa==aa_1, aa, aa_1) + +while True: + print("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + time.sleep(2) + num = 1 + while True: + time.sleep(1) + if num == 1: + print("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") + break diff --git a/test/wifi/__init__.py b/test/wifi/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/wifi/test.py b/test/wifi/test.py new file mode 100644 index 0000000..4075658 --- /dev/null +++ b/test/wifi/test.py @@ -0,0 +1,9 @@ +import subprocess + +result = subprocess.check_output(['netsh', 'wlan', 'show', 'network']) +result = result.decode('gbk') +lst = result.split('\r\n') +lst = lst[4:] +for index in range(len(lst)): + if index % 5 == 0: + print(lst[index]) \ No newline at end of file diff --git a/test/偏函数/__init__.py b/test/偏函数/__init__.py new file mode 100644 index 0000000..fb5e0b5 --- /dev/null +++ b/test/偏函数/__init__.py @@ -0,0 +1,5 @@ +import getopt +import keyword + +print(keyword.kwlist) +print(getopt.__doc__) \ No newline at end of file diff --git a/test/偏函数/cmp_to_key.py b/test/偏函数/cmp_to_key.py new file mode 100644 index 0000000..79933d6 --- /dev/null +++ b/test/偏函数/cmp_to_key.py @@ -0,0 +1,50 @@ +""" +python标准模块functools中的cmp_to_key可以将一个cmp函数变成一个key函数,从而支持自定义排序 +python的列表提供了sort方法,下面是该方法的一个示例 +""" +lst = [(9, 4), (2, 10), (4, 3), (3, 6)] +lst.sort(key=lambda item: item[0]) +print(lst) +""" +sort方法的key参数需要设置一个函数,这个函数返回元素参与大小比较的值,这看起来没有问题,但如果想实现更加复杂的自定义排序,就不那么容易了。 +目前的排序规则是根据元组里第一个元素的大小进行排序,我现在修改规则,如果元组里第一个元素是奇数,就用元组里第一个元素进行排序, +如果元组里第一个元素是偶数,则用这个元组里的第二个元组进行大小比较,面对这样的需求,列表的sort方法无法满足。 +对于这种情形,可以使用functools.cmp_to_key来解决 +""" +from functools import cmp_to_key +lst = [(9, 4), (2, 10), (4, 3), (3, 6)] +def cmp(x, y): + a = x[0] if x[0] % 2 == 1 else x[1] + b = y[0] if y[0] % 2 == 1 else y[1] + return 1 if a > b else -1 if a < b else 0 + +lst.sort(key=cmp_to_key(cmp)) +print(lst) +# 仍然使用sort进行排序,我实现了一个cmp函数,该函数实现了需求中所提到的要求,该函数最终要返回两个元组比较的大小关系,其实cmp_to_key的实现非常简单 + +def cmp_to_key(mycmp): + """Convert a cmp= function into a key= function""" + class K(object): + __slots__ = ['obj'] + def __init__(self, obj): + self.obj = obj + def __lt__(self, other): + return mycmp(self.obj, other.obj) < 0 + def __gt__(self, other): + return mycmp(self.obj, other.obj) > 0 + def __eq__(self, other): + return mycmp(self.obj, other.obj) == 0 + def __le__(self, other): + return mycmp(self.obj, other.obj) <= 0 + def __ge__(self, other): + return mycmp(self.obj, other.obj) >= 0 + __hash__ = None + return K +""" +它在内部定义了一个类K, 并使用我传入的cmp函数完成了比较关系运算符的重载,函数返回的是一个类,而sort函数的key需要的是一个函数, +看起来矛盾,但在python中,这样做完全可行,因为类和函数都是callable的,这里把类当成了函数来用。 +在本篇第一段代码中 +lst.sort(key=lambda item: item[0]) +lambda表达式生成的匿名函数返回的是元组的第一个元素进行大小比较,而现在,cmp_to_key返回的是类K,参与比较的是K的对象, +由于K已经实现了比较关系运算符重载,且算法就是我刚刚实现的cmp函数,这样就最终实现了自定义排序。 +""" diff --git a/test/偏函数/demo.py b/test/偏函数/demo.py new file mode 100644 index 0000000..1fca7a5 --- /dev/null +++ b/test/偏函数/demo.py @@ -0,0 +1,31 @@ +""" +1. 偏函数 +偏函数partial是functools 模块里提供的一个函数。和装饰器对比来理解,装饰器改变了一个函数的行为, +而偏函数不能改变一个函数的行为。偏函数只能根据已有的函数生成一个新的函数,这个新的函数完成已有函数相同的功能, +但是,这个新的函数的部分参数已被偏函数确定下来 + +2. 场景示例 +2.1 常规实现 +为了便于理解,我们构造一个使用场景,假设我们的程序要在dest目录下新建一些文件夹,那么常见的实现功能代码如下 +import os +from os import mkdir +mkdir(os.path.join('./dest', 'dir1')) +mkdir(os.path.join('./dest', 'dir2')) +mkdir(os.path.join('./dest', 'dir3')) +功能很简单,代码很简洁,但是有个小小的不如意之处,每次都是在dest目录下新建文件夹,既然它这么固定,是不是可以不用传递dest参数呢? +2.2 偏函数实现 +import os +from os import mkdir +from functools import partial + +dest_join = partial(os.path.join, './dest') +mkdir(dest_join('dir1')) +mkdir(dest_join('dir2')) +mkdir(dest_join('dir3')) + +dest_join是partial创建出来的一个新的函数,这个函数在执行时会调用os.path.join并将'./dest'作为参数传给join +偏函数将预先确定的参数冻结,起到了缓存的作用,在获得了剩余的参数后,连同之前冻结的确定参数一同传给最终的处理函数。 +虽然看起来代码没有减少,但如果你实际使用就会发现,用了偏函数,免去了反复输入相同参数的麻烦,尤其当这些参数很多很难记忆时 +""" + + diff --git a/test/偏函数/singledispatch.py b/test/偏函数/singledispatch.py new file mode 100644 index 0000000..ff287e8 --- /dev/null +++ b/test/偏函数/singledispatch.py @@ -0,0 +1,39 @@ +from functools import singledispatch + +class Stu(object): + def __init__(self, name): + self.name = name + + def wake_up(self): + print('起床') + +class Police(object): + def __init__(self, name): + self.name = name + + def wake_up(self): + print('起床') + + +@singledispatch +def wake_up(obj): + print('不处理') + + +@wake_up.register(Stu) +def wake_stu(obj): + print('今天周末休息,让孩子们再睡一会') + + +@wake_up.register(Police) +def wake_police(obj): + print('警察很辛苦,又要起床了') + obj.wake_up() + + +stu = Stu('小明') +police = Police('小明爸爸') + +wake_up(stu) +wake_police(police) +wake_up('一个字符串') \ No newline at end of file diff --git a/test/偏函数/wraps.py b/test/偏函数/wraps.py new file mode 100644 index 0000000..74f14e9 --- /dev/null +++ b/test/偏函数/wraps.py @@ -0,0 +1,26 @@ +import time +from functools import wraps + + +def cost(func): + @wraps(func) + def warpper(*args, **kwargs): + t1 = time.time() + res = func(*args, **kwargs) + t2 = time.time() + print(func.__name__ + "执行耗时" + str(t2-t1)) + return res + return warpper + +@cost +def test(sleep_time): + """ + 测试装饰器 + :param sleep_time: + :return: + """ + time.sleep(sleep_time) + + +print(test.__name__) +print(test.__doc__) \ No newline at end of file diff --git a/test/元类/__init__.py b/test/元类/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/元类/demo1.py b/test/元类/demo1.py new file mode 100644 index 0000000..95b9356 --- /dev/null +++ b/test/元类/demo1.py @@ -0,0 +1,121 @@ +# -*- coding: utf-8 -*- +class Test: + pass + +print(type(Test)) +print(type(int)) + +# 结果都为,type就是内置的元类,class关键字定义的所有的类以及内置的类都是由元类type实例化产生。 + +""" + 由于在python3中没有经典类和新式类的区别,因此python3中object是所有类的基类,那内置元类type又是什么? + type是object类的类型,总结来说就是type是object的类型,同时,object又是type的基类,这句话看起来就有问题, + 到底是先有type还是先有object呢?这个问题有点类似于先有鸡还是先有蛋,我们可以通过代码简单分析一下 + + 在python3中类和类型是同一种东西,因此对象.__class__和type(对象)得到的结果是一致的,object的基类为空, + 但是type的基类为object,但是object的类型又是type。 +""" +print(type(object)) +print(object.__class__) + +print(type(type)) +print(type.__class__) + +print(object.__bases__) +print(type.__bases__) + +# python字符串 +strs = """ +global name +global age +name = 'py' +age = 18 +addr = 'xx' +""" +# 定义全局作用域中的名字和值 +globals = { + 'a': '1', + 'b': '2' +} +# 定义局部作用域中的名字和值 +locals = { + 'x': 3, + 'y': 4 +} +exec(strs, globals, locals) +print(globals['name']) +print(locals) + +# 了解了exec的作用之后,就可以分析class关键字如何借助type元类产生类的步骤: +# 1 定义类名 +class_name = 'Test' + +# 2 定义类的基类(父类) +class_bases = (object,) + +# 3 执行类体代码拿到类的名称空间 +class_dic = {} + +# 4 定义类体代码(本质是字符串) +class_body = """ +def __init__(self,name,age): + self.name=name + self.age=age + +def test(self): + print('%s:%s' %(self.name,self.name)) +""" +# 5 将字符串转为python能识别的语法:将class_body运行时产生的名字存入class_dic中 +exec(class_body, {}, class_dic) +# 查看类的名称空间 +print(class_dic) +# 6 调用元类产生类 +Test = type(class_name, class_bases, class_dic) +# 7 调用类产生对象 +t = Test('python', '12') +t.test() + +# 自定义元类 +class MyMeta(type): # 自定义元类必须继承type,否则就是普通的类 + + ''' + 早于__init__方法执行,必须返回空对象,由于该方法是调用类后第一个运行的方法, + 此时并没有对象产生,因此该方法的第一个参数必须是类本身(MyMeta),*args, **kwargs + 用来接收调用元类产生对象所需的参数(类名 类的基类 名称空间) + ''' + def __new__(cls, *args, **kwargs): + return type.__new__(cls, *args, **kwargs) # 直接调用父类type中的__new__方法 + + ''' + 通过__init__控制类的产生,调用自定义元类与调用内置元类type的方式相同, + 需要传入类名、类的父类们、类体代码的名称空间,__init__方法中第一个参数来自于__new__方法产生的空对象。 + ''' + def __init__(self, class_name, class_bases, class_dict): + + ''' + 在该方法内可以控制类的产生 + ''' + if not class_name.istitle(): # 实现类名首字母必须大写,否则抛出异常 + raise NameError('类名的首字母必须大写') + + if '__doc__' not in class_dict or len(class_dict['__doc__'].strip())==0: # 实现类必须有文档注释,否则抛出异常 + raise TypeError('必须有文档注释') + + def __call__(self, *args, **kwargs): + print(self) + print(args) + print(kwargs) + return 'test' + +class Test(metaclass=MyMeta): + + ''' + 我是文档注释 + ''' + + def __init__(self): + self.name = 'python' + + def test(self): + print('test') +t = Test() \ No newline at end of file diff --git a/test/内存优化/slots/test.py b/test/内存优化/slots/test.py new file mode 100644 index 0000000..d9c3f06 --- /dev/null +++ b/test/内存优化/slots/test.py @@ -0,0 +1,49 @@ +import sys +import time +from collections import namedtuple + +from memory_profiler import profile + +class A: + + __slots__ = ('_name', '_age', '_score') + + def __init__(self, name=None, age=None, score=None): + self._name = 'aaaa' + self._age = 'vbba' + self._score = '1111' + + def test1(self): + num =1 + while True: + num = num + 1 + if num > 1000000: + break + ddd=self._name + for i in range(100): + ddd + +class B(A): + # __slots__ = () + def __init__(self): + super().__init__() + + def test(self): + print(self._name) +a= A() +b = B() +b.test() +# print(b._name) +# print(sys.getsizeof(a), sys.getsizeof(b)) +# print(sys.getsizeof(a.__dict__), sys.getsizeof(b.__dict__)) +@profile +def main(): + Point = namedtuple('Point', ('x', 'y', 'z')) + object_list = [Point(i,i,i) for i in range(100000)] + +if __name__=='__main__': + # main() + # print(A().__dict__) + ss = time.time() + A().test1() + print(time.time() - ss) \ No newline at end of file diff --git a/test/内存优化/slots/test1.py b/test/内存优化/slots/test1.py new file mode 100644 index 0000000..048a562 --- /dev/null +++ b/test/内存优化/slots/test1.py @@ -0,0 +1,200 @@ +# # # import timeit +# # # class MyClass: +# # # @staticmethod +# # # def my_static_method(): +# # # pass +# # # def my_function(): +# # # pass +# # # # 通过类名调用静态方法 +# # # def test_static_method(): +# # # MyClass.my_static_method() +# # # # 通过函数名调用函数方法 +# # # def test_function(): +# # # my_function() +# # # # 测试执行速度 +# # # print("static method: ", timeit.timeit(test_static_method, number=10000000)) +# # # print("function: ", timeit.timeit(test_function, number=10000000)) +# # import copy +# # import os +# # import pickle +# # import time +# # import timeit +# # import traceback +# # from collections import namedtuple +# # from concurrent.futures import ThreadPoolExecutor +# # from multiprocessing import Queue +# # from threading import Thread +# # +# # import cv2 +# # import psutil +# # +# # # def mu(): +# # # aa ={ +# # # 'half': 1, +# # # 'iou_thres': (1,2,3), +# # # 'allowedList': [1,3], +# # # 'aa': {"1":"2"}, +# # # } +# # # bb = aa.copy() +# # # def mu1(): +# # # aa ={ +# # # 'half': 1, +# # # 'iou_thres': (1,2,3), +# # # 'allowedList': [1,3], +# # # 'aa': {"1":"2"}, +# # # } +# # # # copy.deepcopy(aa) +# # # print(pickle.loads(pickle.dumps(aa))) +# # # mu1() +# # # print("static method1: ", timeit.timeit(mu, number=100000)) +# # # print("static method2: ", timeit.timeit(mu1, number=100000)) +# # +# # +# # # def aa(): +# # # Point = namedtuple('Point', ('x', 'y', 'z')) +# # # aa = Point("1111111111", "22222222222", "333333333333") +# # # aa.x +# # # aa.y +# # # aa.z +# # # def aa1(): +# # # aa = ["1111111111", "22222222222", "333333333333"] +# # # aa[0] +# # # aa[1] +# # # aa[2] +# # # print("static method1: ", timeit.timeit(aa, number=100000)) +# # # print("static method2: ", timeit.timeit(aa1, number=100000)) +# # # aa=[] +# # # aa[28] = "11111" +# # # print(aa) +# # # def aa1(): +# # # # 获取当前进程的父进程的PID +# # # if psutil.pid_exists(psutil.Process(os.getpid()).ppid()): +# # # print("11111") +# # # else: +# # # print("2222") +# # # print("static method2: ", timeit.timeit(aa1, number=100)) +# # # def aa(): +# # # num=1 +# # # while num < 100: +# # # num+=1 +# # # time.sleep(100) +# # # dd = Thread(target=aa, args=()) +# # # dd.setDaemon(True) +# # # dd.start() +# # # try: +# # # dd.join(1) +# # # except Exception: +# # # print(traceback.format_exc()) +# # # a = Queue() +# # # aa = {"aa": "11"} +# # # a.put(aa) +# # # bb = a.get() +# # # bb["aa"] = "2222" +# # # print(aa) +# # # print(bb) +# # +# # +# # # def dd(): +# # # w = ["1111", "2222", "3333"] +# # # a = w[2] +# # # +# # # +# # # def cc(): +# # # aa = {"aa": "1111", "bb": "2222", "cc": "3333"} +# # # t= aa["cc"] +# # # +# # # print("static method1: ", timeit.timeit(dd, number=1000)) +# # # print("static method2: ", timeit.timeit(cc, number=1000)) +# # import numpy as np +# # +# # +# # # # 创建一个numpy数组 +# # # arr1 = np.array([[[1,2,3]], [[2,3, 4]]]) +# # # # 使用copy()方法深度拷贝数组 +# # # arr2 = arr1.copy() +# # # # 修改arr2中的元素 +# # # arr2[0][0][1] = 5 +# # # # 打印arr1和arr2 +# # # print("arr1:", arr1) +# # # print("arr2:", arr2) +# # # def cop2(): +# # # arr1 = np.array([[1, 2], [3, 4]]) +# # # arr2 = arr1 +# # # def cop(): +# # # arr1 = np.array([[1, 2], [3, 4]]) +# # # arr2 = arr1.copy() +# # # def cop1(): +# # # arr1 = np.array([[1, 2], [3, 4]]) +# # # arr2 = copy.deepcopy(arr1) +# # # print("static method1: ", timeit.timeit(cop2, number=1000)) +# # # print("static method1: ", timeit.timeit(cop, number=1000)) +# # # print("static method2: ", timeit.timeit(cop1, number=1000)) +# # +# # # aa = {} +# # # def dd(aa): +# # # aa["aa"] = 1 +# # # +# # # dd(aa) +# # # print(aa) +# # +# # def aa(num): +# # while True: +# # time.sleep(4) +# # num+= 1 +# # raise Exception("1111") +# # +# # +# # def dd(): +# # num = 1 +# # with ThreadPoolExecutor(max_workers=1) as t: +# # ddd = t.submit(aa, num) +# # while True: +# # ddd.result() +# # time.sleep(1) +# # print(num) +# # +# # image = cv2.imread(r'D:\tuoheng\codenew\tuoheng_alg\image\logo.png') +# # image1 = np.array(image) +# # or_result, or_image = cv2.imencode(".jpg", image1) +# # aa = or_image.tobytes() +# # +# # numpy_array = np.frombuffer(aa, dtype=np.uint8) +# # img_bgr = cv2.cvtColor(numpy_array, cv2.COLOR_RGB2BGR) +# # cv2.sh +# # print(img_bgr) +# import os +# import time +# from os import getpid +# +# import psutil +# +# +# from multiprocessing import Process +# +# def fun2(name, pid): +# while True: +# time.sleep(1) +# print("fun2", getpid(), os.getppid(), psutil.Process(getpid()).ppid(), psutil.pid_exists(psutil.Process(getpid()).ppid())) +# +# def fun1(name): +# print('测试%s多进程' %name) +# p = Process(target=fun2,args=('Python',getpid(),)) #实例化进程对象 +# # p.daemon = True +# p.start() +# print("funn1", getpid(), p.pid) +# +# +# +# if __name__ == '__main__': +# p = Process(target=fun1,args=('Python',)) #实例化进程对象 +# # p.daemon = True +# p.start() +# +# +# print('结束测试', os.getpid()) +# +listeningProcesses={"11111": "1111", "2222": "2222"} + +p = list(listeningProcesses.keys()) +p.reverse() +print(p) \ No newline at end of file diff --git a/test/内置函数/__init__.py b/test/内置函数/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/内置函数/test.py b/test/内置函数/test.py new file mode 100644 index 0000000..4f8d0aa --- /dev/null +++ b/test/内置函数/test.py @@ -0,0 +1,11 @@ + + + +# key参数,表示使用指定的方法来比较大小,而不是使用原数据比较大小 +x = (2, 3, 4, 5) +print(max(x)) + +print(max(x, key=lambda z: 1 / z)) + +############################### collections ################################# + diff --git a/test/协程/__init__.py b/test/协程/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/协程/asnyc.py b/test/协程/asnyc.py new file mode 100644 index 0000000..658bc9e --- /dev/null +++ b/test/协程/asnyc.py @@ -0,0 +1,19 @@ +import asyncio +import time + + +async def task(): + print(f"{time.strftime('%H:%M:%S')} task 开始 ") + time.sleep(2) + print(f"{time.strftime('%H:%M:%S')} task 结束") + + +coroutine = task() +print(f"{time.strftime('%H:%M:%S')} 产生协程对象 {coroutine},函数并未被调用") +loop = asyncio.get_event_loop() +print(f"{time.strftime('%H:%M:%S')} 开始调用协程任务") +start = time.time() +loop.run_until_complete(coroutine) +end = time.time() +print(f"{time.strftime('%H:%M:%S')} 结束调用协程任务, 耗时{end - start} 秒") + diff --git a/test/协程/asnyc回调.py b/test/协程/asnyc回调.py new file mode 100644 index 0000000..dee6177 --- /dev/null +++ b/test/协程/asnyc回调.py @@ -0,0 +1,27 @@ +import asyncio +import time + + +async def _task(): + print(f"{time.strftime('%H:%M:%S')} task 开始 ") + time.sleep(2) + print(f"{time.strftime('%H:%M:%S')} task 结束") + return "运行结束" + + +def callback(task): + print(f"{time.strftime('%H:%M:%S')} 回调函数开始运行") + print(f"状态:{task.result()}") + + +coroutine = _task() +print(f"{time.strftime('%H:%M:%S')} 产生协程对象 {coroutine},函数并未被调用") +task = asyncio.ensure_future(coroutine) # 返回task对象 +task.add_done_callback(callback) # 为task增加一个回调任务 +loop = asyncio.get_event_loop() +print(f"{time.strftime('%H:%M:%S')} 开始调用协程任务") +start = time.time() +loop.run_until_complete(task) +end = time.time() +print(f"{time.strftime('%H:%M:%S')} 结束调用协程任务, 耗时{end - start} 秒") + diff --git a/test/协程/协程.py b/test/协程/协程.py new file mode 100644 index 0000000..085e5c0 --- /dev/null +++ b/test/协程/协程.py @@ -0,0 +1,24 @@ +#-*- coding:utf8 -*- +def consumer(): + r = '' + while True: + n = yield r + if not n: + return + print('[CONSUMER]Consuming %s...' % n) + r = '200 OK' + +def producer(c): + # 启动生成器 + c.send(None) + n = 0 + while n < 5: + n = n + 1 + print('[PRODUCER]Producing %s...' % n) + r = c.send(n) + print('[PRODUCER]Consumer return: %s' % r) + c.close() + +if __name__ == '__main__': + c = consumer() + producer(c) \ No newline at end of file diff --git a/test/协程/协程1.py b/test/协程/协程1.py new file mode 100644 index 0000000..de7960f --- /dev/null +++ b/test/协程/协程1.py @@ -0,0 +1,13 @@ +import asyncio + +@asyncio.coroutine +def test(i): + print('test_1', i) + r = yield from asyncio.sleep(1) + print('test_2', i) + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + tasks = [test(i) for i in range(3)] + loop.run_until_complete(asyncio.wait(tasks)) + loop.close() \ No newline at end of file diff --git a/test/协程/协程2.py b/test/协程/协程2.py new file mode 100644 index 0000000..02ff317 --- /dev/null +++ b/test/协程/协程2.py @@ -0,0 +1,49 @@ +# import asyncio +# import threading +# import time +# +# +# async def print_hello(d): +# print("aaaaaaaaaaa") +# await asyncio.sleep(d) +# print("nnnnnnnnnnnnn") +# return 11 +# +# async def print_hello1(d): +# print("ssssssssssssssss") +# await asyncio.sleep(2) +# print("qqqqqqqqqqqqq") +# return 22 +# def aa(d): +# loop = asyncio.new_event_loop() +# asyncio.set_event_loop(loop) +# start = time.time() +# aaaa = loop.run_until_complete(asyncio.gather(print_hello(1), print_hello(2))) +# print(aaaa) +# # aa = loop.run_until_complete(asyncio.wait(tasks1)) +# # asyncio.gather() +# # print(aa[0].pop().result()) +# # asyncio.run(print_hello()) +# # asyncio.run(print_hello1()) +# # async def main(): +# # task = asyncio.create_task(print_hello()) +# # task1 = asyncio.create_task(print_hello1()) +# # # await task +# # # await task1 +# # asyncio.run(main()) +# print("ddddddddddddddddddddddd", time.time() - start) +# +# threading.Thread(target=aa, args=(1,)).start() +# # threading.Thread(target=aa, args=(loop, 2)).start() +# # threading.Thread(target=aa, args=(loop, 2)).start() +# # loop.close() +# # loop.close() +# # 打印结果 +# # cccccccccccccccccccccc +# # aaaaaaaaaaa +# # nnnnnnnnnnnnn +# # ssssssssssssssss +# # qqqqqqqqqqqqq +# # ddddddddddddddddddddddd +a = lambda x: print(x) +a(1) \ No newline at end of file diff --git a/test/协程/协程3.py b/test/协程/协程3.py new file mode 100644 index 0000000..ee60d8b --- /dev/null +++ b/test/协程/协程3.py @@ -0,0 +1,10 @@ +import time +from concurrent.futures import ThreadPoolExecutor +def aa(a): + print("aaaaaa") + time.sleep(2) + +with ThreadPoolExecutor(max_workers=2) as t: + while True: + time.sleep(10) + t.submit(aa, 1) diff --git a/test/协程/协程笔记.py b/test/协程/协程笔记.py new file mode 100644 index 0000000..88aabb5 --- /dev/null +++ b/test/协程/协程笔记.py @@ -0,0 +1,34 @@ +import asyncio +import time + + +async def sleep(delay): + time.sleep(delay) + print("1111") + + +async def say_after(delay, what): + await sleep(delay) + print(what) + +async def main(): + task1 = asyncio.create_task(say_after(1, 'hello')) + task2 = asyncio.create_task(say_after(2, 'world')) + # await task1 + # await task2 + await asyncio.gather(task1, task2) + # await say_after(1, 'hello') + # await say_after(2, 'world') + + +start = time.time() +loop = asyncio.new_event_loop() +print(loop) +asyncio.set_event_loop(loop) +task1 = loop.create_task(say_after(1, 'hello')) +task2 = loop.create_task(say_after(2, 'world')) +loop.run_until_complete(asyncio.wait([task1, task2])) +loop.close() +# asyncio.run(main()) +print(time.time() - start) + diff --git a/test/字典/__init__.py b/test/字典/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/字典/字典.py b/test/字典/字典.py new file mode 100644 index 0000000..aa7c1ed --- /dev/null +++ b/test/字典/字典.py @@ -0,0 +1,12 @@ +# aa = {"aa": "aa", "a1": "a1", "a2": "a2"} +# print(aa.pop("aa")) +# print(aa) + +# b = {"11": "11"} +# c = {"12": "12"} +# b.update(c) +# b.update(c) +# print(b) + +aa = list(range(0, 1, 10)) +print(aa) \ No newline at end of file diff --git a/test/序列化/Test.py b/test/序列化/Test.py new file mode 100644 index 0000000..b5aa431 --- /dev/null +++ b/test/序列化/Test.py @@ -0,0 +1,23 @@ +from loguru import logger +import pickle +from loguru import logger +# 定义一个类 +# class Person: +# def __init__(self, name, age): +# self.name = name +# self.age = age +# +# # 创建一个Person实例 +# person = Person("Alice", 25) +# +# # 使用Loguru的serialize方法将Person实例序列化为字节字符串 +# serialized_person = logger.serialize(person) +# print(serialized_person) +# # 使用pickle库将字节字符串反序列化为Python对象 +# deserialized_person = pickle.loads(serialized_person) +# +# # 输出反序列化后的对象属性 +# print(deserialized_person.name) # Alice +# print(deserialized_person.age) # 25 +aa = {"name": "11111"} +logger.info(aa) \ No newline at end of file diff --git a/test/序列化/__init__.py b/test/序列化/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/序列化/test1.py b/test/序列化/test1.py new file mode 100644 index 0000000..ba03f91 --- /dev/null +++ b/test/序列化/test1.py @@ -0,0 +1,21 @@ +import sys + +import msgpack + +stu = { + 'name': 'lili', + 'age': 18, + 'score': 100 +} + +msg_str = msgpack.packb(stu) +print(msg_str) +print(len(msg_str)) +print(sys.platform) +print(sys.byteorder) +print(sys.modules) +print(sys.thread_info) +print(sys.implementation) +print(sys.hash_info) +print(sys.getwindowsversion()) +print(sys.getrecursionlimit()) \ No newline at end of file diff --git a/test/异常/__init__.py b/test/异常/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/异常/test.py b/test/异常/test.py new file mode 100644 index 0000000..9596ef6 --- /dev/null +++ b/test/异常/test.py @@ -0,0 +1,6 @@ +""" +1. try-except +2. try-except-except +3. try-except-else +4. try-except-finally +""" \ No newline at end of file diff --git a/test/日志/test.py b/test/日志/test.py new file mode 100644 index 0000000..406d2f3 --- /dev/null +++ b/test/日志/test.py @@ -0,0 +1,5 @@ + + +from os import environ + +print("LOGURU_TRACE_NO" not in environ) \ No newline at end of file diff --git a/test/正则/__init__.py b/test/正则/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/正则/__pycache__/re.cpython-38.pyc b/test/正则/__pycache__/re.cpython-38.pyc new file mode 100644 index 0000000..87b35c3 Binary files /dev/null and b/test/正则/__pycache__/re.cpython-38.pyc differ diff --git a/test/正则/demo.py b/test/正则/demo.py new file mode 100644 index 0000000..0d29dcc --- /dev/null +++ b/test/正则/demo.py @@ -0,0 +1,29 @@ +# -*- coding: UTF-8 -*- + +import re +print(re.match('www', 'www.runoob.com').span()) # 在起始位置匹配 +print(re.match('com', 'www.runoob.com')) # 不在起始位置匹配 + +line = "Cats are smarter than dogs"; + +matchObj = re.match(r'dogs', line, re.M|re.I) +if matchObj: + print("match --> matchObj.group() : ", matchObj.group()) +else: + print("No match!!") + +matchObj = re.search(r'dogs', line, re.M|re.I) +if matchObj: + print("search --> searchObj.group() : ", matchObj.group()) +else: + print("No match!!") + +phone = "2004-959-559 # 这是一个国外电话号码" + +# 删除字符串中的 Python注释 +num = re.sub(r'#.*$', "", phone) +print("电话号码是: ", num) + +# 删除非数字(-)的字符串 +num = re.sub(r'\D', "", phone) +print("电话号码是 : ", num) \ No newline at end of file diff --git a/test/正则/re.py b/test/正则/re.py new file mode 100644 index 0000000..f8c1aba --- /dev/null +++ b/test/正则/re.py @@ -0,0 +1,145 @@ +import re +''' +1.匹配某个字符串 +match():只能匹配某个 +''' +# text = 'python python' +# result = re.match('py', text) +# print(result) +# print(result.group()) + +''' +2.点 +匹配任意的某个字符【无法匹配换行符】【必须从开头开始匹配】 +''' +# text = 'python' +# result = re.match('.', text) +# print(result) +# print(result.group()) + +''' +3.\d +匹配任意的数字【除了数字外均无法匹配】 +''' +# text = '1python' +# result = re.match('\d', text) +# print(result) +# print(result.group()) + +''' +4.\D +除了数字外均可匹配【数字均无法匹配】 +''' +# text = 'python' +# result = re.match('\D', text) +# print(result) +# print(result.group()) + +''' +5.\s +匹配空白字符【\n、 \t、 \r 、空格】 +''' +# text = '\npython' +# result = re.match('\s', text) +# print(result) +# print(result.group()) + +''' +6.\w +匹配小写的a-z,大写的A-Z,数字和下划线 +''' +# text = 'python' +# result = re.match('\w', text) +# print(result) +# print(result.group()) + +''' +7.\W +匹配除小写\w之外的所有字符 +''' +# text = '\npython' +# result = re.match('\W', text) +# print(result) +# print(result.group()) + +''' +8.[] ->> 组合的方式 +只要在中括号内的内容均可匹配 +''' +# text = '\npython' +# result = re.match('[\n_]', text) +# print(result) +# print(result.group()) + +''' +9.星号 * +匹配零个或者多个字符 +''' +# text = '139-1234-5678' +# result = re.match('[-\d]*', text) +# print(result) +# print(result.group()) + +''' +10.加号 + +匹配1个或者多个字符 +''' +# text = '139-1234-5678' +# result = re.match('[-\d]+', text) +# print(result) +# print(result.group()) + +''' +11.问号 ? +匹配0个或者匹配1个 +''' +# text = '139-1234-5678' +# result = re.match('[-\d]?', text) +# print(result) +# print(result.group()) + +''' +12. {m,n} 匹配m到n个 +匹配0个或者匹配1个 +''' +# text = '139-1234-5678' +# result = re.match('[-\d]{1,5}', text) +# print(result) +# print(result.group()) + +''' +13. 匹配所有的数字 +''' +# text = '139-1234-5678' +# result = re.match('[-0-9]*', text) +# print(result) +# print(result.group()) + +''' +14. 匹配所有的非数字 +''' +# text = '139-1234-5678' +# result = re.match('[^0-9]*', text) +# print(result) +# print(result.group()) + +# re.match() 必须从字符串开头进行匹配 +# re.search() 从左到右进行字符串的遍历,找到就返回 +# text = 'aapython' +# result = re.match('py', text) +# print(result) +# print(result.group()) + +# text = 'aapython' +# result = re.search('py', text) +# print(result) +# print(result.group()) + +""" +1. 贪婪模式: 正则表达式会尽可能多地匹配字符【默认就是贪婪模式】 +2. 非贪婪模式: 正则表达式会尽可能少地匹配字符【?】 + +转义字符 \ +""" + + diff --git a/test/水印/ORB算法.py b/test/水印/ORB算法.py new file mode 100644 index 0000000..cf98486 --- /dev/null +++ b/test/水印/ORB算法.py @@ -0,0 +1,44 @@ + +# 自定义计算两个图片相似度函数 +import cv2 + + +def img_similarity(img1_path, img2_path): + """ + :param img1_path: 图片1路径 + :param img2_path: 图片2路径 + :return: 图片相似度 + """ + try: + # 读取图片 + img1 = cv2.imread(img1_path, cv2.IMREAD_GRAYSCALE) + img2 = cv2.imread(img2_path, cv2.IMREAD_GRAYSCALE) + + # 初始化ORB检测器 + orb = cv2.ORB_create() + kp1, des1 = orb.detectAndCompute(img1, None) + kp2, des2 = orb.detectAndCompute(img2, None) + + # 提取并计算特征点 + bf = cv2.BFMatcher(cv2.NORM_HAMMING) + + # knn筛选结果 + matches = bf.knnMatch(des1, trainDescriptors=des2, k=2) + + # 查看最大匹配点数目 + good = [m for (m, n) in matches if m.distance < 0.75 * n.distance] + # print(len(good)) + # print(len(matches)) + similary = float(len(good))/len(matches) + print("(ORB算法)两张图片相似度为:%s" % similary) + return similary + + except: + print('无法计算两张图片相似度') + return '0' +if __name__ == '__main__': + name1='image/AI.jpg' + name2='image/AI3.jpg' + # similary 值为0-1之间,1表示相同 + similary = img_similarity(name1, name2) + print(similary) \ No newline at end of file diff --git a/test/水印/__init__.py b/test/水印/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/水印/same1.py b/test/水印/same1.py new file mode 100644 index 0000000..a79fa29 --- /dev/null +++ b/test/水印/same1.py @@ -0,0 +1,46 @@ +import cv2 +import os +from matplotlib import pyplot as plt + +def FLANN(): + + targetPath = 'AI.jpg' + trainingImage = cv2.imread(targetPath, flags=0) + + templatePath = 'image/' + icons = os.listdir(templatePath) + iconMatch= dict({'name': '未识别', 'value': 0}) + for icon in icons: + queryImage = cv2.imread(templatePath + icon, 0) + + sift = cv2.SIFT_create() + kp1, des1 = sift.detectAndCompute(queryImage, None) + kp2, des2 = sift.detectAndCompute(trainingImage, None) + + indexParams = dict(algorithm=0, trees=5) + searchParams = dict(checks=50) + flann = cv2.FlannBasedMatcher(indexParams,searchParams) + matches = flann.knnMatch(des1,des2,k=2) + + matchesMask = [[0,0] for i in range(len(matches))] + matchNumber = 0 + + for i,(m,n) in enumerate(matches): + if m.distance < 0.7 * n.distance: + matchesMask[i] = [1,0] + matchNumber = matchNumber+1 + + drawParams = dict(matchColor = (0,255,0), matchesMask = matchesMask[:50], flags = 0) + resultImage = cv2.drawMatchesKnn(queryImage,kp1,trainingImage,kp2,matches[:50],None,**drawParams) + + if matchNumber > iconMatch['value']: + iconMatch['name'] = icon.split('_')[0] + iconMatch['value'] = matchNumber + + return resultImage, iconMatch + +if __name__ == '__main__': + resultImage, res = FLANN() + # plt.imshow(resultImage) + # plt.show() + print(resultImage, res) diff --git a/test/水印/same2.py b/test/水印/same2.py new file mode 100644 index 0000000..7cec491 --- /dev/null +++ b/test/水印/same2.py @@ -0,0 +1,21 @@ +import cv2 + +target = cv2.imread("image/AI.jpg") + +template = cv2.imread("image/AI1.jpg") + +theight, twidth = template.shape[:2] + +result = cv2.matchTemplate(target,template,cv2.TM_CCOEFF_NORMED) +print(result) +cv2.normalize( result, result, 0, 1, cv2.NORM_MINMAX, -1 ) + +min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result) +print(min_val, max_val, max_loc) +strmin_val = str(min_val) + +cv2.rectangle(target,min_loc,(min_loc[0]+twidth,min_loc[1]+theight),(0,0,225),2) + +# cv2.imshow("MatchResult----MatchingValue="+strmin_val,target) +# cv2.waitKey() +# cv2.destroyAllWindows() \ No newline at end of file diff --git a/test/水印/same3.py b/test/水印/same3.py new file mode 100644 index 0000000..e1009fd --- /dev/null +++ b/test/水印/same3.py @@ -0,0 +1,18 @@ +import os +import cv2 +# from skimage.measure import compare_ssim +# from skimage.metrics import _structural_similarity +from skimage.metrics import structural_similarity as ssim + + +if __name__ == '__main__': + img00 = cv2.imread('image/AI.jpg') + img10 = cv2.imread('image/AI3.jpg') + img0 = cv2.cvtColor(img00,cv2.COLOR_BGR2GRAY) # 将图像转换为灰度图 + img1 = cv2.cvtColor(img10,cv2.COLOR_BGR2GRAY) # 将图像转换为灰度图 + #进行结构性相似度判断 + # ssim_value = _structural_similarity.structural_similarity(img,img1,multichannel=True) + score= ssim(img0, img1) + print(score) + + diff --git a/test/水印/互信息.py b/test/水印/互信息.py new file mode 100644 index 0000000..00e3eb3 --- /dev/null +++ b/test/水印/互信息.py @@ -0,0 +1,8 @@ +from PIL import Image +from pixelmatch.contrib.PIL import pixelmatch +img_a = Image.open("../image/AI.jpg") +img_b = Image.open("../image/AI3.jpg") +img_diff = Image.new("RGBA", img_a.size) +# note how there is no need to specify dimensions +mismatch = pixelmatch(img_a, img_b, img_diff, includeAA=True) +print(mismatch) \ No newline at end of file diff --git a/test/水印/余弦相似度计算.py b/test/水印/余弦相似度计算.py new file mode 100644 index 0000000..9dcb445 --- /dev/null +++ b/test/水印/余弦相似度计算.py @@ -0,0 +1,97 @@ +## -*- coding: utf-8 -*- +# !/usr/bin/env python +# 余弦相似度计算 +import time + +import cv2 +from PIL import Image +from numpy import average, dot, linalg +# 对图片进行统一化处理 +def get_thum(image, size=(64, 64), greyscale=False): + # 利用image对图像大小重新设置, Image.ANTIALIAS为高质量的 + image = image.resize(size, Image.ANTIALIAS) + if greyscale: + # 将图片转换为L模式,其为灰度图,其每个像素用8个bit表示 + image = image.convert('L') + return image +# 计算图片的余弦距离 +def image_similarity_vectors_via_numpy(image1, image2): + image1 = get_thum(image1) + image2 = get_thum(image2) + images = [image1, image2] + vectors = [] + norms = [] + for image in images: + vector = [] + for pixel_tuple in image.getdata(): + vector.append(average(pixel_tuple)) + vectors.append(vector) + # linalg=linear(线性)+algebra(代数),norm则表示范数 + # 求图片的范数 + norms.append(linalg.norm(vector, 2)) + a, b = vectors + a_norm, b_norm = norms + # dot返回的是点积,对二维数组(矩阵)进行计算 + res = dot(a / a_norm, b / b_norm) + return res + + +#差值感知算法 +def dHash(image): + #缩放9*8 + image=cv2.resize(image,(9,8),interpolation=cv2.INTER_CUBIC) + #转换灰度图 + image=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) + # print(image.shape) + hash=[] + #每行前一个像素大于后一个像素为1,相反为0,生成哈希 + for i in range(8): + for j in range(8): + if image[i,j]>image[i,j+1]: + hash.append(1) + else: + hash.append(0) + return hash + +#计算汉明距离 +def Hamming_distance(hash1,hash2): + num = 0 + for index in range(len(hash1)): + if hash1[index] != hash2[index]: + num += 1 + return num + +if __name__ == '__main__': + # 把图片表示成一个向量,通过计算向量之间的余弦距离来表征两张图片的相似度 0.9760 + image1 = cv2.imread('../image/1.jpg') + image2 = cv2.imread('../image/2.jpg') + # image3 = cv2.imread('image/AI2.jpg') + # image4 = cv2.imread('image/AI3.jpg') + # image5 = cv2.imread('image/AI4.jpg') + # image6 = cv2.imread('a.jpg') + # image7 = cv2.imread('AI.jpg') + hash1 = dHash(image1) + hash2 = dHash(image2) + # hash3 = dHash(image3) + # hash4 = dHash(image4) + # hash5 = dHash(image5) + # hash6 = dHash(image6) + # hash7 = dHash(image7) + start = time.time() + dist = Hamming_distance(hash1, hash2) + #将距离转化为相似度 + similarity = 1 - dist * 1.0 / 64 + # print(dist) + print(similarity, time.time() - start) + # cosin = image_similarity_vectors_via_numpy(image1, image2) + # print('图片余弦相似度', cosin) + # cosin1 = image_similarity_vectors_via_numpy(image1, image3) + # print('图片余弦相似度', cosin1) + # cosin2 = image_similarity_vectors_via_numpy(image1, image4) + # print('图片余弦相似度', cosin2) + # cosin3 = image_similarity_vectors_via_numpy(image1, image5) + # print('图片余弦相似度', cosin3) + # cosin4 = image_similarity_vectors_via_numpy(image5, image6) + # print('图片余弦相似度', cosin4) + # cosin5 = image_similarity_vectors_via_numpy(image1, image6) + # print('图片余弦相似度', cosin5) \ No newline at end of file diff --git a/test/水印/视频添加图片水印1.py b/test/水印/视频添加图片水印1.py new file mode 100644 index 0000000..44de721 --- /dev/null +++ b/test/水印/视频添加图片水印1.py @@ -0,0 +1,46 @@ +import cv2 +import numpy as np + + +def watermark(src_path, mask_path, alpha=1): + # 读取原图 + img = src_path + # 获取原图高和宽度 + h, w = img.shape[0], img.shape[1] + # 读取LOG + mask = mask_path + if w > h: + rate = int(w * 0.1) / mask.shape[1] + else: + rate = int(h * 0.1) / mask.shape[0] + mask = cv2.resize(mask, None, fx=rate, fy=rate, interpolation=cv2.INTER_NEAREST) + mask_h, mask_w = mask.shape[0], mask.shape[1] + mask_channels = cv2.split(mask) + dst_channels = cv2.split(img) + b, g, r, a = cv2.split(mask) + + # 计算mask在图片的坐标 + ul_points = (int(h * 0.9), int(int(w / 2) - mask_w / 2)) + dr_points = (int(h * 0.9) + mask_h, int(int(w / 2) + mask_w / 2)) + for i in range(3): + dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] = dst_channels[i][ + ul_points[0]: dr_points[0], + ul_points[1]: dr_points[1]] * ( + 255.0 - a * alpha) / 255 + dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] += np.array( + mask_channels[i] * (a * alpha / 255), dtype=np.uint8) + dst_img = cv2.merge(dst_channels) + # cv2.imwrite(r'd:\1_1.jpg', dst_img) + return dst_img + +import time +# 导入我们将要使用的logo +logo = "logo.png" +img2 = "a.jpg" +time11 = time.time() +a = watermark(img2, logo) +time12 = time.time() +print(time12-time11) +cv2.imshow("Watermarked Image", a) +cv2.imwrite("watermarked.jpg", a) +cv2.waitKey(100000) diff --git a/test/水印/视频添加文字水印.py b/test/水印/视频添加文字水印.py new file mode 100644 index 0000000..3725767 --- /dev/null +++ b/test/水印/视频添加文字水印.py @@ -0,0 +1,18 @@ +import cv2 +import numpy as np +# 中文乱码,不支持中文 +img=cv2.imread("C:\\Users\\chenyukun\\Pictures\\Camera Roll\\a.jpg") # 导入我们需要添加水印的图片 +# RGB_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) +RGB_img = img +blank_img = np.zeros(shape=(RGB_img.shape[0],RGB_img.shape[1],3), dtype=np.uint8) +font = cv2.FONT_HERSHEY_SIMPLEX +# 添加水印的文字内容 +cv2.putText(blank_img,text='Learn Python',org=(40, 90), + fontFace=font,fontScale= 2, + color=(255,0,0),thickness=10,lineType=cv2.LINE_4) +blended = cv2.addWeighted(src1=RGB_img, alpha=0.7, + src2=blank_img, beta=1, gamma = 2) +cv2.imshow("Watermarked Image", blended) +cv2.imwrite("watermarked.jpg", blended) +cv2.waitKey(100000) +cv2.destroyAllWindows() \ No newline at end of file diff --git a/test/水印/视频添加文字水印1.py b/test/水印/视频添加文字水印1.py new file mode 100644 index 0000000..1eac175 --- /dev/null +++ b/test/水印/视频添加文字水印1.py @@ -0,0 +1,35 @@ +import cv2 +import numpy as np +from PIL import Image, ImageDraw, ImageFont +# PIL添加水印 +def cv2AddChineseText(img, text, position, textColor=(0, 255, 0), textSize=30): + if (isinstance(img, np.ndarray)): # 判断是否OpenCV图片类型 + img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) + # 创建一个可以在给定图像上绘图的对象 + draw = ImageDraw.Draw(img) + # 字体的格式 + fontStyle = ImageFont.truetype( + "../font/simsun.ttc", textSize, encoding="utf-8") + # 绘制文本 + draw.text(position, text, textColor, font=fontStyle) + # 转换回OpenCV格式 + return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR) + +img=cv2.imread("C:\\Users\\chenyukun\\Pictures\\Camera Roll\\a.jpg") # 导入我们需要添加水印的图片 +# RGB_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) +# RGB_img = img +# numpy.zeros(shape,dtype=float,order = 'C') +# np.zeros返回给定形状和类型的新数组,用0填充。 +# shape: int 或 int 的元组 +# dtype: 类型 +# uint8是专门用于存储各种图像的(包括RGB,灰度图像等),范围是从0–255 +# blank_img = np.zeros(shape=(RGB_img.shape[0],RGB_img.shape[1],3), dtype=np.uint8) +# font = cv2.FONT_HERSHEY_TRIPLEX +# 添加水印的文字内容 +# fontScale字体大小 +# cv2.putText(图片img,“文本内容”,(左下角坐标),字体,字体大小,(颜色),线条粗细,线条类型) +frame=cv2AddChineseText(img, "拓恒技术", (123, 123),(0, 255, 0), 30) +cv2.imshow("Watermarked Image", frame) +cv2.imwrite("watermarked.jpg", frame) +cv2.waitKey(100000) +cv2.destroyAllWindows() \ No newline at end of file diff --git a/test/水印/视频添加文字水印2.py b/test/水印/视频添加文字水印2.py new file mode 100644 index 0000000..6145f16 --- /dev/null +++ b/test/水印/视频添加文字水印2.py @@ -0,0 +1,3 @@ +from watermarker.marker import add_mark +add_mark(file="test1.jpg", out="add_mark_test1.jpg", + mark="Python", opacity=0.2, angle=30, space=30) \ No newline at end of file diff --git a/test/水印/视频添加文字水印3.py b/test/水印/视频添加文字水印3.py new file mode 100644 index 0000000..a9f5dd1 --- /dev/null +++ b/test/水印/视频添加文字水印3.py @@ -0,0 +1,114 @@ +import cv2 +from PIL import Image, ImageDraw, ImageFont + +################################# +# 给图片加上水印 +################################# + +class Water: + def __init__(self): + # 颜色对应http://www.yuangongju.com/color + self.color_dict = { + 'white':(255,255,255,255), + 'black':(0,0,0,255), + 'gray':(205,201,201,255), + 'red':(255,0,0,255), + 'yellow':(255,215,0,255), + 'blue':(0,0,170,255), + 'purple':(205,105,201,255), + 'green':(0,205,0,255) + } + + self.position_list = [1,2,3,4] + + def one_water(self, image, text, position=1, fontsize=20, fontcolor='black'): + """ + 普通照片水印 + params: + image:图片 + text:水印文字 + position:水印位置 + 1:左上 + 2:右上 + 3:右下 + 4:左下 + fontsize:字体大小 + fontcolor:字体颜色 + [white, black, gray, red, yellow, blue, purple, green] + """ + if position not in self.position_list: + position = 1 + + h, w = image.size[:2] + + keys = self.color_dict.keys() + if fontcolor not in keys: + fontcolor = 'black' + color = self.color_dict[fontcolor] + fnt = ImageFont.truetype('../font/simsun.ttc', fontsize) + + im = image.convert('RGBA') + mask = Image.new('RGBA', im.size, (0,0,0,0)) + + d = ImageDraw.Draw(mask) + + size_h, size_w = d.textsize(text, font=fnt) + + alpha = 5 + if position == 1: + weizhi = (0 + alpha, 0 + alpha) + elif position == 2: + weizhi = (h - size_h - alpha, 0 + alpha) + elif position == 3: + weizhi = (h - size_h - alpha, w - size_w - alpha) + else: + weizhi = (0 + alpha, w - size_w - alpha) + + # position 为左上角位置 + d.text(weizhi, text, font=fnt, fill=color) + out = Image.alpha_composite(im, mask) + return out + + def fill_water(self, image, text, fontsize): + """ + 半透明水印,布满整张图,并且自动旋转45° + params: + image:图片 + text:文字 + fontsize:文字大小 + """ + font = ImageFont.truetype('../font/simsun.ttc', fontsize) + + # 添加背景 + new_img = Image.new('RGBA', (image.size[0] * 3, image.size[1] * 3), (255, 255, 255, 255)) + new_img.paste(image, image.size) + + # 添加水印 + font_len = len(text) + rgba_image = new_img.convert('RGBA') + text_overlay = Image.new('RGBA', rgba_image.size, (0, 0, 0, 0)) + image_draw = ImageDraw.Draw(text_overlay) + + for i in range(0, rgba_image.size[0], font_len*40+100): + for j in range(0, rgba_image.size[1], 200): + # print(f'i:{i}, j:{j}, text:{text}, font:{font}') + image_draw.text((i, j), text, font=font, fill=(0, 0, 0, 50)) + text_overlay = text_overlay.rotate(-45) + image_with_text = Image.alpha_composite(rgba_image, text_overlay) + + image_with_text = image_with_text.crop((image.size[0], image.size[1], image.size[0] * 2, image.size[1] * 2)) + return image_with_text + + +if __name__ == '__main__': + img = Image.open("../a.jpg") + fontcolor = 'yellow' + + water = Water() + text = "hello world" + + fill_img = water.fill_water(img, text, fontsize=36) + # 一定要保存为png格式 + fill_img.save(u'aa.png') + + print('finish') \ No newline at end of file diff --git a/test/游戏/Food.py b/test/游戏/Food.py new file mode 100644 index 0000000..87bd5d9 --- /dev/null +++ b/test/游戏/Food.py @@ -0,0 +1,62 @@ +import pygame + +STEP = 44 + + +class Food(): + def __init__(self, x, y, surface): + self.x = x * STEP + self.y = y * STEP + self.surface = surface + self.image = pygame.image.load("food.png").convert() + + def draw(self): + self.surface.blit(self.image, (self.x, self.y)) + +class Snake(): + def __init__(self, x, y, surface): + self.x = [x*STEP] + self.y = [y*STEP] # 用两个列表来存储贪吃蛇每个节点的位置 + self.length = 1 # 贪吃蛇的长度 + self.direction = 0 # 0表示向右, 1表示向下, 2表示向左, 3表示向上 + self.image = pygame.image.load("snake.png").convert() # 加载蛇 + self.surface = surface + self.step = 44 # 运动步长 + self.updateCount = 0 # 更新次数 + + # 虽然有这么多节点,但是有length来控制界面上画出多少蛇的节点 + for i in range(1, 100): + self.x.append(-100) + self.y.append(-100) + + def draw(self): + for i in range(self.length): + self.surface.blit(self.image, (self.x[i],self.y[i])) + + def moveRight(self): + self.direction = 0 + + def moveLeft(self): + self.direction = 2 + + def moveUp(self): + self.direction = 3 + + def moveDown(self): + self.direction = 1 + + def update(self): + self.updateCount += 1 + if self.updateCount > 2: + for i in range(self.length-1, 0, -1): + self.x[i] = self.x[i-1] + self.y[i] = self.y[i-1] + if self.direction == 0: + self.x[0] = self.x[0] + self.step # 向右 + if self.direction == 1: + self.y[0] = self.y[0] + self.step # 向下 + if self.direction == 2: + self.x[0] = self.x[0] - self.step # 向左 + if self.direction == 3: + self.y[0] = self.y[0] - self.step # 向上 + self.updateCount = 0 diff --git a/test/游戏/SnakeGame.py b/test/游戏/SnakeGame.py new file mode 100644 index 0000000..40cfae8 --- /dev/null +++ b/test/游戏/SnakeGame.py @@ -0,0 +1,93 @@ +import random + +from pygame.locals import * +import pygame +import time + +from test.游戏.Food import Food, Snake, STEP + + +class SnakeGame(): + def __init__(self): + self.width = 800 + self.height = 600 + self._running = False + + + def init(self): + pygame.init() #初始化所有导入的pygame模块 + # 初始化一个准备显示的窗口或屏幕 + self._display_surf = pygame.display.set_mode((self.width,self.height), pygame.HWSURFACE) + self.food = Food(5, 5, self._display_surf) + self.snake = Snake(1, 1, self._display_surf) + self._running = True + + def run(self): + self.init() + while self._running: + pygame.event.pump() # 内部处理pygame事件处理程序 + self.listen_keybord() # 监听键盘上下左右键 + self.loop() + self.render() + time.sleep(0.05) + + def listen_keybord(self): + keys = pygame.key.get_pressed() + + if (keys[K_RIGHT]): + self.snake.moveRight() + + if (keys[K_LEFT]): + self.snake.moveLeft() + + if (keys[K_UP]): + self.snake.moveUp() + + if (keys[K_DOWN]): + self.snake.moveDown() + + if (keys[K_ESCAPE]): + self._running = False + + def render(self): + self._display_surf.fill((0, 0, 0)) # 游戏界面填充为黑色 + self.food.draw() # 画出食物 + self.snake.draw() # 画出蛇 + pygame.display.flip() # 刷新屏幕 + + + def loop(self): + self.snake.update() + self.eat() + self.faild_check() + + def faild_check(self): + # 检查是否吃到了自己 + for i in range(2,self.snake.length): + if self.isCollision(self.snake.x[0], self.snake.y[0], self.snake.x[i], self.snake.y[i],40): + print('吃到自己了') + exit(0) + + if self.snake.x[0] < 0 or self.snake.x[0] > self.width \ + or self.snake.y[0] < 0 or self.snake.y[0] > self.height: + print('出边界了') + exit(0) + + def eat(self): + if self.isCollision(self.food.x, self.food.y, self.snake.x[0], self.snake.y[0], 40): + self.food.x = random.randint(2, 9)*STEP + self.food.y = random.randint(2, 9)*STEP + self.snake.length += 1 # 蛇的长度加1 + + + + @staticmethod + def isCollision(x1, y1, x2, y2, bsize): + if x1 >= x2 and x1 <= x2 + bsize: + if y1 >= y2 and y1 <= y2 + bsize: + return True + return False + +if __name__ == '__main__': + snake = SnakeGame() + snake.run() \ No newline at end of file diff --git a/test/游戏/__init__.py b/test/游戏/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/游戏/__pycache__/Food.cpython-38.pyc b/test/游戏/__pycache__/Food.cpython-38.pyc new file mode 100644 index 0000000..7b7e5bb Binary files /dev/null and b/test/游戏/__pycache__/Food.cpython-38.pyc differ diff --git a/test/游戏/__pycache__/__init__.cpython-38.pyc b/test/游戏/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..4e8a265 Binary files /dev/null and b/test/游戏/__pycache__/__init__.cpython-38.pyc differ diff --git a/test/游戏/food.png b/test/游戏/food.png new file mode 100644 index 0000000..88c7eed Binary files /dev/null and b/test/游戏/food.png differ diff --git a/test/游戏/snake.png b/test/游戏/snake.png new file mode 100644 index 0000000..2f387e0 Binary files /dev/null and b/test/游戏/snake.png differ diff --git a/test/算法/__init__.py b/test/算法/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/算法/冒泡.py b/test/算法/冒泡.py new file mode 100644 index 0000000..3d99c98 --- /dev/null +++ b/test/算法/冒泡.py @@ -0,0 +1,20 @@ + +def pop_sort(lst): + for i in range(len(lst)-1, 0, -1): + move_max(lst, i) + + +def move_max(lst, max_index): + for i in range(max_index): + if lst[i] > lst[i+1]: + lst[i], lst[i+1] = lst[i+1], lst[i] + +if __name__ == '__main__': + lst = [4, 1, 7, 2, 3, 6] + # pop_sort(lst) + # print(lst) + for j in range(len(lst) - 1, 0, -1): + for i in j: + if lst[i] > lst[i+1]: + lst[i], lst[i+1] = lst[i+1], lst[i] + diff --git a/test/算法/插入.py b/test/算法/插入.py new file mode 100644 index 0000000..8b53829 --- /dev/null +++ b/test/算法/插入.py @@ -0,0 +1,21 @@ +def insert(lst, index): + if lst[index-1] < lst[index]: + return + + tmp = lst[index] + tmp_index = index + while tmp_index > 0 and lst[tmp_index-1] > tmp: + lst[tmp_index] = lst[tmp_index-1] + tmp_index -= 1 + lst[tmp_index] = tmp + + +def insert_sort(lst): + for i in range(1, len(lst)): + insert(lst, i) + + +if __name__ == '__main__': + lst = [1, 6, 2, 7, 5] + insert_sort(lst) + print(lst) \ No newline at end of file diff --git a/test/算法/选择.py b/test/算法/选择.py new file mode 100644 index 0000000..35f7aa7 --- /dev/null +++ b/test/算法/选择.py @@ -0,0 +1,21 @@ +""" +假设有一个序列,a[0],a[1],a[2]...a[n]现在,对它进行排序。我们先从0这个位置到n这个位置找出最小值,然后将这个最小值与a[0]交换, +然后呢,a[1]到a[n]就是我们接下来要排序的序列 +我们可以从1这个位置到n这个位置找出最小值,然后将这个最小值与a[1]交换,之后,a[2]到a[n]就是我们接下来要排序的序列 +每一次,我们都从序列中找出一个最小值,然后把它与序列的第一个元素交换位置,这样下去,待排序的元素就会越来越少,直到最后一个 +""" + + +def select_sort(lst): + for i in range(len(lst)): + min = i + for j in range(min, len(lst)): + # 寻找min 到len(lst)-1 这个范围内的最小值 + if lst[min] > lst[j]: + min = j + lst[i], lst[min] = lst[min], lst[i] + + +lst = [2, 6, 1, 8, 2, 4, 9] +select_sort(lst) +print(lst) diff --git a/test/类型标注/__init__.py b/test/类型标注/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/类型标注/test.py b/test/类型标注/test.py new file mode 100644 index 0000000..043c7ac --- /dev/null +++ b/test/类型标注/test.py @@ -0,0 +1,18 @@ + +from typing import Optional, Union, Any, Set + + +a: int = 8 +b: bool = True +c: str = 'ok' +d: Optional[Union[int, float]] = None +e: float = 9.8 +f: bytes = b'32' + +d = 5 +d = 9.8 +d = None + +s: Set[int] = {1, 2, '3'} +for ss in s: + print(ss) \ No newline at end of file diff --git a/test/类型标注/test1.py b/test/类型标注/test1.py new file mode 100644 index 0000000..1e85ec1 --- /dev/null +++ b/test/类型标注/test1.py @@ -0,0 +1,29 @@ +from typing import TypeVar, Generic, List + + +T = TypeVar('T') + + +class Stack(Generic[T]): + def __init__(self): + self.data: List[T] = [] + + def push(self, item: T): + self.data.append(item) + + def pop(self) -> T: + return self.data.pop(-1) + + def top(self) -> T: + return self.data[-1] + + def size(self) -> int: + return len(self.data) + + def is_empty(self) -> bool: + return len(self.data) == 0 + +stack = Stack[int]() +stack.push('3') +stack.push('5') +print(stack.pop()) diff --git a/test/线程/Test.py b/test/线程/Test.py new file mode 100644 index 0000000..e4fce2e --- /dev/null +++ b/test/线程/Test.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +import threading +import time +from concurrent.futures import ThreadPoolExecutor, ALL_COMPLETED, wait + + +class Test(object): + def __init__(self): + # threading.Thread.__init__(self) + self._sName = "machao" + + def process(self): + #args是关键字参数,需要加上名字,写成args=(self,) + th1 = threading.Thread(target=self.buildList, args=()) + th1.start() + th1.join() + + def buildList(self): + while True: + print("start") + print(self._sName) + self._sName = "1111111" + time.sleep(3) +def bb(): + print("!1111111111") + +def aa(aa): + print(aa) + time.sleep(5) + return "1111" + + +# test = Test() +# test.process() +# print(3//2) +# with ThreadPoolExecutor(max_workers=10) as t: +# aa = t.submit(aa, "aaa") +# results = wait([aa], timeout=60, return_when=ALL_COMPLETED) +# completed_futures = results.done +# for f in completed_futures: +# if f.exception(): +# raise f.exception() +# else: +# print(f"Task {f.result()} succeeded") +def test1(message): + while True: + time.sleep(1) + print(message) + +message = {"a": "1", "b": "2", "c": "3"} + +aa = message +print(aa is message) +message = None +print(aa) +print(message) +# with ThreadPoolExecutor(max_workers=10) as t: +# t.submit(test1, message) +# print("1111111111111111111111111111111") +# del message +# print("aaa", message) \ No newline at end of file diff --git a/test/线程/Test1.py b/test/线程/Test1.py new file mode 100644 index 0000000..aed2903 --- /dev/null +++ b/test/线程/Test1.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +import time +from multiprocessing import Queue + +def get_no_block_queue(queue): + try: + return queue.get(block=False) + except Exception: + return None + +def clear_queue(queue, is_close=False): + while True: + if queue.empty() or queue.qsize() == 0: + if is_close: + queue.close() + break + r = get_no_block_queue(queue) + del r + +aa = Queue(10) +aa.put("111") +aa.put("111") +aa.cancel_join_thread() +time.sleep(2) +clear_queue(aa, is_close=True) +clear_queue(aa, is_close=True) +print("111111") \ No newline at end of file diff --git a/test/装饰器/装饰器.py b/test/装饰器/装饰器.py new file mode 100644 index 0000000..9c6a5e0 --- /dev/null +++ b/test/装饰器/装饰器.py @@ -0,0 +1,18 @@ +import functools + + +def log(text): + def decorator(func): + @functools.wraps(func) + def wrapper(*args, **kw): + print('%s %s():' % (text, func.__name__)) + return func(*args, **kw) + return wrapper + return decorator + +@log('execute') +def now(): + print('2015-3-25') + +now = log('execute')(now) +print(now.__name__) \ No newline at end of file diff --git a/test/设计模式/__init__.py b/test/设计模式/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/设计模式/单例/__init__.py b/test/设计模式/单例/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/设计模式/单例/__pycache__/single.cpython-38.pyc b/test/设计模式/单例/__pycache__/single.cpython-38.pyc new file mode 100644 index 0000000..451a7be Binary files /dev/null and b/test/设计模式/单例/__pycache__/single.cpython-38.pyc differ diff --git a/test/设计模式/单例/demo2.py b/test/设计模式/单例/demo2.py new file mode 100644 index 0000000..4457e30 --- /dev/null +++ b/test/设计模式/单例/demo2.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +from threading import RLock + +class SingletonType(type): + single_lock = RLock() + + def __call__(cls, *args, **kwargs): # 创建cls的对象时候调用 + with SingletonType.single_lock: + if not hasattr(cls, "_instance"): + cls._instance = super(SingletonType, cls).__call__(*args, **kwargs) # 创建cls的对象 + + return cls._instance + + +class Singleton(metaclass=SingletonType): + def __init__(self, name): + self.name = name + + +single_1 = Singleton('第1次创建') +single_2 = Singleton('第2次创建') + +print(single_1.name, single_2.name) # 第1次创建 第1次创建 +print(single_1 is single_2) \ No newline at end of file diff --git a/test/设计模式/单例/demo3.py b/test/设计模式/单例/demo3.py new file mode 100644 index 0000000..658575c --- /dev/null +++ b/test/设计模式/单例/demo3.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +from threading import RLock +single_lock = RLock() + +def Singleton(cls): + instance = {} + + def _singleton_wrapper(*args, **kargs): + with single_lock: + if cls not in instance: + instance[cls] = cls(*args, **kargs) + return instance[cls] + + return _singleton_wrapper + + +@Singleton +class SingletonTest(object): + def __init__(self, name): + self.name = name + + +slt_1 = SingletonTest('第1次创建') +print(slt_1.name) +slt_2 = SingletonTest('第2次创建') +print(slt_1.name, slt_2.name) + +print(slt_1 is slt_2) diff --git a/test/设计模式/单例/demo4.py b/test/设计模式/单例/demo4.py new file mode 100644 index 0000000..21f9aaa --- /dev/null +++ b/test/设计模式/单例/demo4.py @@ -0,0 +1,18 @@ +from threading import RLock +class Singleton(object): + single_lock = RLock() + + def __init__(self, name): + self.name = name + + @classmethod + def instance(cls, *args, **kwargs): + with Singleton.single_lock: + if not hasattr(Singleton, "_instance"): + Singleton._instance = Singleton(*args, **kwargs) + return Singleton._instance + +single_1 = Singleton.instance('第1次创建') +single_2 = Singleton.instance('第2次创建') + +print(single_1 is single_2) # True \ No newline at end of file diff --git a/test/设计模式/单例/demo5.py b/test/设计模式/单例/demo5.py new file mode 100644 index 0000000..c1052c7 --- /dev/null +++ b/test/设计模式/单例/demo5.py @@ -0,0 +1,22 @@ +from threading import RLock + +class Singleton(object): + single_lock = RLock() + + def __init__(self, name): + if hasattr(self, 'name'): + return + self.name = name + + def __new__(cls, *args, **kwargs): + with Singleton.single_lock: + if not hasattr(Singleton, "_instance"): + Singleton._instance = object.__new__(cls) + + return Singleton._instance + +single_1 = Singleton('第1次创建') +single_2 = Singleton('第2次创建') + +print(single_1.name, single_2.name) # 第2次创建 第2次创建 +print(single_1 is single_2) # True \ No newline at end of file diff --git a/test/设计模式/单例/single.py b/test/设计模式/单例/single.py new file mode 100644 index 0000000..16aae96 --- /dev/null +++ b/test/设计模式/单例/single.py @@ -0,0 +1,15 @@ + + +class DbSingleton(): + def __init__(self, host, port, username, password): + self.host = host + self.port = port + self.username = username + self.password = password + self.pool = None # 连接池 + + def connect(self): + print("建立连接") + + +db_singleton = DbSingleton('host', 'port', 'username', 'password') \ No newline at end of file diff --git a/test/设计模式/单例/test.py b/test/设计模式/单例/test.py new file mode 100644 index 0000000..89f104f --- /dev/null +++ b/test/设计模式/单例/test.py @@ -0,0 +1,7 @@ + +from single import db_singleton + +if __name__ == '__main__': + print(id(db_singleton)) + print(id(db_singleton)) + print(id(db_singleton)) \ No newline at end of file diff --git a/test/设计模式/简单工厂模式/__init__.py b/test/设计模式/简单工厂模式/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/设计模式/简单工厂模式/demo.py b/test/设计模式/简单工厂模式/demo.py new file mode 100644 index 0000000..db78dc8 --- /dev/null +++ b/test/设计模式/简单工厂模式/demo.py @@ -0,0 +1,36 @@ +from abc import ABC, abstractmethod + + +class Fruit(ABC): + def __init__(self, name): + self.name = name + + @abstractmethod + def make_juice(self): + pass + + +class Apple(Fruit): + def make_juice(self): + print(f"制作{self.name}汁") + + +class Grape(Fruit): + def make_juice(self): + print(f"制作{self.name}酒") + + +class FruitFactory(): + @classmethod + def create_fruit(cls, name): + if name == 'apple': + return Apple('苹果') + elif name == 'grape': + return Grape("葡萄") + + +fruit1 = FruitFactory.create_fruit('apple') +fruit1.make_juice() + +fruit2 = FruitFactory.create_fruit('grape') +fruit2.make_juice() \ No newline at end of file diff --git a/test/设计模式/简单工厂模式/demo1.py b/test/设计模式/简单工厂模式/demo1.py new file mode 100644 index 0000000..4c2ddc2 --- /dev/null +++ b/test/设计模式/简单工厂模式/demo1.py @@ -0,0 +1,44 @@ +from abc import ABC, abstractmethod + + +class Fruit(ABC): + def __init__(self, name): + self.name = name + + @abstractmethod + def make_juice(self): + pass + + +class Apple(Fruit): + def make_juice(self): + print(f"制作{self.name}汁") + + +class Grape(Fruit): + def make_juice(self): + print(f"制作{self.name}酒") + + +class AbcFruitFactory(ABC): + @abstractmethod + def create_fruit(self): + pass + + +class AppleFactory(AbcFruitFactory): + def create_fruit(self): + return Apple('苹果') + + +class OrangeFactory(AbcFruitFactory): + def create_fruit(self): + return Grape('葡萄') + + +fruit1 = AppleFactory().create_fruit() +fruit1.make_juice() # 制作苹果汁 + + +fruit2 = OrangeFactory().create_fruit() +fruit2.make_juice() \ No newline at end of file diff --git a/test/语法/__init__.py b/test/语法/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/语法/datetime/__init__.py b/test/语法/datetime/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/语法/datetime/test.py b/test/语法/datetime/test.py new file mode 100644 index 0000000..9d8b583 --- /dev/null +++ b/test/语法/datetime/test.py @@ -0,0 +1,106 @@ +import datetime +import time + +# # 今天的日期 +# print("今天的日期是:", datetime.date.today()) +# +# print("使用时间戳创建日期", datetime.date.fromtimestamp(1234567896)) +# +# print("使用公历序数创建的日期:", datetime.date.fromordinal(1)) +# +# today = datetime.date(year=2020,month=8,day=31) # 使用参数创建日期 +# +# print('date对象的年份:', today.year) +# +# print('date对象的月份:', today.month) +# +# print('date对象的日:', today.day) +# +# print("date对象的struct_time结构为:",today.timetuple()) +# +# print("返回当前公历日期的序数:",today.toordinal()) # 与fromordinal函数作用相反 +# +# print("当前日期为星期(其中:周一对应0):{}".format(today.weekday())) +# +# print("当前日期为星期(其中:周一对应1):{}".format(today.isoweekday())) +# +# print("当前日期的年份、第几周、周几(其中返回为元组):",today.isocalendar()) +# +# print("以ISO 8601格式‘YYYY-MM-DD’返回date的字符串形式:",today.isoformat()) +# +# print("返回一个表示日期的字符串(其格式如:Mon Aug 31 00:00:00 2020):",today.ctime()) +# +# print("指定格式为:",today.strftime("%Y/%m/%d")) +# +# print("替换后的日期为:",today.replace(2019,9,29)) +# +# create_time = datetime.time(hour=11,minute=18,second=31) # 使用参数创建日期 +# +# print('create_time对象的小时为:', create_time.hour) +# +# print('create_time对象的分钟为:', create_time.minute) +# +# print('create_time对象的秒数为:', create_time.second) +# +# print("返回create_time的字符串形式:",create_time.isoformat()) +# +# print("指定格式为:",create_time.strftime("%H/%M/%S")) +# +# print("替换后的时间为:",create_time.replace(20,9,29)) +# +# print("现在的时间是:",datetime.datetime.today()) +# +# print("返回现在的时间是:",datetime.datetime.now()) +# +# print("当前UTC日期和时间是:",datetime.datetime.utcnow()) +# +# print("对应时间戳的日期和时间是:",datetime.datetime.fromtimestamp(1234567896)) +# +# print("对应UTC时间戳的日期和时间是:",datetime.datetime.utcfromtimestamp(1234567896)) +# +# print("公历序列对应的日期和时间是:",datetime.datetime.fromordinal(1)) +# +# print("日期和时间的合体为:",datetime.datetime.combine(datetime.date(2020, 8, 31), datetime.time(12, 12, 12))) +# +# now = datetime.datetime(2020,8,31,12,10,10) +# +# print("年为:",now.year) +# +# print("月为:",now.month) +# +# print("日为:",now.day) +# +# print("小时为:",now.hour) +# +# print("分钟为:",now.minute) +# +# print("秒数为:",now.second) +# +# print('当前日期为:', now.date() ) +# +# print('当前时间:', now.time() ) +# +# print("返回struct_time为",now.timetuple()) # 和date一样 +# +# print("返回UTC的struct_time为",now.utctimetuple()) +# +# print("返回的公历序列数为:",now.toordinal()) # 和date一样 +# +# print("返回标准日期格式为:",now.isoformat()) # 和date一样 +# +# print("返回的周几(1表示周一):",now.isoweekday()) # 和date一样 +# +# print("返回的周几(0表示周一):",now.weekday()) # 和date一样 +# +# print("now.isocalendar():", now.isocalendar()) # 和date一样 +# +# print("now.ctime():",now.ctime()) # 和date一样 +# +# print("格式化时间为:",now.strftime('%Y/%m/%d %H:%M:%S')) # 把日期按照format指定的格式进行格式化 +# +# print(datetime.datetime.strptime("2020/12/29 8:8:00",'%Y/%m/%d %H:%M:%S')) + +current_time = 1577761708 +date_time = datetime.datetime.fromtimestamp(current_time) +print(date_time) +print(time.localtime()) \ No newline at end of file diff --git a/test/语法/for/__init__.py b/test/语法/for/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/语法/for/demo.py b/test/语法/for/demo.py new file mode 100644 index 0000000..15d6bf0 --- /dev/null +++ b/test/语法/for/demo.py @@ -0,0 +1,43 @@ + +magicians = ['alice', 'david', 'carolina'] +for magician in magicians: + print(magician) + +print(0b1101010) + +value = int('1101010', 2) +print(value) # 106 + +value = int('125', 8) +print(value) # 85 + +value = int('3f2a1', 16) +print(value) # 258721 + +print(bin(106)) # 0b1101010 十进制转二进制 +print(oct(85)) # 0o125 十进制转八进制 +print(hex(258721)) # 0x3f2a1 十进制转十六进制 + +text = '1aa2' +print(text.split('a')) + +# 1. 将字符串 "abcd" 转成大写 +print("abcd".upper()) +# 2. 计算字符串 "cd" 在 字符串 "abcd"中出现的位置 +print("abcd".index('cd')) +print("abcd".find('cd')) +# 3. 字符串 "a,b,c,d" ,请用逗号分割字符串,分割后的结果是什么类型的? +print("a,b,c,d".split(',')) +# 4. "{name}喜欢{fruit}".format(name="李雷") 执行会出错,请修改代码让其正确执行 +print("{name}喜欢{fruit}".format(name="李雷", fruit='水果')) +# 5. string = "Python is good", 请将字符串里的Python替换成 python,并输出替换后的结果 +print("Python is good".replace("Python", "python")) +# 6. 有一个字符串 string = "python修炼第一期.html",请写程序从这个字符串里获得.html前面的部分,要用尽可能多的方式来做这个事情 +print("python修炼第一期.html".split('.')[0]) +# 7. 如何获取字符串的长度? +# 8. "this is a book",请将字符串里的book替换成apple +# 9. "this is a book", 请用程序判断该字符串是否以this开头 +# 10. "this is a book", 请用程序判断该字符串是否以apple结尾 +# 11. "This IS a book", 请将字符串里的大写字符转成小写字符 +# 12. "This IS a book", 请将字符串里的小写字符,转成大写字符 +# 13. "this is a book\n", 字符串的末尾有一个回车符,请将其删除 \ No newline at end of file diff --git a/test/语法/list/__init__.py b/test/语法/list/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/语法/list/demo.py b/test/语法/list/demo.py new file mode 100644 index 0000000..c263a8f --- /dev/null +++ b/test/语法/list/demo.py @@ -0,0 +1,34 @@ +bicycles = ['trek', 'cannondale', 'redline', 'specialized'] +print(bicycles) +print(bicycles[0]) +print(bicycles[0].title()) +print(bicycles[-1]) + +motorcycles = ['honda', 'yamaha', 'suzuki'] +print(motorcycles) +motorcycles[0] = 'ducati' +print(motorcycles) +motorcycles.append('ducati') +print(motorcycles) +motorcycles.insert(0, 'ducati') +print(motorcycles) +del motorcycles[0] +print(motorcycles) +popped_motorcycle = motorcycles.pop() +print(motorcycles) +print(popped_motorcycle) + +# 使用方法 sort()对列表进行永久性排序 +cars = ['bmw', 'audi', 'toyota', 'subaru'] +cars.sort() +print(cars) +cars.sort(reverse=True) +print(cars) + +# 使用函数 sorted()对列表进行临时排序 +cars = ['bmw', 'audi', 'toyota', 'subaru'] +print(cars) +print(sorted(cars)) +print(sorted(cars, reverse=True)) +print(cars.reverse()) +print(len(cars)) \ No newline at end of file diff --git a/test/语法/statistics_test/__init__.py b/test/语法/statistics_test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/语法/statistics_test/test.py b/test/语法/statistics_test/test.py new file mode 100644 index 0000000..8d06314 --- /dev/null +++ b/test/语法/statistics_test/test.py @@ -0,0 +1,16 @@ +import statistics + +lst = [1, 4, 5, 7, 1, 3, 6, 9, 19] + +print(statistics.mean(lst)) # 算数平均值 +print(statistics.harmonic_mean(lst)) # 调和平均值 +print(statistics.median(lst)) # 中位数 +print(statistics.median_low(lst)) # 数据的第一个中位数(总数为偶数时有两个中位数) +print(statistics.median_high(lst)) # 数据的第二个中位数 +print(statistics.median_grouped(lst)) # 分组数据的中位数的均值 +print(statistics.mode(lst)) # 离散数据的模式, 数据中最常见的值 + +print(statistics.pstdev(lst)) # 数据总体的标准差 +print(statistics.pvariance(lst)) # 数据总体的方差 +print(statistics.stdev(lst)) # 数据样本的标准差 +print(statistics.variance(lst)) # 数据样本的方差 \ No newline at end of file diff --git a/test/语法/time/__init__.py b/test/语法/time/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/语法/time/test.py b/test/语法/time/test.py new file mode 100644 index 0000000..6679d15 --- /dev/null +++ b/test/语法/time/test.py @@ -0,0 +1,42 @@ +import time + +# 获取当前时间戳 1685344329.938672 +print(time.time()) + +# 获取当前时间,表示为计算机可处理的时间格式 +print(time.gmtime()) + +# 时间格式化:将时间以合理的方式展示出来 +print(time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())) +print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))) +print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) +# +print(time.strptime("2023-05-29 07:21:07", "%Y-%m-%d %H:%M:%S")) + +# 返回一个CPU级别的精确时间计数值, 单位为秒, 由于这个计算值七点不确定,连续调用差值才有意义 +print(time.perf_counter()) + +# 获取当前时间 +print(time.localtime(time.time())) +print(time.localtime()) + +# 接受时间元组并返回一个可读的形式为"Tue Dec 11 18:07:14 2008"(2008年12月11日 周二18时07分14秒)的24个字符的字符串。 +print(time.asctime(time.localtime(time.time()))) +print(time.asctime(time.localtime())) +# 获取当前时间并以易读方式表示,返回字符串 +print(time.ctime()) # Mon May 29 15:16:00 2023 + +# 返回格林威治西部的夏令时地区的偏移秒数。如果该地区在格林威治东部会返回负值(如西欧,包括英国)。对夏令时启用地区才能使用。 +print(time.altzone) + +# +start = time.perf_counter() +start1 = time.process_time() +time.sleep(1) +end = time.perf_counter() +end1 = time.process_time() +print(end - start) +print(end1 - start1) + +# 接受时间对象并返回时间戳(1970纪元后经过的浮点秒数) +print(time.mktime(time.localtime())) diff --git a/test/语法/全局变量.py b/test/语法/全局变量.py new file mode 100644 index 0000000..e51a94a --- /dev/null +++ b/test/语法/全局变量.py @@ -0,0 +1,27 @@ + +def get_mathematical_score(): + return 90 + + +def get_english_score(): + return 95 + + +def get_history_score(): + return 98 + + +def get_score_by_course(course): + """ + 根据课程获取考试分数 + :param course: + :return: + """ + global_dict = globals() + print(global_dict) + func_name = 'get_{course}_score'.format(course=course) + func = global_dict.get(func_name) + return func() + + +print(get_score_by_course('history')) \ No newline at end of file diff --git a/test/语法/全局变量1.py b/test/语法/全局变量1.py new file mode 100644 index 0000000..4cd9eb7 --- /dev/null +++ b/test/语法/全局变量1.py @@ -0,0 +1,51 @@ +def func_dispatch(func): + registry = {} + + def dispatch(key_word): + return registry.get(key_word, registry[object]) + + def register(key_word, func=None): + if func is None: + return lambda f: register(key_word, f) + + registry[key_word] = func + return func + + def wrapper(*args, **kw): + return dispatch(args[0])(*args, **kw) + + registry[object] = func + wrapper.register = register + return wrapper + + +@func_dispatch +def score_dispath(course): + return 0 + + +@score_dispath.register('mathematical') +def get_mathematical_score(course): + return 90 + + +@score_dispath.register('english') +def get_english_score(course): + return 95 + + +@score_dispath.register('history') +def get_history_score(course): + return 98 + + +def get_score_by_course(course): + """ + 根据课程获取考试分数 + :param course: + :return: + """ + return score_dispath(course) + + +print(get_score_by_course('mathematical')) \ No newline at end of file diff --git a/test/语法/回调.py b/test/语法/回调.py new file mode 100644 index 0000000..e7ca18b --- /dev/null +++ b/test/语法/回调.py @@ -0,0 +1,39 @@ +class TestClass(object): + def __init__(self): + self.fun = 0 + + def decorator(self, fun): + #通过fun变量实现对传入函数的回调 + self.fun = fun + #仅注册回调函数,将原函数返回,不执行原函数工鞥呢,不改变原函数功能 + return fun + + def decorator1(self, type): + def wrapper(func): + if type == 'A': + self.fun_A = func + if type == 'B': + self.fun_B = func + return func + return wrapper + +test = TestClass() + +#将decorator_test函数传入test的decorator函数,并执行decorator函数 +@test.decorator +def decorator_test(): + print('this is decorator_test') + +@test.decorator1('A') +def decorator_test(): + print('this is decorator_test A') + +@test.decorator1('B') +def decorator_test(): + print('this is decorator_test B') + +#通过test的fun变量回调decorator_test函数 +test.fun(); + +test.fun_A (); +test.fun_B (); diff --git a/test/语法/装饰器/__init__.py b/test/语法/装饰器/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/读写/__init__.py b/test/读写/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/读写/csv_test.py b/test/读写/csv_test.py new file mode 100644 index 0000000..ef46e6a --- /dev/null +++ b/test/读写/csv_test.py @@ -0,0 +1,29 @@ + +import csv + +import numpy as np + +# with open("data.csv") as f: +# csv_reader = csv.reader(f) +# for row in csv_reader: +# print(row) +# +# import pandas as pd +# df = pd.read_csv("data.csv", encoding="utf-8") +# print(df) +# df_array = np.array(df) # 将pandas读取的数据转化为array +# df_list = df_array.tolist() # 将数组转化为list +# print(df_list) +# x = df[['name', 'age']] +# print(x) +# y = df[['name']] +# print(y) +# def aa(): +# num=3 +# while True: +# if num==3: +# return +# print("aaaaaaaaaa") +# +# aa() +# print("11111111") diff --git a/test/读写/data.csv b/test/读写/data.csv new file mode 100644 index 0000000..0fa4903 --- /dev/null +++ b/test/读写/data.csv @@ -0,0 +1,4 @@ +name,age +1,1 +2,2 +3,3 diff --git a/test/读写/demo.py b/test/读写/demo.py new file mode 100644 index 0000000..8d59536 --- /dev/null +++ b/test/读写/demo.py @@ -0,0 +1,71 @@ +# """ +# 模式 描述 +# r 以只读的形式打开文件,文件的指针在开头 +# r+ 读写,文件指针在开头 +# rb 以二进制的形式,只读文件指针在开头 +# w 只写,文件不存在,则创建新的,存在则覆盖,指针在开头 +# w+ 读写,文件不存在,则创建新的,存在则覆盖,指针在开头 +# wb 只写,以二进制的形式 +# a 追加模式,文件指针在结尾 +# a+ 读写,不存在则创建,存在直接追加 +# ab 以二进制形式追加 +# +# 1. close(): 关闭文件---非常重要 +# 2. read([count]): 读取文件中的内容 count:字节数量 +# 3. readlines(): 读取所有内容,打包成列表 +# 4. readline(): 读取一行数据,追加读取,读取过的不能再次读取 +# 5. seek(offset,[from]): 修改指针的位置:从from位置移动了offset个字节, +# from:0则表示从起始位置,1则表示从当前位置开始,2则表示从末尾开始 +# offset:要移动的字节数 +# 6. write(): 向文件中写入内容 +# """ +import json +import sys +import time +import traceback +from collections import namedtuple +from queue import Queue + +import yaml + +# +# import yaml +# +# +# # 写文件 +# # with open("hello.txt", 'w') as f: +# # f.write("hello world") +# import pandas as pd +# # 读文件 +ss = time.time() +# with open(r"D:\tuoheng\codenew\tuoheng_alg\config\dsp_dev_service.yml",'r', encoding='utf-8') as f: +# data = yaml.safe_load(f) +with open(r"D:\tuoheng\codenew\tuoheng_alg\test\读写\dsp_application.json", 'r', encoding='utf-8') as f: + a = json.loads(f.read()) + print(a) +print(time.time()-ss) +# # try: +# # aa = Queue(1) +# # aa.put(1, timeout=2) +# # aa.put(2, block=True, timeout=5) +# # except Exception as e: +# # traceback_str = traceback.format_exc() +# # print("aaaaaaaaaaaaaa", traceback_str) +# import time +# class a(): +# def __init__(self, value): +# self.value = value +# +# def test(self): +# num = 0 +# aa = self.value +# while True: +# num += 1 +# bb = aa +# if num > 10000000: +# break +# ss = time.time() +# a("1111").test() +# print(time.time()-ss) +envs = ('dev', 'test', 'prod') +print('dev1' in envs) \ No newline at end of file diff --git a/test/读写/dsp_application.json b/test/读写/dsp_application.json new file mode 100644 index 0000000..a47b21d --- /dev/null +++ b/test/读写/dsp_application.json @@ -0,0 +1,234 @@ +{ + "dsp": {"active": "dev"}, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + } +, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + } +} diff --git a/test/读写/hello.txt b/test/读写/hello.txt new file mode 100644 index 0000000..95d09f2 --- /dev/null +++ b/test/读写/hello.txt @@ -0,0 +1 @@ +hello world \ No newline at end of file diff --git a/test/路径/Test.py b/test/路径/Test.py new file mode 100644 index 0000000..8236e69 --- /dev/null +++ b/test/路径/Test.py @@ -0,0 +1,16 @@ +# import os +# import sys +# +# from util import RWUtils, LogUtils +# from loguru import logger +# print(os.getcwd()) +# +# print(os.path.relpath(__file__)) +# base_dir = os.path.dirname(os.path.realpath(sys.argv[0])) +# content = YmlUtils.getConfigs(base_dir + "/../../") +# LogUtils.init_log(content) +# +# try: +# 2/0 +# except Exception as e: +# logger.exception("异常信息:{}", e) diff --git a/test/路径/__init__.py b/test/路径/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/进程/__init__.py b/test/进程/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/test/进程/test.py b/test/进程/test.py new file mode 100644 index 0000000..cdad406 --- /dev/null +++ b/test/进程/test.py @@ -0,0 +1,34 @@ +import time +from concurrent.futures import ProcessPoolExecutor + +a = 0 + + +def aa(): + global a + # print("aaaaaaaa", a) + time.sleep(3) + a += 1 + +def bb(): + global a + print(a) + +if __name__ == "__main__": + with ProcessPoolExecutor(max_workers=3) as t: + t.submit(aa) + t.submit(bb) + t.submit(aa) + t.submit(bb) + t.submit(aa) + t.submit(bb) + t.submit(aa) + t.submit(bb) + t.submit(aa) + t.submit(bb) + t.submit(aa) + t.submit(bb) + t.submit(aa) + t.submit(bb) + t.submit(aa) + diff --git a/test/进程/test1.py b/test/进程/test1.py new file mode 100644 index 0000000..f151cc9 --- /dev/null +++ b/test/进程/test1.py @@ -0,0 +1,89 @@ +import time +from multiprocessing import Process, Queue + + +def get_no_block_queue(queue): + try: + return queue.get(block=False) + except Exception: + return None + + +class B(Process): + def __init__(self, a, b, c, d): + super().__init__() + self.a = a + self.b = b + self.c = c + self.d = d + + def run(self): + self.a.put("11111111111") + self.b.put("11111111111") + self.c.put("11111111111") + self.d.put("11111111111") + time.sleep(3) + +class D(Process): + def __init__(self, a, b, c, d): + super().__init__() + self.a = a + self.b = b + self.c = c + self.d = d + + def run(self): + self.a.put("11111111111") + self.b.put("11111111111") + self.c.put("11111111111") + self.d.put("11111111111") + time.sleep(3) + + +class C(Process): + def __init__(self, a, b, c, d): + super().__init__() + self.a = a + self.b = b + self.c = c + self.d = d + + def run(self): + self.a.put("1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111") + self.b.put("1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111") + self.c.put("1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111") + self.d.put("1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111") + self.d.cancel_join_thread() + time.sleep(3) + + +class A(Process): + def __init__(self): + super().__init__() + self.a = Queue() + self.b = Queue() + self.c = Queue() + self.d = Queue() + + def run(self): + b = B(self.a, self.b, self.c, self.d) + b.daemon = True + b.start() + c = C(self.a, self.b, self.c, self.d) + c.daemon = True + c.start() + d = D(self.a, self.b, self.c, self.d) + d.daemon = True + d.start() + while True: + time.sleep(1) + print("11111111111111") + #b.join() + print("222222222222222222") + #c.join() + print("333333333333333333") + + +if __name__ == "__main__": + aa = A() + aa.start() diff --git a/test/集合/test.py b/test/集合/test.py new file mode 100644 index 0000000..0b54dd5 --- /dev/null +++ b/test/集合/test.py @@ -0,0 +1,26 @@ +list1 = [1, 2, 3, 4] +list2 = [1,2,4] +if set(list2) == set(list1): + print("1111111") +else: + print("222222") + +import numpy as np + +# list1 = [1, 2, 3, 4] +# tl = np.asarray([1, 2], np.float32) +# box = np.asarray([tl], np.int32) +# print(tl)c +# print(box[0][1]) +import cv2 +# ai_video_file = cv2.VideoWriter(r"C:\Users\chenyukun\Desktop\fsdownload\aa.mp4", cv2.VideoWriter_fourcc(*'mp4v'), 25, +# (1920,1080)) +# # ai_video_file.set(cv2.VIDEOWRITER_PROP_BITRATE, 4000) +# ai_video_file.set(cv2.CAP_PROP_BITRATE, 4000) +# ai_video_file.set(cv2.VIDEOWRITER_PROP_QUALITY, 80) +# print(help(cv2.VideoWriter.set)) +# print(dir(cv2)) +# print(help(cv2)) + +print(bool(0)) +print(False) \ No newline at end of file diff --git a/util/AliyunSdk.py b/util/AliyunSdk.py new file mode 100644 index 0000000..3671b4e --- /dev/null +++ b/util/AliyunSdk.py @@ -0,0 +1,150 @@ +# -*- coding: utf-8 -*- +from json import loads +from os.path import join +from traceback import format_exc + +import oss2 +import time + +from aliyunsdkvod.request.v20170321.GetPlayInfoRequest import GetPlayInfoRequest +from loguru import logger + +from common.YmlConstant import aliyun_yml_path +from exception.CustomerException import ServiceException +from enums.ExceptionEnum import ExceptionType +from aliyunsdkcore.client import AcsClient +from aliyunsdkvod.request.v20170321 import GetPlayInfoRequest + +from util.RWUtils import getConfigs +from vodsdk.AliyunVodUploader import AliyunVodUploader +from vodsdk.UploadVideoRequest import UploadVideoRequest + + +class AliyunOssSdk: + + __slots__ = ('bucket', '__request_id', '__config') + + def __init__(self, *args): + base_dir, env, self.__request_id = args + self.bucket = None + self.__config = getConfigs(join(base_dir, aliyun_yml_path % env)) + self.get_oss_bucket() + + def get_oss_bucket(self): + if self.bucket is None: + auth = oss2.Auth(self.__config["access_key"], self.__config["access_secret"]) + self.bucket = oss2.Bucket(auth, self.__config["oss"]["endpoint"], + self.__config["oss"]["bucket"], + connect_timeout=self.__config["oss"]["connect_timeout"]) + + def put_object(self, updatePath, fileByte): + request_id = self.__request_id + logger.info("开始上传文件到oss, requestId:{}", request_id) + max_retries = 3 + retry_count = 0 + while True: + try: + self.get_oss_bucket() + self.bucket.put_object(updatePath, fileByte) + logger.info("上传文件到oss成功! requestId:{},{}".format( request_id, updatePath)) + return updatePath + break + except Exception as e: + retry_count += 1 + time.sleep(1) + self.bucket = None + logger.info("上传文件到oss失败, 重试次数:{}, requestId:{}", retry_count, request_id) + if retry_count > max_retries: + logger.error("上传文件到oss重试失败:{}, requestId:{}", format_exc(), request_id) + raise e + + +class ThAliyunVodSdk: + + __slots__ = ('__config', '__request_id') + + def __init__(self, base_dir, env, request_id): + self.__request_id = request_id + self.__config = getConfigs(join(base_dir, aliyun_yml_path % env)) + + def init_vod_client(self, accessKeyId, accessKeySecret): + regionId = self.__config["vod"]["ecsRegionId"] + return AcsClient(accessKeyId, accessKeySecret, regionId, auto_retry=True, max_retry_time=3, timeout=30) + + def get_play_info(self, videoId): + logger.info("开始获取视频地址,videoId:{}, requestId:{}", videoId, self.__request_id) + clt = self.init_vod_client(self.__config["access_key"], self.__config["access_secret"]) + start = time.time() + retry_num = 0 + while True: + try: + request: GetPlayInfoRequest = GetPlayInfoRequest.GetPlayInfoRequest() + request.set_accept_format('JSON') + request.set_VideoId(videoId) + request.set_AuthTimeout(3600 * 5) + response = loads(clt.do_action_with_exception(request)) + play_url = response["PlayInfoList"]["PlayInfo"][0]["PlayURL"] + logger.info("获取视频地址成功,视频地址: {}, requestId: {}", play_url, self.__request_id) + return play_url + except Exception as e: + logger.info("获取视频地址失败,5秒后重试, requestId: {}", self.__request_id) + retry_num += 1 + time.sleep(5) + current_time = time.time() + if "HTTP Status: 403" not in str(e) and retry_num > 12: + logger.error("获取视频地址失败: {}, requestId: {}", format_exc(), self.__request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + if "HTTP Status: 403" in str(e) and ("UploadFail" in str(e) or "TranscodeFail" in str(e) or + "ProduceFail" in str(e)): + logger.error("获取视频地址失败: {}, requestId: {}", format_exc(), self.__request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + diff_time = current_time - start + if diff_time > 60 * 60 * 5: + logger.error("获取视频地址失败超时异常: {},超时时间:{}, requestId: {}", format_exc(), + diff_time, self.__request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_TIMEOUT_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_TIMEOUT_EXCEPTION.value[1]) + + def upload_local_video(self, filePath, file_title): + logger.info("开始执行vod视频上传, filePath: {}, requestId: {}", filePath, self.__request_id) + uploader = AliyunVodUploader(self.__config["access_key"], self.__config["access_secret"], self.__request_id) + uploadVideoRequest: UploadVideoRequest = UploadVideoRequest(filePath, file_title) + logger.info("视频分类:{}, requestId:{}", self.__config["vod"]["cateId"], self.__request_id) + uploadVideoRequest.setCateId(self.__config["vod"]["cateId"]) + # 可以设置视频封面,如果是本地或网络图片可使用UploadImageRequest上传图片到视频点播,获取到ImageURL + # ImageURL示例:https://example.com/sample-****.jpg + # uploadVideoRequest.setCoverURL('') + # 标签 + # uploadVideoRequest.setTags('tag1,tag2') + MAX_RETRIES = 3 + retry_count = 0 + while True: + try: + result = uploader.uploadLocalVideo(uploadVideoRequest) + logger.info("vod视频上传成功, videoId:{}, requestId:{}", result.get("VideoId"), self.__request_id) + return result.get("VideoId") + except Exception: + retry_count += 1 + time.sleep(1) + uploader = AliyunVodUploader(self.__config["access_key"], self.__config["access_secret"], + self.__request_id) + uploadVideoRequest: UploadVideoRequest = UploadVideoRequest(filePath, file_title) + uploadVideoRequest.setCateId(self.__config["vod"]["cateId"]) + logger.error("vod视频上传失败:{},重试次数:{}, requestId:{}", format_exc(), retry_count, + self.__request_id) + if retry_count >= MAX_RETRIES: + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + + def get_play_url(self, filePath, file_title): + videoId = self.upload_local_video(filePath, file_title) + if videoId is None or len(videoId) == 0: + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + return self.get_play_info(videoId) + +# if __name__ == "__main__": +# aa = ThAliyunVodSdk('/home/th/tuo_heng/dev/tuoheng_alg', 'dev', "1") +# print(aa.get_play_info('6928821035b171ee9f3b6632b68f0102')) diff --git a/util/CpuUtils.py b/util/CpuUtils.py new file mode 100644 index 0000000..eee06c4 --- /dev/null +++ b/util/CpuUtils.py @@ -0,0 +1,78 @@ +from os.path import dirname +from traceback import format_exc + +import psutil +from loguru import logger + +from enums.ExceptionEnum import ExceptionType +from exception.CustomerException import ServiceException + + +def check_cpu(base_dir, requestId=None): + path = dirname(base_dir) + cpu_use = psutil.cpu_percent() + cpu_mem = psutil.virtual_memory().percent + cpu_swap = psutil.swap_memory().percent + cpu_disk = psutil.disk_usage(path).percent + if float(cpu_use) > 70 or float(cpu_mem) > 70 or cpu_swap > 85 or cpu_disk > 90: + if requestId: + logger.info("""############################################################################################### + CPU 使用率:{}, 内存使用:{}, SWAP内存使用率:{}, 服务磁盘使用率:{}, requestId:{} + ###############################################################################################""", + cpu_use, cpu_mem, cpu_swap, cpu_disk, requestId) + else: + logger.info("""############################################################################################### + CPU 使用率:{}, 内存使用:{}, SWAP内存使用率:{}, 服务磁盘使用率:{} + ###############################################################################################""", + cpu_use, cpu_mem, cpu_swap, cpu_disk) + raise ServiceException(ExceptionType.NO_RESOURCES.value[0], + ExceptionType.NO_RESOURCES.value[1]) + + +def print_cpu_ex_status(base_dir, requestId=None): + result = False + try: + path = dirname(base_dir) + cpu_use = psutil.cpu_percent() + cpu_mem = psutil.virtual_memory().percent + cpu_swap = psutil.swap_memory().percent + cpu_disk = psutil.disk_usage(path).percent + if float(cpu_use) > 70 or float(cpu_mem) > 70 or cpu_swap > 85 or cpu_disk > 90: + result = True + if requestId: + logger.info("""############################################################################################### + CPU 使用率:{}, 内存使用:{}, SWAP内存使用率:{}, 服务磁盘使用率:{}, requestId:{} + ###############################################################################################""", + cpu_use, cpu_mem, cpu_swap, cpu_disk, requestId) + else: + logger.info("""############################################################################################### + CPU 使用率:{}, 内存使用:{}, SWAP内存使用率:{}, 服务磁盘使用率:{} + ###############################################################################################""", + cpu_use, cpu_mem, cpu_swap, cpu_disk) + except Exception: + logger.error("打印cpu状态异常: {}", format_exc()) + return result + + +def print_cpu_status(base_dir=None, requestId=None,lineNum=None): + if base_dir: + path = dirname(base_dir) + if not lineNum: lineNum='未定义' + cpu_use = psutil.cpu_percent() + cpu_mem = psutil.virtual_memory().percent + cpu_swap = psutil.swap_memory().percent + cpu_lj = psutil.cpu_count() # 逻辑cpu个数 + cpu_wl = psutil.cpu_count(logical=False) # 物理cpu个数 + if base_dir: + cpu_disk = psutil.disk_usage(path).percent + else: cpu_disk="未统计" + if requestId: + logger.info("""############################################################################################ + 行号:{} CPU 使用率:{}, 内存使用:{}, SWAP内存使用率:{}, 逻辑个数:{}, 物理个数:{}, 服务磁盘使用率:{}, requestId:{} + ###############################################################################################""", lineNum,cpu_use, + cpu_mem, cpu_swap, cpu_lj, cpu_wl, cpu_disk, requestId) + else: + logger.info("""############################################################################################### + 行号:{} CPU 使用率:{}, 内存使用:{}, SWAP内存使用率:{}, 逻辑个数:{}, 物理个数:{}, 服务磁盘使用率:{} + ###############################################################################################""",lineNum ,cpu_use, + cpu_mem, cpu_swap, cpu_lj, cpu_wl, cpu_disk) \ No newline at end of file diff --git a/util/Cv2Utils.py b/util/Cv2Utils.py new file mode 100644 index 0000000..af2800c --- /dev/null +++ b/util/Cv2Utils.py @@ -0,0 +1,1095 @@ +# -*- coding: utf-8 -*- +from json import loads +from time import time +from traceback import format_exc + +import cv2 +import subprocess as sp + +import numpy as np +from loguru import logger +from common import Constant +from exception.CustomerException import ServiceException +from enums.ExceptionEnum import ExceptionType + + +class Cv2Util: + __slots__ = [ + 'pullUrl', + 'pushUrl', + 'orFilePath', + 'aiFilePath', + 'p', + 'or_video_file', + 'ai_video_file', + 'fps', + 'width', + 'height', + 'wh', + 'h', + 'w', + 'all_frames', + 'bit_rate', + 'pull_p', + 'requestId', + 'p_push_retry_num', + 'isGpu', + 'read_w_h', + 'context', + 'p_push_time' + ] + + def __init__(self, pullUrl=None, pushUrl=None, orFilePath=None, aiFilePath=None, requestId=None, context=None, + gpu_ids=None): + self.pullUrl = pullUrl + self.pushUrl = pushUrl + self.orFilePath = orFilePath + self.aiFilePath = aiFilePath + self.p = None + self.or_video_file = None + self.ai_video_file = None + self.fps = None + self.width = None + self.height = None + self.wh = None + self.h = None + self.w = None + self.all_frames = None + self.bit_rate = None + self.pull_p = None + self.requestId = requestId + self.p_push_time = 0 + self.p_push_retry_num = 0 + self.isGpu = False + self.read_w_h = None + self.context = context + if gpu_ids is not None and len(gpu_ids) > 0: + self.isGpu = True + + def getFrameConfig(self, fps, width, height): + if self.fps is None or self.width != width or self.height != height: + self.fps = fps + self.width = width + self.height = height + if width > Constant.width: + self.h = int(self.height // 2) + self.w = int(self.width // 2) + else: + self.h = int(self.height) + self.w = int(self.width) + + def clear_video_info(self): + self.fps = None + self.width = None + self.height = None + + ''' + 获取视频信息 + ''' + + def get_video_info(self): + try: + if self.pullUrl is None or len(self.pullUrl) == 0: + logger.error("拉流地址不能为空, requestId:{}", self.requestId) + raise ServiceException(ExceptionType.PULL_STREAM_URL_EXCEPTION.value[0], + ExceptionType.PULL_STREAM_URL_EXCEPTION.value[1]) + args = ['ffprobe', '-show_format', '-show_streams', '-of', 'json', self.pullUrl] + p = sp.Popen(args, stdout=sp.PIPE, stderr=sp.PIPE) + out, err = p.communicate(timeout=20) + if p.returncode != 0: + raise Exception("未获取视频信息!!!!!requestId:" + self.requestId) + probe = loads(out.decode('utf-8')) + if probe is None or probe.get("streams") is None: + raise Exception("未获取视频信息!!!!!requestId:" + self.requestId) + # 视频大小 + # format = probe['format'] + # size = int(format['size'])/1024/1024 + video_stream = next((stream for stream in probe['streams'] if stream.get('codec_type') == 'video'), None) + if video_stream is None: + raise Exception("未获取视频信息!!!!!requestId:" + self.requestId) + width = video_stream.get('width') + height = video_stream.get('height') + nb_frames = video_stream.get('nb_frames') + fps = video_stream.get('r_frame_rate') + # duration = video_stream.get('duration') + # bit_rate = video_stream.get('bit_rate') + if width is not None and int(width) != 0 and height is not None and int(height) != 0: + self.width = int(width) + self.height = int(height) + self.wh = self.width * self.height * 3 + if width > Constant.width: + self.h = int(self.height // 2) + self.w = int(self.width // 2) + else: + self.h = int(self.height) + self.w = int(self.width) + if nb_frames: + self.all_frames = int(nb_frames) + up, down = str(fps).split('/') + self.fps = int(eval(up) / eval(down)) + if self.fps > 30: + logger.info("获取视频FPS大于30帧, FPS:{}, requestId:{}", self.fps, self.requestId) + self.fps = 30 + if self.fps < 25: + logger.info("获取视频FPS小于25帧, FPS:{}, requestId:{}", self.fps, self.requestId) + self.fps = 25 + # if duration: + # self.duration = float(video_stream['duration']) + # self.bit_rate = int(bit_rate) / 1000 + logger.info("视频信息, width:{}|height:{}|fps:{}|all_frames:{}, requestId:{}", + self.width, self.height, self.fps, self.all_frames, self.requestId) + except ServiceException as s: + logger.error("获取视频信息异常: {}, requestId:{}", s.msg, self.requestId) + self.clear_video_info() + raise s + except Exception: + logger.error("获取视频信息异常:{}, requestId:{}", format_exc(), self.requestId) + self.clear_video_info() + + ''' + 录屏任务获取视频信息 + ''' + + def get_recording_video_info(self): + try: + video_info = 'ffprobe -show_format -show_streams -of json %s' % self.pullUrl + 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("未获取视频信息!!!!!requestId:" + self.requestId) + probe = loads(out.decode('utf-8')) + if probe is None or probe.get("streams") is None: + raise Exception("未获取视频信息!!!!!requestId:" + self.requestId) + video_stream = next((stream for stream in probe['streams'] if stream.get('codec_type') == 'video'), None) + if video_stream is None: + raise Exception("未获取视频信息!!!!!requestId:" + self.requestId) + width = video_stream.get('width') + height = video_stream.get('height') + nb_frames = video_stream.get('nb_frames') + fps = video_stream.get('r_frame_rate') + if width and int(width) > 0: + self.width = int(width) + if height and int(height) > 0: + self.height = int(height) + if self.width and self.height: + self.wh = int(width * height * 3) + self.read_w_h = ([self.height, self.width, 3]) + if nb_frames and int(nb_frames) > 0: + self.all_frames = int(nb_frames) + if fps: + up, down = str(fps).split('/') + self.fps = int(eval(up) / eval(down)) + logger.info("视频信息, width:{}|height:{}|fps:{}|all_frames:{}, requestId:{}", self.width, + self.height, self.fps, self.all_frames, self.requestId) + except ServiceException as s: + logger.error("获取视频信息异常: {}, requestId:{}", s.msg, self.requestId) + self.clear_video_info() + raise s + except Exception: + logger.error("获取视频信息异常:{}, requestId:{}", format_exc(), self.requestId) + self.clear_video_info() + + def getRecordingFrameConfig(self, fps, width, height): + self.fps = fps + self.width = width + self.height = height + + ''' + 录屏拉取视频 + ''' + + def recording_pull_p(self): + try: + # 如果视频信息不存在, 不初始化拉流 + if self.checkconfig(): + return + # 如果已经初始化, 不再初始化 + if self.pull_p: + return + command = ['ffmpeg -re', '-y', '-an' + # '-hide_banner', + ] + if self.pullUrl.startswith('rtsp://'): + command.extend(['-rtsp_transport', 'tcp']) + if self.isGpu: + command.extend(['-hwaccel', 'cuda']) + command.extend(['-i', self.pullUrl, + '-f', 'rawvideo', + '-pix_fmt', 'bgr24', + '-r', '25', + '-']) + self.pull_p = sp.Popen(command, stdout=sp.PIPE) + except ServiceException as s: + logger.exception("构建拉流管道异常: {}, requestId:{}", s.msg, self.requestId) + self.clear_video_info() + if self.pull_p: + logger.info("重试, 关闭拉流管道, requestId:{}", self.requestId) + self.pull_p.stdout.close() + self.pull_p.terminate() + self.pull_p.wait() + self.pull_p = None + raise s + except Exception as e: + logger.error("构建拉流管道异常:{}, requestId:{}", e, self.requestId) + self.clear_video_info() + if self.pull_p: + logger.info("重试, 关闭拉流管道, requestId:{}", self.requestId) + self.pull_p.stdout.close() + self.pull_p.terminate() + self.pull_p.wait() + self.pull_p = None + + def recording_read(self): + result = None + try: + self.recording_pull_p() + in_bytes = self.pull_p.stdout.read(self.wh) + if in_bytes is not None and len(in_bytes) > 0: + try: + result = np.frombuffer(in_bytes, np.uint8).reshape(self.read_w_h) + except Exception: + logger.error("视频格式异常:{}, requestId:{}", format_exc(), self.requestId) + raise ServiceException(ExceptionType.VIDEO_RESOLUTION_EXCEPTION.value[0], + ExceptionType.VIDEO_RESOLUTION_EXCEPTION.value[1]) + except ServiceException as s: + if self.pull_p: + logger.info("重试, 关闭拉流管道, requestId:{}", self.requestId) + self.pull_p.stdout.close() + self.pull_p.terminate() + self.pull_p.wait() + self.pull_p = None + raise s + except Exception: + logger.error("读流异常:{}, requestId:{}", format_exc(), self.requestId) + if self.pull_p: + logger.info("重试, 关闭拉流管道, requestId:{}", self.requestId) + self.pull_p.stdout.close() + self.pull_p.terminate() + self.pull_p.wait() + self.pull_p = None + return result + + ''' + 拉取视频 + ''' + + def build_pull_p(self): + try: + command = ['ffmpeg'] + if self.pullUrl.startswith("rtsp://"): + command.extend(['-rtsp_transport', 'tcp']) + command.extend(['-re', + '-y', + '-an', + # '-hwaccel', 'cuda', cuvid + '-c:v', 'h264_cuvid', + # '-resize', self.wah, + '-i', self.pullUrl, + '-f', 'rawvideo', + '-pix_fmt', 'bgr24', + '-r', '25', + '-']) + self.pull_p = sp.Popen(command, stdout=sp.PIPE) + except ServiceException as s: + logger.exception("构建拉流管道异常: {}, requestId:{}", s.msg, self.requestId) + raise s + except Exception as e: + logger.error("构建拉流管道异常:{}, requestId:{}", format_exc(), self.requestId) + self.clear_video_info() + if self.pull_p: + logger.info("重试, 关闭拉流管道, requestId:{}", self.requestId) + self.pull_p.stdout.close() + self.pull_p.terminate() + self.pull_p.wait() + self.pull_p = None + + def checkconfig(self): + if self.width is None or self.height is None or self.fps is None: + return True + return False + + def read(self): + result = None + try: + if self.pull_p is None: + self.build_pull_p() + in_bytes = self.pull_p.stdout.read(self.wh) + if in_bytes is not None and len(in_bytes) > 0: + try: + result = (np.frombuffer(in_bytes, np.uint8).reshape([self.height, self.width, 3])) + # img = (np.frombuffer(in_bytes, np.uint8)).reshape((self.h, self.w)) + except Exception as ei: + logger.error("视频格式异常:{}, requestId:{}", format_exc(), self.requestId) + raise ServiceException(ExceptionType.VIDEO_RESOLUTION_EXCEPTION.value[0], + ExceptionType.VIDEO_RESOLUTION_EXCEPTION.value[1]) + # result = cv2.cvtColor(img, cv2.COLOR_YUV2BGR_NV12) + # result = cv2.cvtColor(result, cv2.COLOR_RGB2BGR) + if self.width > Constant.width: + result = cv2.resize(result, (self.w, self.h), interpolation=cv2.INTER_LINEAR) + except ServiceException as s: + raise s + except Exception as e: + self.clear_video_info() + if self.pull_p: + logger.info("关闭拉流管道, requestId:{}", self.requestId) + self.pull_p.stdout.close() + self.pull_p.terminate() + self.pull_p.wait() + self.pull_p = None + logger.error("读流异常:{}, requestId:{}", format_exc(), self.requestId) + return result + + def close(self): + self.clear_video_info() + if self.pull_p: + if self.pull_p.stdout: + self.pull_p.stdout.close() + self.pull_p.terminate() + self.pull_p.wait() + self.pull_p = None + logger.info("关闭拉流管道完成, requestId:{}", self.requestId) + if self.p: + if self.p.stdin: + self.p.stdin.close() + self.p.terminate() + self.p.wait() + self.p = None + # self.p.communicate() + # self.p.kill() + logger.info("关闭管道完成, requestId:{}", self.requestId) + if self.or_video_file: + self.or_video_file.release() + self.or_video_file = None + logger.info("关闭原视频写入流完成, requestId:{}", self.requestId) + if self.ai_video_file: + self.ai_video_file.release() + self.ai_video_file = None + logger.info("关闭AI视频写入流完成, requestId:{}", self.requestId) + + # 构建 cv2 + # def build_cv2(self): + # try: + # if self.cap is not None: + # logger.info("重试, 关闭cap, requestId:{}", self.requestId) + # self.cap.release() + # if self.p is not None: + # logger.info("重试, 关闭管道, requestId:{}", self.requestId) + # self.p.stdin.close() + # self.p.terminate() + # self.p.wait() + # if self.pullUrl is None: + # logger.error("拉流地址不能为空, requestId:{}", self.requestId) + # raise ServiceException(ExceptionType.PULL_STREAM_URL_EXCEPTION.value[0], + # ExceptionType.PULL_STREAM_URL_EXCEPTION.value[1]) + # if self.pushUrl is None: + # logger.error("推流地址不能为空, requestId:{}", self.requestId) + # raise ServiceException(ExceptionType.PUSH_STREAM_URL_EXCEPTION.value[0], + # ExceptionType.PUSH_STREAM_URL_EXCEPTION.value[1]) + # self.cap = cv2.VideoCapture(self.pullUrl) + # if self.fps is None or self.fps == 0: + # self.fps = int(self.cap.get(cv2.CAP_PROP_FPS)) + # if self.width is None or self.width == 0: + # self.width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + # if self.height is None or self.height == 0: + # self.height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + # command = ['/usr/bin/ffmpeg', + # # '-y', # 不经过确认,输出时直接覆盖同名文件。 + # '-f', 'rawvideo', + # '-vcodec', 'rawvideo', + # '-pix_fmt', 'bgr24', # 显示可用的像素格式 + # # '-s', "{}x{}".format(self.width * 2, self.height), + # '-s', "{}x{}".format(int(self.width), int(self.height/2)), + # # '-r', str(15), + # '-i', '-', # 指定输入文件 + # '-g', '25', + # '-b:v', '3000k', + # '-tune', 'zerolatency', # 加速编码速度 + # '-c:v', 'libx264', # 指定视频编码器 + # '-sc_threshold', '0', + # '-pix_fmt', 'yuv420p', + # '-an', + # '-preset', 'ultrafast', # 指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, + # # superfast, veryfast, faster, fast, medium, slow, slower, veryslow。 + # '-f', 'flv', + # self.pushUrl] + # # 管道配置 + # logger.info("fps:{}|height:{}|width:{}|requestId:{}", self.fps, self.height, self.width, self.requestId) + # self.p = sp.Popen(command, stdin=sp.PIPE) + # except ServiceException as s: + # logger.exception("构建cv2异常: {}, requestId:{}", s, self.requestId) + # raise s + # except Exception as e: + # logger.exception("初始化cv2异常:{}, requestId:{}", e, self.requestId) + + # 构建 cv2 + def build_p(self): + try: + if self.pushUrl is None or len(self.pushUrl) == 0: + logger.error("推流地址不能为空, requestId:{}", self.requestId) + raise ServiceException(ExceptionType.PUSH_STREAM_URL_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_URL_EXCEPTION.value[1]) + command = ['ffmpeg', + # '-loglevel', 'debug', + '-re', + '-y', + "-an", + '-f', 'rawvideo', + '-vcodec', 'rawvideo', + '-pix_fmt', 'bgr24', + '-thread_queue_size', '1024', + '-s', "{}x{}".format(self.w * 2, self.h), + '-i', '-', # 指定输入文件 + '-r', str(25), + '-g', str(25), + '-maxrate', '6000k', + # '-profile:v', 'high', + '-b:v', '5000k', + # '-crf', '18', + # '-rc:v', 'vbr', + # '-cq:v', '25', + # '-qmin', '25', + # '-qmax', '25', + '-c:v', 'h264_nvenc', # + '-bufsize', '5000k', + # '-c:v', 'libx264', # 指定视频编码器 + # '-tune', 'zerolatency', # 加速编码速度 + # '-sc_threshold', '0', + '-pix_fmt', 'yuv420p', + # '-flvflags', 'no_duration_filesize', + # '-preset', 'fast', # 指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, + '-preset', 'p6', # 指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, + '-tune', 'll', + '-f', 'flv', + self.pushUrl] + logger.info("fps:{}|height:{}|width:{}|requestId:{}", self.fps, self.height, self.width, + self.requestId) + self.p = sp.Popen(command, stdin=sp.PIPE, shell=False) + except ServiceException as s: + if self.p: + if self.p.stdin: + self.p.stdin.close() + self.p.terminate() + self.p.wait() + logger.exception("构建p管道异常: {}, requestId:{}", s.msg, self.requestId) + raise s + except Exception as e: + if self.p: + if self.p.stdin: + self.p.stdin.close() + self.p.terminate() + self.p.wait() + logger.error("初始化p管道异常:{}, requestId:{}", format_exc(), self.requestId) + + def push_stream(self, frame): + current_retry_num = 0 + while True: + try: + if self.p is None: + self.build_p() + self.p.stdin.write(frame.tostring()) + break + except ServiceException as s: + raise s + except Exception as ex: + if self.p_push_time == 0: + self.p_push_time = time.time() + if time.time() - self.p_push_time < 2: + self.p_push_retry_num += 1 + self.p_push_time = time.time() + if time.time() - self.p_push_time > 60: + self.p_push_retry_num = 0 + self.p_push_time = time.time() + logger.error("推流管道异常:{}, requestId: {}", format_exc(), self.requestId) + if self.p: + try: + if self.p.stdin: + self.p.stdin.close() + self.p.terminate() + self.p.wait() + except: + logger.error("推流管道异常:{}, requestId: {}", format_exc(), self.requestId) + self.p = None + current_retry_num += 1 + if self.p_push_retry_num > 100: + logger.error("推流进管道异常:{}, requestId: {}", format_exc(), self.requestId) + raise ServiceException(ExceptionType.PUSH_STREAMING_CHANNEL_IS_OCCUPIED.value[0], + ExceptionType.PUSH_STREAMING_CHANNEL_IS_OCCUPIED.value[1]) + if current_retry_num > 3: + logger.error("推流进管道异常:{}, requestId: {}", format_exc(), self.requestId) + raise ServiceException(ExceptionType.PUSH_STREAM_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_EXCEPTION.value[1]) + + def build_or_write(self): + try: + if self.orFilePath is not None and self.or_video_file is None: + self.or_video_file = cv2.VideoWriter(self.orFilePath, cv2.VideoWriter_fourcc(*'mp4v'), 25, + (self.w, self.h)) + # self.or_video_file.set(cv2.CAP_PROP_BITRATE, 5000) + if self.or_video_file is None: + logger.error("or_video_file为空, requestId:{}", self.requestId) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + except ServiceException as s: + if self.or_video_file: + self.or_video_file.release() + self.or_video_file = None + logger.error("构建OR文件写对象异常: {}, requestId:{}", s.msg, self.requestId) + raise s + except Exception as e: + if self.or_video_file: + self.or_video_file.release() + self.or_video_file = None + logger.error("构建OR文件写对象异常: {}, requestId:{}", format_exc(), self.requestId) + raise e + except: + if self.or_video_file: + self.or_video_file.release() + self.or_video_file = None + logger.exception("构建OR文件写对象异常:{}, requestId:{}", format_exc(), self.requestId) + raise Exception("构建OR文件写对象异常") + + def build_ai_write(self): + try: + if self.aiFilePath is not None and self.ai_video_file is None: + self.ai_video_file = cv2.VideoWriter(self.aiFilePath, cv2.VideoWriter_fourcc(*'mp4v'), 25, + (self.w * 2, self.h)) + # self.ai_video_file.set(cv2.CAP_PROP_BITRATE, 5000) + if self.ai_video_file is None: + logger.error("ai_video_file为空, requestId:{}", self.requestId) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + except ServiceException as s: + if self.ai_video_file: + self.ai_video_file.release() + self.ai_video_file = None + logger.error("构建AI文件写对象异常: {}, requestId:{}", s.msg, self.requestId) + raise s + except Exception as e: + if self.ai_video_file: + self.ai_video_file.release() + self.ai_video_file = None + logger.error("构建AI文件写对象异常: {}, requestId:{}", format_exc(), self.requestId) + raise e + except: + if self.ai_video_file: + self.ai_video_file.release() + self.ai_video_file = None + logger.error("构建AI文件写对象异常:{}, requestId:{}", format_exc(), self.requestId) + raise Exception("构建AI文件写对象异常") + + def video_or_write(self, frame): + ai_retry_num = 0 + while True: + try: + if self.or_video_file is None: + self.build_or_write() + self.or_video_file.write(frame) + break + except ServiceException as s: + raise s + except Exception as ex: + if ai_retry_num > 3: + logger.error("重新写入原视频视频到本地, 重试失败:{}, requestId: {}", format_exc(), + self.requestId) + raise ex + finally: + ai_retry_num += 1 + + def video_ai_write(self, frame): + ai_retry_num = 0 + while True: + try: + if self.ai_video_file is None: + self.build_ai_write() + self.ai_video_file.write(frame) + break + except ServiceException as s: + raise s + except Exception as ex: + if ai_retry_num > 3: + logger.exception("重新写入分析后的视频到本地,重试失败:{}, requestId: {}", format_exc(), + self.requestId) + raise ex + finally: + ai_retry_num += 1 + + def video_merge(self, frame1, frame2): + # frameLeft = cv2.resize(frame1, (int(self.width / 2), int(self.height / 2)), interpolation=cv2.INTER_LINEAR) + # frameRight = cv2.resize(frame2, (int(self.width / 2), int(self.height / 2)), interpolation=cv2.INTER_LINEAR) + # frame_merge = np.hstack((frameLeft, frameRight)) + frame_merge = np.hstack((frame1, frame2)) + return frame_merge + + def getP(self): + if self.p is None: + logger.error("获取管道为空, requestId:{}", self.requestId) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + return self.p + + def getOrVideoFile(self): + if self.or_video_file is None: + logger.error("获取原视频写入对象为空, requestId:{}", self.requestId) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + return self.or_video_file + + def getAiVideoFile(self): + if self.ai_video_file is None: + logger.error("获取AI视频写入对象为空, requestId:{}", self.requestId) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + return self.ai_video_file + + +def check_video_stream(width, height): + if width is None or height is None: + return True + return False + + +def build_video_info(pull_url, requestId): + try: + if pull_url is None or len(pull_url) == 0: + logger.error("拉流地址不能为空, requestId:{}", requestId) + raise ServiceException(ExceptionType.PULL_STREAM_URL_EXCEPTION.value[0], + ExceptionType.PULL_STREAM_URL_EXCEPTION.value[1]) + pp = sp.Popen(['ffprobe', '-show_format', '-show_streams', '-of', 'json', pull_url], stdout=sp.PIPE, + stderr=sp.PIPE) + out, err = pp.communicate(timeout=18) + if pp.returncode != 0: + logger.error("获取视频信息失败: {}, requestId:{}", err.decode('utf-8'), requestId) + raise Exception("未获取视频信息!!!!") + probe = loads(out.decode('utf-8')) + video_stream = next((stream for stream in probe['streams'] if stream.get('codec_type') == 'video'), None) + if video_stream is None: + raise Exception("未获取视频信息!!!!") + width_new, height_new = video_stream.get('width'), video_stream.get('height') + nb_frames = video_stream.get('nb_frames', 0) + duration = video_stream.get('duration') + if duration is not None and float(duration) != float(0): + nb_frames = int(float(duration) * 25) + if width_new is not None and int(width_new) != 0 and height_new is not None and int(height_new) != 0: + height_o = int(height_new) + width, height = int(width_new), height_o * 3 // 2 + width_height_3 = width * height + all_frames = int(nb_frames) + w_2, h_2 = width, height_o + if width > Constant.width: + w_2, h_2 = width // 2, height_o // 2 + logger.info("视频信息, width:{}|height:{}|all_frames:{}, requestId:{}", width, height_o, all_frames, + requestId) + return width, height, width_height_3, all_frames, w_2, h_2 + raise Exception("未获取视频信息!!!!") + except ServiceException as s: + logger.error("获取视频信息异常: {}, requestId:{}", s.msg, requestId) + raise s + except Exception: + logger.error("获取视频信息异常:{}, requestId:{}", format_exc(), requestId) + return None, None, None, 0, None, None + + +def build_video_info2(pull_url, requestId): + try: + pp = sp.Popen(['ffprobe', '-show_format', '-show_streams', '-of', 'json', pull_url], stdout=sp.PIPE, + stderr=sp.PIPE) + out, err = pp.communicate(timeout=17) + if pp.returncode != 0: + logger.error("获取视频信息失败: {}, requestId:{}", err.decode('utf-8'), requestId) + raise Exception("未获取视频信息!!!!") + probe = loads(out.decode('utf-8')) + video_stream = next((stream for stream in probe['streams'] if stream.get('codec_type') == 'video'), None) + if video_stream is None: + raise Exception("未获取视频信息!!!!") + width_new, height_new = video_stream.get('width'), video_stream.get('height') + nb_frames = video_stream.get('nb_frames', 0) + # fps = video_stream.get('r_frame_rate') + duration = video_stream.get('duration') + if duration is not None and float(duration) != float(0): + nb_frames = int(float(duration) * 25) + # bit_rate = video_stream.get('bit_rate') + if width_new is not None and int(width_new) != 0 and height_new is not None and int(height_new) != 0: + width_o, height_o = int(width_new), int(height_new) + # width_height_3 = width * height * 3 + width_height_3 = width_o * height_o * 3 // 2 + width, height, all_frames = width_o, height_o * 3 // 2, int(nb_frames) + w, h = width_o, height_o + if width > Constant.width: + w, h = width_o // 2, height_o // 2 + # up, down = str(fps).split('/') + # self.fps = int(eval(up) / eval(down)) + # if duration: + # self.duration = float(video_stream['duration']) + # self.bit_rate = int(bit_rate) / 1000 + logger.info("视频信息, width:{}|height:{}|all_frames:{}, requestId:{}", width_o, height_o, all_frames, + requestId) + return width, height, width_height_3, all_frames, w, h + raise Exception("未获取视频信息!!!!") + except ServiceException as s: + logger.error("获取视频信息异常: {}, requestId:{}", s.msg, requestId) + raise s + except Exception: + logger.error("获取视频信息异常:{}, requestId:{}", format_exc(), requestId) + return None, None, None, 0, None, None + + +def start_pull_p(pull_url, requestId): + try: + command = ['ffmpeg'] + if pull_url.startswith("rtsp://"): + command.extend(['-timeout', '20000000', '-rtsp_transport', 'tcp']) + if pull_url.startswith("http") or pull_url.startswith("rtmp"): + command.extend(['-rw_timeout', '20000000']) + command.extend(['-re', + '-y', + '-an', + # '-hwaccel', 'cuda', cuvid + '-c:v', 'h264_cuvid', + # '-resize', self.wah, + '-i', pull_url, + '-f', 'rawvideo', + # '-pix_fmt', 'bgr24', + '-r', '25', + '-']) + return sp.Popen(command, stdout=sp.PIPE) + except ServiceException as s: + logger.error("构建拉流管道异常: {}, requestId:{}", s.msg, requestId) + raise s + except Exception as e: + logger.error("构建拉流管道异常:{}, requestId:{}", format_exc(), requestId) + raise e + + +def clear_pull_p(pull_p, requestId): + try: + if pull_p and pull_p.poll() is None: + logger.info("关闭拉流管道, requestId:{}", requestId) + if pull_p.stdout: + pull_p.stdout.close() + pull_p.terminate() + pull_p.wait(timeout=30) + logger.info("拉流管道已关闭, requestId:{}", requestId) + except Exception as e: + logger.error("关闭拉流管道异常: {}, requestId:{}", format_exc(), requestId) + if pull_p and pull_p.poll() is None: + pull_p.kill() + pull_p.wait(timeout=30) + raise e + + +def pull_read_video_stream(pull_p, pull_url, width, height, width_height_3, w_2, h_2, requestId): + result = None + try: + if pull_p is None: + pull_p = start_pull_p(pull_url, requestId) + in_bytes = pull_p.stdout.read(width_height_3) + if in_bytes is not None and len(in_bytes) > 0: + try: + # result = (np.frombuffer(in_bytes, np.uint8).reshape([height * 3 // 2, width, 3])) + result = (np.frombuffer(in_bytes, np.uint8)).reshape((height, width)) + result = cv2.cvtColor(result, cv2.COLOR_YUV2BGR_NV12) + # result = cv2.cvtColor(result, cv2.COLOR_RGB2BGR) + if width > Constant.width: + result = cv2.resize(result, (w_2, h_2), interpolation=cv2.INTER_LINEAR) + except Exception: + logger.error("视频格式异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.VIDEO_RESOLUTION_EXCEPTION.value[0], + ExceptionType.VIDEO_RESOLUTION_EXCEPTION.value[1]) + except ServiceException as s: + clear_pull_p(pull_p, requestId) + raise s + except Exception: + clear_pull_p(pull_p, requestId) + pull_p, width, height = None, None, None + logger.error("读流异常:{}, requestId:{}", format_exc(), requestId) + return result, pull_p, width, height + + +def pull_read_video_stream2(pull_p, pull_url, width, height, width_height_3, w, h, requestId): + result = None + try: + if pull_p is None: + pull_p = start_pull_p(pull_url, requestId) + in_bytes = pull_p.stdout.read(width_height_3) + if in_bytes is not None and len(in_bytes) > 0: + try: + result = (np.frombuffer(in_bytes, np.uint8)).reshape((height, width)) + result = cv2.cvtColor(result, cv2.COLOR_YUV2BGR_NV12) + if width > Constant.width: + result = cv2.resize(result, (w, h), interpolation=cv2.INTER_LINEAR) + except Exception: + logger.error("视频格式异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.VIDEO_RESOLUTION_EXCEPTION.value[0], + ExceptionType.VIDEO_RESOLUTION_EXCEPTION.value[1]) + except ServiceException as s: + clear_pull_p(pull_p, requestId) + raise s + except Exception: + clear_pull_p(pull_p, requestId) + pull_p, width, height = None, None, None + logger.error("读流异常:{}, requestId:{}", format_exc(), requestId) + return result, pull_p, width, height + + +def video_conjuncing(frame1, frame2): + # frameLeft = cv2.resize(frame1, (int(self.width / 2), int(self.height / 2)), interpolation=cv2.INTER_LINEAR) + # frameRight = cv2.resize(frame2, (int(self.width / 2), int(self.height / 2)), interpolation=cv2.INTER_LINEAR) + # frame_merge = np.hstack((frameLeft, frameRight)) + frame_merge = np.hstack((frame1, frame2)) + return frame_merge + + +def build_push_p(push_url, width, height, requestId): + push_p = None + try: + if push_url is None or len(push_url) == 0: + logger.error("推流地址不能为空, requestId:{}", requestId) + raise ServiceException(ExceptionType.PUSH_STREAM_URL_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_URL_EXCEPTION.value[1]) + command = ['ffmpeg', + # '-loglevel', 'debug', + # '-re', + '-y', + "-an", + '-f', 'rawvideo', + '-vcodec', 'rawvideo', + '-pix_fmt', 'bgr24', + '-thread_queue_size', '1024', + '-s', "{}x{}".format(width, height), + '-i', '-', # 指定输入文件 + '-r', str(25), + '-g', str(25), + '-maxrate', '6000k', + # '-profile:v', 'high', + '-b:v', '4000k', + # '-crf', '18', + # '-rc:v', 'vbr', + # '-cq:v', '25', + # '-qmin', '25', + # '-qmax', '25', + '-c:v', 'h264_nvenc', # + '-bufsize', '4000k', + # '-c:v', 'libx264', # 指定视频编码器 + # '-tune', 'zerolatency', # 加速编码速度 + # '-sc_threshold', '0', + # '-rc', 'cbr_ld_hq', + # '-zerolatency', '1', + '-pix_fmt', 'yuv420p', + # '-flvflags', 'no_duration_filesize', + # '-preset', 'fast', # 指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, + '-preset', 'p6', # 指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, + '-tune', 'll', + '-f', 'flv', + push_url] + logger.info("height:{}|width:{}|requestId:{}", height, width, requestId) + push_p = sp.Popen(command, stdin=sp.PIPE, shell=False) + return push_p + except ServiceException as s: + if push_p: + if push_p.stdin: + push_p.stdin.close() + push_p.terminate() + push_p.wait() + logger.error("构建p管道异常: {}, requestId:{}", s.msg, requestId) + raise s + except Exception as e: + if push_p: + if push_p.stdin: + push_p.stdin.close() + push_p.terminate() + push_p.wait() + logger.error("初始化p管道异常:{}, requestId:{}", format_exc(), requestId) + raise e + + +def push_video_stream(frame, push_p, push_url, p_push_status, requestId): + """ + :param frame: 当前视频帧 + :param push_p: 推流管道 + :param push_url: 推流地址 + :param p_push_status: 控制异常控制 + :param requestId: 请求id + :return: 推流管道 + """ + st = time() + try: + if push_p is None: + height, width = frame.shape[0:2] + push_p = build_push_p(push_url, width, height, requestId) + push_p.stdin.write(frame.tostring()) + return push_p + except ServiceException as s: + clear_push_p(push_p, requestId) + raise s + except Exception: + et = time() - st + logger.error("推流异常使用时间:{}, requestId: {}", et, requestId) + if et > 20: + logger.error("推流进管道异常:{}, requestId: {}", format_exc(), requestId) + raise ServiceException(ExceptionType.PUSH_STREAMING_CHANNEL_IS_OCCUPIED.value[0], + ExceptionType.PUSH_STREAMING_CHANNEL_IS_OCCUPIED.value[1]) + if p_push_status[0] == 0: + p_push_status[0] = time() + p_push_status[1] += 1 + elif time() - p_push_status[0] <= 60: + p_push_status[1] += 1 + p_push_status[0] = time() + elif time() - p_push_status[0] > 60: + p_push_status[1] = 1 + p_push_status[0] = time() + logger.error("推流管道异常:{}, requestId: {}", format_exc(), requestId) + clear_push_p(push_p, requestId) + if p_push_status[1] > 5: + logger.error("推流进管道异常:{}, requestId: {}", format_exc(), requestId) + raise ServiceException(ExceptionType.PUSH_STREAMING_CHANNEL_IS_OCCUPIED.value[0], + ExceptionType.PUSH_STREAMING_CHANNEL_IS_OCCUPIED.value[1]) + return None + + +def clear_push_p(push_p, requestId): + if push_p: + try: + if push_p.stdin: + push_p.stdin.close() + push_p.terminate() + push_p.wait() + except Exception: + logger.error("推流管道异常:{}, requestId: {}", format_exc(), requestId) + + +def close_or_write_stream(or_video_file, requestId): + try: + if or_video_file: + or_video_file.release() + except Exception: + logger.info("关闭原视频写流管道异常:{}, requestId:{}", format_exc(), requestId) + + +def close_ai_write_stream(ai_video_file, requestId): + try: + if ai_video_file: + ai_video_file.release() + except Exception: + logger.info("关闭AI视频写流管道异常:{}, requestId:{}", format_exc(), requestId) + + +def close_all_p(push_p, or_video_file, ai_video_file, requestId): + logger.info("开始停止推流、写流管道!requestId:{}", requestId) + clear_push_p(push_p, requestId) + close_or_write_stream(or_video_file, requestId) + close_ai_write_stream(ai_video_file, requestId) + logger.info("停止推流、写流管道完成!requestId:{}", requestId) + + +def build_or_video(orFilePath, width, height, requestId): + or_video_file = None + try: + or_video_file = cv2.VideoWriter(orFilePath, cv2.VideoWriter_fourcc(*'mp4v'), 25, (width, height)) + if or_video_file is None: + logger.error("or_video_file为空, requestId:{}", requestId) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + return or_video_file + except ServiceException as s: + if or_video_file: + or_video_file.release() + logger.error("构建OR文件写对象异常: {}, requestId:{}", s.msg, requestId) + raise s + except Exception as e: + if or_video_file: + or_video_file.release() + logger.error("构建OR文件写对象异常: {}, requestId:{}", format_exc(), requestId) + raise e + + +def write_or_video(frame, orFilePath, or_video_file, or_write_status, requestId): + """ + :param frame: 当时视频帧 + :param orFilePath: 原视频名称 + :param or_video_file: 原视频本地写流对象 + :param or_write_status: 原视频写流状态检查 [0, 0] 第一个参数时间,第二个参数重试的次数 + :param requestId: 请求id + :return: 原视频本地写流对象 + :desc 如果写流失败了, 不重试, 丢弃本次视频帧 + """ + try: + if or_video_file is None: + height, width = frame.shape[0], frame.shape[1] + or_video_file = build_or_video(orFilePath, width, height, requestId) + or_video_file.write(frame) + return or_video_file + except ServiceException as s: + if or_video_file: + or_video_file.release() + raise s + except Exception as ex: + # 当第一次写视频帧到本地失败, 更新or_write_status的时间和重试次数 + if or_write_status[0] == 0: + or_write_status[0] = time() + or_write_status[1] += 1 + # 1分钟内失败重试次数更新, 1分钟中容忍小于5次的失败次数 + elif time() - or_write_status[0] <= 60: + or_write_status[1] += 1 + or_write_status[0] = time() + # 大于1分钟初始化检查数组 + elif time() - or_write_status[0] > 60: + or_write_status[1] = 1 + or_write_status[0] = time() + if or_write_status[1] > 5: + if or_video_file: + or_video_file.release() + logger.error("重新写入原视频视频到本地, 重试失败:{}, requestId: {}", format_exc(), requestId) + raise ex + return or_video_file + + +def build_ai_video(aiFilePath, width, height, requestId): + ai_video_file = None + try: + ai_video_file = cv2.VideoWriter(aiFilePath, cv2.VideoWriter_fourcc(*'mp4v'), 25, (width, height)) + if ai_video_file is None: + logger.error("ai_video_file为空, requestId:{}", requestId) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + return ai_video_file + except ServiceException as s: + if ai_video_file: + ai_video_file.release() + logger.error("构建AI文件写对象异常: {}, requestId:{}", s.msg, requestId) + raise s + except Exception as e: + if ai_video_file: + ai_video_file.release() + logger.error("构建AI文件写对象异常: {}, requestId:{}", format_exc(), requestId) + raise e + + +def write_ai_video(frame, aiFilePath, ai_video_file, ai_write_status, requestId): + try: + if ai_video_file is None: + height, width = frame.shape[0], frame.shape[1] + ai_video_file = build_ai_video(aiFilePath, width, height, requestId) + ai_video_file.write(frame) + return ai_video_file + except ServiceException as s: + if ai_video_file: + ai_video_file.release() + raise s + except Exception as ex: + if ai_write_status[0] == 0: + ai_write_status[0] = time() + ai_write_status[1] += 1 + # 大于1分钟初始化检查数组 + elif time() - ai_write_status[0] > 60: + ai_write_status[1] = 1 + ai_write_status[0] = time() + # 1分钟内失败重试次数更新, 1分钟中容忍小于5次的失败次数 + elif time() - ai_write_status[0] <= 60: + ai_write_status[1] += 1 + ai_write_status[0] = time() + if ai_write_status[1] > 5: + if ai_video_file: + ai_video_file.release() + logger.error("重新写入分析后的视频到本地,重试失败:{}, requestId: {}", format_exc(), requestId) + raise ex + return ai_video_file diff --git a/util/FileUtils.py b/util/FileUtils.py new file mode 100644 index 0000000..9446319 --- /dev/null +++ b/util/FileUtils.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +from os import makedirs +from os.path import exists + +from loguru import logger + +''' + 文件处理工具类 +''' + + +def create_dir_not_exist(file_path): + if not exists(file_path): + logger.info("开始创建文件夹: {}", file_path) + makedirs(file_path) + logger.info("文件夹创建完成 {}", file_path) diff --git a/util/GPUtils.py b/util/GPUtils.py new file mode 100644 index 0000000..ec528ce --- /dev/null +++ b/util/GPUtils.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- +from traceback import format_exc + +from GPUtil import getAvailable, getGPUs +from loguru import logger +from torch.cuda import is_available + +from enums.ExceptionEnum import ExceptionType +from exception.CustomerException import ServiceException + + +# order- 确定返回可用 GPU 设备 ID 的顺序。order应指定为以下字符串之一: +# 'first'- 按升序排列可用的 GPU 设备 ID(默认) +# 'last'- 按 id 降序排列可用的 GPU 设备 id +# 'random'- 随机订购可用的 GPU 设备 ID +# 'load'- 按负载递增排序可用的 GPU 设备 ID +# 'memory'- 通过升序内存使用来排序可用的 GPU 设备 ID +# limit- 将返回的 GPU 设备 ID 数量限制为指定数量。必须是正整数。(默认 = 1) +# maxLoad- 被认为可用的 GPU 的最大当前相对负载。负载大于 的 GPUmaxLoad不会返回。(默认 = 0.5) +# maxMemory- 被视为可用的 GPU 的最大当前相对内存使用量。maxMemory不返回当前内存使用量大于的 GPU 。(默认 = 0.5) +# includeNan- 真/假标志,指示是否包括负载或内存使用为 NaN 的 GPU(指示无法检索使用情况)。(默认 = 假) +# excludeID- ID 列表,应从可用 GPU 列表中排除。见GPU类描述。(默认 = []) +# excludeUUIDexcludeID-除了它使用 UUID 之外,其他相同。(默认 = []) +# 输出 +# deviceIDs - 所有可用 GPU 设备 ID 的列表。如果当前负载和内存使用量分别小于maxLoad和maxMemory,则认为 GPU 可用。该列表是根据 排序的order。返回的设备 ID 的最大数量由 限制limit。 +def get_gpu_ids(): + deviceIDs = getAvailable(maxLoad=0.80, maxMemory=0.80) + return deviceIDs + + +def get_all_gpu_ids(): + return getGPUs() + + +def get_first_gpu_name(): + gps = get_all_gpu_ids() + if len(gps) == 0: + raise ServiceException(ExceptionType.NO_GPU_RESOURCES.value[0], + ExceptionType.NO_GPU_RESOURCES.value[1]) + return gps[0].name + + +def check_gpu_resource(requestId=None): + gpu_ids = get_gpu_ids() + if len(gpu_ids) == 0 or 0 not in gpu_ids: + print_gpu_status(requestId) + raise ServiceException(ExceptionType.NO_RESOURCES.value[0], + ExceptionType.NO_RESOURCES.value[1]) + return gpu_ids + + +def print_gpu_ex_status(requestId=None): + result = False + try: + gpu_ids = get_gpu_ids() + if len(gpu_ids) == 0 or 0 not in gpu_ids: + result = True + print_gpu_status(requestId) + except Exception: + logger.error("打印gpu状态异常: {}", format_exc()) + return result +def select_best_server(servers): + best_server_info = None + lowest_memory_usage = float('inf') # 初始化为无穷大 + + for ip, server_info in servers.items(): + gpu_list = server_info['GPU'] + for gpu in gpu_list: + if gpu['ID'] == 0: + memory_used = gpu['Memory Used'] + memory_total = gpu['Memory Total'] + memory_usage = (memory_used / memory_total) * 100 # 计算显存使用率 + + if memory_usage < lowest_memory_usage: + lowest_memory_usage = memory_usage + best_server_info = { + 'hostname': server_info['System']['Platform Node'], + 'IP': server_info['System']['Local IP Address'], + 'gpuId': gpu['ID'] + } + + return best_server_info + +def print_gpu_status(requestId=None): + try: + GPUs = get_all_gpu_ids() + if len(GPUs) == 0: + return + for gpu in GPUs: + if requestId: + logger.info("""############################################################################################ + GPU ID:{}, GPU 名称:{}, 负载率:{}, 内存使用率:{}, 总内存:{}, 占用内存:{}, 空闲内存:{}, requestId:{} + ############################################################################################""", gpu.id, + gpu.name, gpu.load * 100, gpu.memoryUtil * 100, gpu.memoryTotal, gpu.memoryUsed, gpu.memoryFree, + requestId) + else: + logger.info("""############################################################################################ + GPU ID:{}, GPU 名称:{}, 负载率:{}, 内存使用率:{}, 总内存:{}, 占用内存:{}, 空闲内存:{} + ############################################################################################""", gpu.id, + gpu.name, gpu.load * 100, gpu.memoryUtil * 100, gpu.memoryTotal, gpu.memoryUsed, gpu.memoryFree) + except Exception: + logger.error("打印gpu状态异常: {}", format_exc()) + + +def check_cude_is_available(): + if not is_available(): + raise Exception("cuda不在活动状态, 请检测显卡驱动是否正常!!!!") diff --git a/util/ImageUtils.py b/util/ImageUtils.py new file mode 100644 index 0000000..4854f49 --- /dev/null +++ b/util/ImageUtils.py @@ -0,0 +1,391 @@ +# -*- coding: utf-8 -*- +from io import BytesIO +from traceback import format_exc + +import cv2 +import requests +from PIL import Image, ImageDraw, ImageFont +import numpy as np +from loguru import logger + +from enums.ExceptionEnum import ExceptionType +from exception.CustomerException import ServiceException + +''' + 文字水印 +''' + + +class TextWaterMark(): + def __init__(self): + self.color_dict = { + # R G B + # 网址查看:https://tool.oschina.net/commons?type=3 + # 网址查看:http://tools.jb51.net/static/colorpicker/ + 'white': (255, 255, 255, 255), + 'black': (0, 0, 0, 255), + 'gray': (205, 201, 201, 255), + 'red': (255, 0, 0, 255), + 'yellow': (255, 215, 0, 255), + 'blue': (0, 0, 170, 255), + 'purple': (205, 105, 201, 255), + 'green': (0, 205, 0, 255) + } + self.position_list = [1, 2, 3, 4] + + """ + 普通照片水印 + params: + image:图片 + text:水印文字 + position:水印位置 + 1:左上 + 2:右上 + 3:右下 + 4:左下 + fontface: 字体 + fontsize:字体大小 + fontcolor:字体颜色 + [white, black, gray, red, yellow, blue, purple, green] + """ + + def common_water(self, image, text, position=1, fontface='../font/simsun.ttc', fontsize=20, fontcolor='black'): + flag = False + if isinstance(image, np.ndarray): # 判断是否OpenCV图片类型 + flag = True + image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGRA2RGBA)) + if position not in self.position_list: + position = 1 + w, h = image.size[:2] + keys = self.color_dict.keys() + if fontcolor not in keys: + fontcolor = 'black' + color = self.color_dict[fontcolor] + fnt = ImageFont.truetype(fontface, fontsize) + im = image.convert('RGBA') + mask = Image.new('RGBA', im.size, (0, 0, 0, 0)) + d = ImageDraw.Draw(mask) + size_w, size_h = d.textsize(text, font=fnt) + if position == 1: + weizhi = (w * 0.1, h * 0.1) + elif position == 2: + weizhi = (w * 0.9 - size_w, h * 0.1) + elif position == 3: + weizhi = (w * 0.9 - size_w, h * 0.9 - size_h) + else: + weizhi = (w * 0.1, h * 0.9 - size_h) + # position 为左上角位置 + d.text(weizhi, text, font=fnt, fill=color) + out = Image.alpha_composite(im, mask) + if flag: + out = cv2.cvtColor(np.asarray(out), cv2.COLOR_BGRA2RGBA) + return out + + """ + 半透明水印,布满整张图,并且自动旋转45° + params: + image:图片 + text:文字 + fontsize:文字大小 + """ + + def fill_water(self, image, text, fontsize): + flag = False + if isinstance(image, np.ndarray): # 判断是否OpenCV图片类型 + flag = True + image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGRA2RGBA)) + font = ImageFont.truetype('../font/simsun.ttc', fontsize) + # 添加背景 + new_img = Image.new('RGBA', (image.size[0] * 3, image.size[1] * 3), (255, 255, 255, 255)) + new_img.paste(image, image.size) + + # 添加水印 + font_len = len(text) + rgba_image = new_img.convert('RGBA') + text_overlay = Image.new('RGBA', rgba_image.size, (0, 0, 0, 0)) + image_draw = ImageDraw.Draw(text_overlay) + + for i in range(0, rgba_image.size[0], font_len * 40 + 100): + for j in range(0, rgba_image.size[1], 200): + # print(f'i:{i}, j:{j}, text:{text}, font:{font}') + image_draw.text((i, j), text, font=font, fill=(0, 0, 0, 50)) + text_overlay = text_overlay.rotate(-45) + image_with_text = Image.alpha_composite(rgba_image, text_overlay) + + image_with_text = image_with_text.crop((image.size[0], image.size[1], image.size[0] * 2, image.size[1] * 2)) + if flag: + image_with_text = cv2.cvtColor(np.asarray(image_with_text), cv2.COLOR_BGRA2RGBA) + return image_with_text + + +class PictureWaterMark: + __slots__ = ('logo', '__requestId') + + def __init__(self, logo=None, requestId=None): + self.__requestId = requestId + self.logo = logo + if requestId is None: + self.__requestId = '1' + if logo is None: + self.logo = cv2.imread("./image/logo.png", -1) + + # def common_water(self, image, logo): + # width, height = image.shape[1], image.shape[0] + # mark_width, mark_height = logo.shape[1], logo.shape[0] + # rate = int(width * 0.2) / mark_width + # logo_new = cv2.resize(logo, None, fx=rate, fy=rate, interpolation=cv2.INTER_NEAREST) + # position = (int(width * 0.95 - logo_new.shape[1]), int(height * 0.95 - logo_new.shape[0])) + # b = Image.new('RGBA', (width, height), (0, 0, 0, 0)) # 创建新图像:透明' + # a = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) + # watermark = Image.fromarray(cv2.cvtColor(logo_new, cv2.COLOR_BGRA2RGBA)) + # # 图片旋转 + # # watermark = watermark.rotate(45) + # b.paste(a, (0, 0)) + # b.paste(watermark, position, mask=watermark) + # return cv2.cvtColor(np.asarray(b), cv2.COLOR_BGR2RGB) + + def common_water_1(self, image, logo, alpha=1): + try: + h, w = image.shape[0], image.shape[1] + # if w >= h: + rate = int(w * 0.1) / logo.shape[1] + # else: + # rate = int(h * 0.1) / logo.shape[0] + mask = cv2.resize(logo, None, fx=rate, fy=rate, interpolation=cv2.INTER_NEAREST) + mask_h, mask_w = mask.shape[0], mask.shape[1] + mask_channels = cv2.split(mask) + dst_channels = cv2.split(image) + # b, g, r, a = cv2.split(mask) + # 计算mask在图片的坐标 + # if w >= h: + ul_points = (int(h * 0.95) - mask_h, int(w - h * 0.05 - mask_w)) + dr_points = (int(h * 0.95), int(w - h * 0.05)) + # else: + # ul_points = (int(h * 0.95) - mask_h, int(w - h * 0.05 - mask_w)) + # dr_points = (int(h * 0.95), int(w - h * 0.05)) + for i in range(3): + dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] = dst_channels[i][ + ul_points[0]: dr_points[0], + ul_points[1]: dr_points[ + 1]] * ( + 255.0 - mask_channels[ + 3] * alpha) / 255 + dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] += np.array( + mask_channels[i] * (mask_channels[3] * alpha / 255), dtype=np.uint8) + dst_img = cv2.merge(dst_channels) + return dst_img + except Exception: + logger.error("加水印异常:{}, requestId:{}", format_exc(), self.__requestId) + return image + + +def add_water_pic(image, logo, requestId, alpha=1): + try: + h, w = image.shape[0], image.shape[1] + # if w >= h: + rate = int(w * 0.1) / logo.shape[1] + # else: + # rate = int(h * 0.1) / logo.shape[0] + mask = cv2.resize(logo, None, fx=rate, fy=rate, interpolation=cv2.INTER_NEAREST) + mask_h, mask_w = mask.shape[0], mask.shape[1] + mask_channels = cv2.split(mask) + dst_channels = cv2.split(image) + # b, g, r, a = cv2.split(mask) + # 计算mask在图片的坐标 + # if w >= h: + ul_points = (int(h * 0.95) - mask_h, int(w - h * 0.05 - mask_w)) + dr_points = (int(h * 0.95), int(w - h * 0.05)) + # else: + # ul_points = (int(h * 0.95) - mask_h, int(w - h * 0.05 - mask_w)) + # dr_points = (int(h * 0.95), int(w - h * 0.05)) + for i in range(3): + dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] = dst_channels[i][ + ul_points[0]: dr_points[0], + ul_points[1]: dr_points[ + 1]] * ( + 255.0 - mask_channels[ + 3] * alpha) / 255 + dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] += np.array( + mask_channels[i] * (mask_channels[3] * alpha / 255), dtype=np.uint8) + dst_img = cv2.merge(dst_channels) + return dst_img + except Exception: + logger.error("加水印异常:{}, requestId:{}", format_exc(), requestId) + return image + + +# 差值感知算法 +def dHash(image): + # 缩放9*8 + image = cv2.resize(image, (9, 8), interpolation=cv2.INTER_CUBIC) + # 转换灰度图 + image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) + # print(image.shape) + hash = [] + # 每行前一个像素大于后一个像素为1,相反为0,生成哈希 + for i in range(8): + for j in range(8): + if image[i, j] > image[i, j + 1]: + hash.append(1) + else: + hash.append(0) + return hash + + +# 计算汉明距离 +def Hamming_distance(hash1, hash2): + num = 0 + for index in range(len(hash1)): + if hash1[index] != hash2[index]: + num += 1 + return num + + +def url2Array(url, enable_ex=True): + try: + response = requests.get(url) + image = Image.open(BytesIO(response.content)) + image1 = np.array(image) + img_bgr = cv2.cvtColor(image1, cv2.COLOR_RGB2BGR) + return img_bgr + except Exception: + logger.exception("url地址请求异常: {}", format_exc()) + if enable_ex: + raise ServiceException(ExceptionType.URL_ADDRESS_ACCESS_FAILED.value[0], + ExceptionType.URL_ADDRESS_ACCESS_FAILED.value[1]) + return None + + +def url2Content(url): + response = requests.get(url) + return response.content + + +def url2Image(url): + response = requests.get(url) + image = Image.open(BytesIO(response.content)) + image1 = np.array(image) + img_bgr = cv2.cvtColor(image1, cv2.COLOR_RGB2BGR) + img = Image.fromarray(img_bgr) + return img + + +def url2Byte(url): + response = requests.get(url) + return BytesIO(response.content) + + +def markRectangle(url, text, textCoordinate, imageLeftUpCoordinate, imageRightDownCoordinate, color): + img = url2Array(url) + # ( 蓝, 绿, 红) + # 红色 (0, 0, 255) + # 洋红色 (255, 0, 255) + # 青色 (255, 255, 0) + # 黑色 (0, 0, 0) + # 蓝色 (255, 0, 0) + # 绿色 (0, 255, 0) + # 黄色 (0, 255, 255) # 不考虑 + cv2.putText(img, text, textCoordinate, cv2.FONT_HERSHEY_SIMPLEX, 1.0, color, 1, cv2.LINE_AA) + # rectangle 坐标的参数格式为左上角(x1, y1),右下角(x2, y2), 颜色 , 粗细 + cv2.rectangle(img, imageLeftUpCoordinate, imageRightDownCoordinate, color, 2) + return img + + +# def draw_painting_joint(img, xywh, score=0.5, color=None, +# font={'line_thickness': None, 'boxLine_thickness': None, 'fontSize': None}): +# imh, imw, imc = img.shape +# tl = font['line_thickness'] or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 +# box_tl = font['boxLine_thickness'] or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 # 根据图像的尺寸计算出适合用于绘制图像边框的线宽。 +# c1, c2 = (int(xywh[0]), int(xywh[1])), (int(xywh[2]), int(xywh[3])) +# cv2.rectangle(img, c1, c2, color, thickness=box_tl, lineType=cv2.LINE_AA) +# +# label = ' %.2f' % (score) +# tf = max(tl, 1) # font thickness +# fontScale = font['fontSize'] or tl * 0.33 +# t_size = cv2.getTextSize(label, 0, fontScale=fontScale, thickness=tf)[0] +# cv2.rectangle(img, (int(box[0]) + lw, int(box[1])), c2, color, -1, cv2.LINE_AA) # filled +# cv2.putText(img, label, (c1[0] + lw, c1[1] - (lh - t_size[1]) // 2), 0, fontScale, [225, 255, 255], thickness=tf, +# lineType=cv2.LINE_AA) +# # print('#####line224 fontScale:',fontScale,' thickness:',tf,' line_thickness:',font['line_thickness'],' boxLine thickness:',box_tl) +# return img + + +def img_pad(img, size, pad_value=[114, 114, 114]): + ###填充成固定尺寸 + H, W, _ = img.shape + r = max(H / size[0], W / size[1]) + img_r = cv2.resize(img, (int(W / r), int(H / r))) + tb = size[0] - img_r.shape[0] + lr = size[1] - img_r.shape[1] + top = int(tb / 2) + bottom = tb - top + left = int(lr / 2) + right = lr - left + pad_image = cv2.copyMakeBorder(img_r, top, bottom, left, right, cv2.BORDER_CONSTANT, value=pad_value) + return pad_image, (top, left, r) + + +def letterbox(img, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True, stride=32): + # 调整图像大小和填充图像,同时满足步幅多重约束 + shape = img.shape[:2] # current shape [height, width] 当前形状 [高度、宽度] + if isinstance(new_shape, int): + new_shape = (new_shape, new_shape) + + # Scale ratio (new / old) 缩放比例(新/旧) + r = min(new_shape[0] / shape[0], new_shape[1] / shape[1]) + if not scaleup: # 仅缩减,不纵向扩展(为了更好的测试 mAP) + r = min(r, 1.0) + + ratio = r, r # width, height ratios 宽度、高度比 + new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) + dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding + if auto: # 最小矩形 + dw, dh = np.mod(dw, stride), np.mod(dh, stride) # wh padding + elif scaleFill: # stretch + dw, dh = 0.0, 0.0 + new_unpad = (new_shape[1], new_shape[0]) + ratio = new_shape[1] / shape[1], new_shape[0] / shape[0] # width, height ratios + + dw /= 2 # divide padding into 2 sides + dh /= 2 + + if shape[::-1] != new_unpad: # resize + img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR) + top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) + left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) + img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # add border + return img, ratio, (dw, dh) + +# if __name__ == '__main__': +# # img = cv2.imread("../test/a.jpg", -1) +# # fontcolor = 'yellow' +# # +# # water = TextWaterMark() +# # text = "hello world" +# # +# # # fill_img = water.common_water(img, text, position=4, fontface='../font/庞门正道标题体2.0增强版.ttf', fontsize=20, fontcolor='black') +# # fill_img = water.fill_water(img, text, 20) +# # # 一定要保存为png格式 +# # cv2.imshow('result', fill_img) +# # cv2.waitKey(111111110) +# # print('finish') +# pic = PictureWaterMark() +# image = cv2.imread("a.jpg") +# logo = cv2.imread("../image/logo.png", -1) +# # print(image, logo) +# start = time.time() +# frame = pic.common_water(image, logo) +# print(time.time() - start) +# start1 = time.time() +# frame1 = pic.common_water_1(image, logo) +# # cv2.imwrite("watermarked.jpg", frame1) +# print(time.time() - start1) +# # cap = cv2.VideoCapture("../data/111111.mp4") +# # logo = cv2.imread("../image/logo.png", -1) +# # while True: +# # is_opened, frame = cap.read() +# # frame = pic.common_water(frame, logo) +# # cv2.imshow('frame', frame) +# # cv2.waitKey(1) # 等待输入任何按键 +# # # 关闭 +# # cap.release() diff --git a/util/ImgBaiduSdk.py b/util/ImgBaiduSdk.py new file mode 100644 index 0000000..6ebf0a2 --- /dev/null +++ b/util/ImgBaiduSdk.py @@ -0,0 +1,295 @@ +# -*- coding: utf-8 -*- +import time +import traceback +from os.path import join + +from aip import AipImageClassify, AipBodyAnalysis +from loguru import logger + +from common.YmlConstant import baidu_yml_path +from enums.BaiduSdkEnum import BAIDUERRORDATA +from enums.ExceptionEnum import ExceptionType +from exception.CustomerException import ServiceException +from util.ImageUtils import url2Content +from util.RWUtils import getConfigs + + +class AipImageClassifyClient: + + __slots__ = ('__client', '__config') + + def __init__(self, base_dir, env): + self.__client = None + self.__config = getConfigs(join(base_dir, baidu_yml_path % env)) + self.init_client() + # self.lock = Lock() + + def init_client(self): + if self.__client is None: + self.__client = AipImageClassify(str(self.__config["vehicle"]["APP_ID"]), + self.__config["vehicle"]["API_KEY"], + self.__config["vehicle"]["SECRET_KEY"]) + + ''' + 车辆检测 + ''' + + def vehicleDetectUrl(self, url, request_id, options={}): + self.init_client() + # try: + # self.lock.acquire() + reply_num = 0 + reply_value = None + while True: + try: + options["show"] = "true" + res_image = self.__client.vehicleDetectUrl(url, options) + error_code = res_image.get("error_code") + if error_code: + enum = BAIDUERRORDATA.get(error_code) + # 如果异常编码未知, 返回空值 + if enum is None: + logger.error("百度云车辆检测异常!error_code:{}, request_id: {}", error_code, request_id) + return None + # 重试指定次数后,还是异常,输出统一内部异常 + if enum.value[3] == 0: + if reply_value is None: + reply_value = enum.value[4] + logger.error("百度云车辆检测异常!error_code:{}, error_msg:{}, reply_num:{}, request_id: {}", + enum.value[0], enum.value[2], reply_num, request_id) + raise Exception() + # 重试指定次数后,还是异常,输出对应的异常 + if enum.value[3] == 1: + if reply_value is None: + reply_value = enum.value[4] + raise ServiceException(str(enum.value[0]), enum.value[2]) + # 重试指定次数后,还是异常,输出空 + if enum.value[3] == 2: + if reply_value is None: + reply_value = enum.value[4] + if reply_num >= reply_value: + return None + raise Exception() + return res_image + except Exception as e: + time.sleep(1) + reply_num += 1 + self.init_client() + if reply_num > reply_value: + if isinstance(e, ServiceException): + raise ServiceException(e.code, e.msg) + logger.error("车辆检测识别失败: {}, request_id: {}", traceback.format_exc(), request_id) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + # except Exception as ee: + # logger.exception("车辆检测加锁异常: {}, request_id: {}", ee, request_id) + # raise ServiceException(ExceptionType.UNIVERSAL_TEXT_RECOGNITION_FAILED.value[0], + # ExceptionType.UNIVERSAL_TEXT_RECOGNITION_FAILED.value[1]) + # finally: + # self.lock.release() + + ''' + 车辆检测 + ''' + + def vehicleDetect(self, iamge, request_id, options={}): + self.init_client() + # try: + # self.lock.acquire() + reply_num = 0 + reply_value = None + while True: + try: + options["show"] = "true" + res_image = self.__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:{}, request_id: {}", error_code, request_id) + return None + # 重试指定次数后,还是异常,输出统一内部异常 + if enum.value[3] == 0: + if reply_value is None: + reply_value = enum.value[4] + logger.error("百度云车辆检测异常!error_code:{}, error_msg:{}, reply_num:{}, request_id: {}", + enum.value[0], enum.value[2], reply_num, request_id) + raise Exception() + # 重试指定次数后,还是异常,输出对应的异常 + if enum.value[3] == 1: + if reply_value is None: + reply_value = enum.value[4] + raise ServiceException(str(enum.value[0]), enum.value[2]) + # 重试指定次数后,还是异常,输出空 + if enum.value[3] == 2: + if reply_value is None: + reply_value = enum.value[4] + if reply_num >= reply_value: + return None + raise Exception() + return res_image + except Exception as e: + time.sleep(1) + reply_num += 1 + self.init_client() + if reply_num > reply_value: + if isinstance(e, ServiceException): + raise ServiceException(e.code, e.msg) + logger.error("车辆检测识别失败: {}, request_id: {}", traceback.format_exc(), request_id) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + + +class AipBodyAnalysisClient: + + __slots__ = ('__config', '__client') + + def __init__(self, base_dir, env): + self.__client = None + self.__config = getConfigs(join(base_dir, baidu_yml_path % env)) + self.init_client() + # self.lock = Lock() + + def init_client(self): + if self.__client is None: + self.__client = AipBodyAnalysis(str(self.__config["person"]["APP_ID"]), self.__config["person"]["API_KEY"], + self.__config["person"]["SECRET_KEY"]) + + ''' + 人体检测与属性识别 + ''' + + def bodyAttr(self, url, request_id, options={}): + self.init_client() + image = self.readImage(url, request_id) + # try: + # self.lock.acquire() + reply_num = 0 + reply_value = None + while True: + try: + options["show"] = "true" + res_image = self.__client.bodyAttr(image, options) + error_code = res_image.get("error_code") + if error_code: + enum = BAIDUERRORDATA.get(error_code) + # 如果异常编码未知, 返回空值 + if enum is None: + logger.error("百度云人体检测与属性识别异常!error_code:{}, request_id: {}", error_code, request_id) + return None + # 重试指定次数后,还是异常,输出统一内部异常 + if enum.value[3] == 0: + if reply_value is None: + reply_value = enum.value[4] + logger.error("百度云人体检测与属性识别异常!error_code:{}, error_msg:{}, reply_num:{}, request_id: {}", + enum.value[0], enum.value[2], reply_num, request_id) + raise Exception() + # 重试指定次数后,还是异常,输出对应的异常 + if enum.value[3] == 1: + if reply_value is None: + reply_value = enum.value[4] + raise ServiceException(str(enum.value[0]), enum.value[2]) + # 重试指定次数后,还是异常,输出空 + if enum.value[3] == 2: + if reply_value is None: + reply_value = enum.value[4] + if reply_num >= reply_value: + return None + raise Exception() + return res_image + except Exception as e: + time.sleep(0.5) + reply_num += 1 + self.init_client() + if reply_num > reply_value: + if isinstance(e, ServiceException): + raise ServiceException(e.code, e.msg) + logger.error("人体检测与属性识别失败: {}, request_id: {}", traceback.format_exc(), request_id) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + # except Exception as ee: + # logger.exception("车辆检测加锁异常: {}, request_id: {}", ee, request_id) + # raise ServiceException(ExceptionType.UNIVERSAL_TEXT_RECOGNITION_FAILED.value[0], + # ExceptionType.UNIVERSAL_TEXT_RECOGNITION_FAILED.value[1]) + # finally: + # self.lock.release() + + ''' + 人流量统计 + ''' + + def bodyNum(self, url, request_id, options={}): + self.init_client() + image = self.readImage(url, request_id) + # try: + # self.lock.acquire() + reply_num = 0 + reply_value = None + while True: + try: + options["show"] = "true" + res_image = self.__client.bodyNum(image, options) + error_code = res_image.get("error_code") + if error_code: + enum = BAIDUERRORDATA.get(error_code) + # 如果异常编码未知, 返回空值 + if enum is None: + logger.error("百度云人流量统计异常!error_code:{}, request_id: {}", error_code, request_id) + return None + # 重试指定次数后,还是异常,输出统一内部异常 + if enum.value[3] == 0: + if reply_value is None: + reply_value = enum.value[4] + logger.error("百度云人流量统计异常!error_code:{}, error_msg:{}, reply_num:{}, request_id: {}", + enum.value[0], enum.value[2], reply_num, request_id) + raise Exception() + # 重试指定次数后,还是异常,输出对应的异常 + if enum.value[3] == 1: + if reply_value is None: + reply_value = enum.value[4] + raise ServiceException(str(enum.value[0]), enum.value[2]) + # 重试指定次数后,还是异常,输出空 + if enum.value[3] == 2: + if reply_value is None: + reply_value = enum.value[4] + if reply_num >= reply_value: + return None + raise Exception() + return res_image + except Exception as e: + time.sleep(0.5) + reply_num += 1 + self.init_client() + if reply_num > reply_value: + if isinstance(e, ServiceException): + raise ServiceException(e.code, e.msg) + logger.exception("人流量统计失败: {}, request_id: {}", traceback.format_exc(), request_id) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + # except Exception as ee: + # logger.exception("车辆检测加锁异常: {}, request_id: {}", ee, request_id) + # raise ServiceException(ExceptionType.UNIVERSAL_TEXT_RECOGNITION_FAILED.value[0], + # ExceptionType.UNIVERSAL_TEXT_RECOGNITION_FAILED.value[1]) + # finally: + # self.lock.release() + + def readImage(self, url, request_id): + try: + return url2Content(url) + except Exception as e: + logger.error("读取图片异常!url: {}, request_id: {}, 异常信息:{}", url, request_id, traceback.format_exc()) + raise ServiceException(ExceptionType.READ_IAMGE_URL_EXCEPTION.value[0], + ExceptionType.READ_IAMGE_URL_EXCEPTION.value[1]) + +# if __name__ == '__main__': +# with open(r"D:\work\alg_new\tuoheng_alg\dsp_dev_service.yml", "r", encoding='utf-8') as f: +# file_content = f.read() +# content = yaml.load(file_content, yaml.FullLoader) +# aipImageClassifyClient = AipImageClassifyClient(content) +# aipBodyAnalysisClient = AipBodyAnalysisClient(content) +# url = "https://pic.52112.com/180623/JPG-180623-12/c4cyivkxEh_small.jpg" +# # result = aipImageClassifyClient.vehicleDetectUrl(url, "1111111") +# result = aipBodyAnalysisClient.bodyNum(url, "1111111") +# iamge = base64.b64decode(result.get("image")) +# print(iamge) diff --git a/util/KafkaUtils.py b/util/KafkaUtils.py new file mode 100644 index 0000000..b8e83c7 --- /dev/null +++ b/util/KafkaUtils.py @@ -0,0 +1,167 @@ +# -*- coding: utf-8 -*- +import time +from json import dumps, loads +from traceback import format_exc + +from kafka import KafkaProducer, KafkaConsumer, TopicPartition, OffsetAndMetadata +from loguru import logger + + +# 生产者 +class CustomerKafkaProducer: + __slots__ = ( + '__configs', + 'customerProducer', + '__bootstrap_servers' + ) + + def __init__(self, kafka_config): + self.__configs = kafka_config["producer"] + self.__bootstrap_servers = kafka_config["bootstrap_servers"] + self.customerProducer = None + self.get_producer() + + # 获取kafka生产者 + def get_producer(self): + if self.customerProducer is None: + logger.info("配置kafka生产者!") + self.customerProducer = KafkaProducer( + bootstrap_servers=self.__bootstrap_servers, + acks=self.__configs["acks"], + retries=self.__configs["retries"], + linger_ms=self.__configs["linger_ms"], + retry_backoff_ms=self.__configs["retry_backoff_ms"], + max_in_flight_requests_per_connection=self.__configs["max_in_flight_requests_per_connection"], + key_serializer=lambda m: dumps(m).encode("utf-8"), + value_serializer=lambda m: dumps(m).encode("utf-8")) + + # mode 模式1:异步发送 2:同步发送 + # def on_send_success(record_metadata): 成功回调 + # def on_send_error(exc): 失败回调 + def sender(self, topic, key, message, mode=1, customer_send_success=None, customer_send_error=None): + retry_send_num = 0 + while True: + try: + self.get_producer() + logger.info("kafka发送信息,topic:{}|key:{}|message:{}|mode:{}|requestId:{}", topic, key, message, mode, + message.get("request_id")) + if mode == 1: + if not customer_send_success: + customer_send_success = CustomerKafkaProducer.on_send_success + if not customer_send_error: + customer_send_error = CustomerKafkaProducer.on_send_error + self.customerProducer.send(topic=topic, key=key, value=message) \ + .add_callback(customer_send_success, message.get("request_id")) \ + .add_errback(customer_send_error, message.get("request_id")) + if mode == 2: + try: + self.customerProducer.send(topic=topic, key=key, value=message).get(timeout=30) + logger.info("kafka同步发送信息成功, requestId:{}", message.get("request_id")) + except Exception as ke: + logger.error("kafka同步发送消息异常: {}, requestId:{}", format_exc(), + message.get("request_id")) + raise ke + break + except Exception as e: + retry_send_num += 1 + logger.error("kafka发送消息异常, 开始重试, 当前重试次数:{} requestId:{}", retry_send_num, + message.get("request_id")) + time.sleep(1) + self.customerProducer = None + if retry_send_num > 3: + logger.error("kafka发送消息重试失败: {}, requestId:{}", format_exc(), + message.get("request_id")) + raise e + + def close_producer(self): + self.customerProducer.flush() + self.customerProducer.close() + logger.info("kafka生产者关闭完成!") + + @staticmethod + def on_send_success(requestId, record_metadata): + logger.info("kafka异步发送信息成功,topic:{}|partition:{}|offset:{}|requestId:{}", record_metadata.topic, + record_metadata.partition, record_metadata.offset, requestId) + + @staticmethod + def on_send_error(requestId, exc): + logger.exception("kafka异步发送消息异常: {}, requestId:{}", exc, requestId) + + +# 生产者 +class CustomerKafkaConsumer: + __slots__ = ('__configs', 'customerConsumer', '__bootstrap_servers', '__topics') + + def __init__(self, kafka_config, topics=()): + logger.info("初始化消费者") + self.__configs = kafka_config["consumer"] + self.__bootstrap_servers = kafka_config["bootstrap_servers"] + self.customerConsumer = None + self.__topics = topics + self.subscribe() + logger.info("初始化消费者完成") + + def subscribe(self): + if self.customerConsumer is None: + logger.info("获取消费者!") + self.customerConsumer = KafkaConsumer( + bootstrap_servers=self.__bootstrap_servers, + # client_id=self.__configs[KAFKA_CLIENT_ID], + group_id=self.__configs["group_id"], + auto_offset_reset=self.__configs["auto_offset_reset"], + enable_auto_commit=bool(self.__configs["enable_auto_commit"]), + max_poll_records=self.__configs["max_poll_records"], + value_deserializer=lambda m: loads(m.decode("utf-8"))) + logger.info("kafka生产者订阅topic:{}", self.__topics) + # if self.topics is None or len(self.topics) == 0: + # logger.error("消费者订阅topic不能为空!") + # raise Exception("消费者订阅topic不能为空!") + # # 手动配置分区 + # customer_partition = [] + # for topic in self.topics: + # for p in self.content["kafka"][self.content["dsp"]["active"]][topic]["partition"]: + # customer_partition.append(TopicPartition(topic, p)) + # self.customerConsumer.assign(customer_partition) + # 自动配置 + self.customerConsumer.subscribe(topics=self.__topics) + logger.info("kafka生产者订阅topic完成") + + def poll(self): + msg = None + try: + self.subscribe() + msg = self.customerConsumer.poll() + except Exception: + self.customerConsumer = None + logger.error("消费者拉取消息异常: {}", format_exc()) + return msg + + def commit_offset(self, message, request_id,log=True): + retry_num = 0 + topic = message.topic + offset = message.offset + 1 + partition = message.partition + while True: + try: + self.subscribe() + if log: logger.info("消费者开始提交offset,topic:{}|offset:{}|partition:{}|requestId:{}", topic, offset, partition, + request_id) + tp = TopicPartition(topic=topic, partition=partition) + self.customerConsumer.commit(offsets={tp: (OffsetAndMetadata(offset, None))}) + if log: logger.info("消费者提交offset完成,topic:{}|offset:{}|partition:{}|requestId:{}", topic, offset, partition, + request_id) + break + except Exception: + self.customerConsumer = None + if log: logger.error("消费者提交offset异常: {}, 重试次数: {}, requestId:{}", format_exc(), retry_num, request_id) + time.sleep(1) + retry_num += 1 + if retry_num > 3: + if log : logger.error("消费者提交offset重试失败: {}, requestId:{}", format_exc(), request_id) + break + +# if __name__=="__main__": +# try: +# 1/0 +# except Exception as e: +# logger.exception("aaaaa:{} {}", e, "11111") diff --git a/util/LocationUtils.py b/util/LocationUtils.py new file mode 100644 index 0000000..d63c473 --- /dev/null +++ b/util/LocationUtils.py @@ -0,0 +1,156 @@ + +import os,math +import numpy as np + +# WGS-84经纬度转Web墨卡托 +def wgs_to_mercator(x, y): + y = 85.0511287798 if y > 85.0511287798 else y + y = -85.0511287798 if y < -85.0511287798 else y + + x2 = x * 20037508.34 / 180.0 + y2 = math.log(math.tan((90.0 + y) * math.pi / 360.0)) / (math.pi / 180.0) + + #print( ' y:',y, " before Log:",math.tan((90.0 + y) * math.pi / 360.0), ' log:' , math.log(math.tan((90.0 + y) * math.pi / 360.0))) + y2 = y2 * 20037508.34 / 180.0 + return x2, y2 +def mercator_to_wgs(x, y): + """ + 将墨卡托投影坐标转换为WGS-84经纬度坐标 + :param x: 墨卡托投影的X坐标 + :param y: 墨卡托投影的Y坐标 + :return: 经度(longitude)和纬度(latitude) + """ + # 地球半径(米) + R = 6378137.0 + # 墨卡托投影的X坐标转换为经度 + lon = x / R * 180.0 / math.pi + # 墨卡托投影的Y坐标转换为纬度 + lat = math.atan(math.sinh(y / R)) * 180.0 / math.pi + return lon, lat + + +def ImageCorToCamCor(p0,w=1920,h=1080): + x,y=p0[0:2] + return x-w/2.,(h-y)-h/2. + +def wgs84_to_gcj02(lat, lon): + """将 WGS-84 坐标转换为 GCJ-02 坐标 (高德地图坐标)""" + A = 6378245.0 # 长半轴 + EE = 0.00669342162296594323 # 偏心率平方 + if out_of_china(lat, lon): + return lat, lon # 如果在中国以外,直接返回 WGS-84 坐标 + + # 坐标转换 + dlat = transform_lat(lon - 105.0, lat - 35.0) + dlon = transform_lon(lon - 105.0, lat - 35.0) + radlat = lat / 180.0 * math.pi + magic = math.sin(radlat) + magic = 1 - EE * magic * magic + sqrt_magic = math.sqrt(magic) + dlat = (dlat * 180.0) / (A * (1 - EE) / (magic * sqrt_magic) * math.pi) + dlon = (dlon * 180.0) / (A / sqrt_magic * math.cos(radlat) * math.pi) + + mg_lat = lat + dlat + mg_lon = lon + dlon + + return mg_lat, mg_lon + +def out_of_china(lat, lon): + """检查坐标是否在中国以外""" + return lon < 72.004 or lon > 137.8347 or lat < 0.8293 or lat > 55.8271 + +def transform_lat(lon, lat): + """辅助函数: 进行纬度转换""" + ret = (-100.0 + 2.0 * lon + 3.0 * lat + 0.2 * lat * lat + + 0.1 * lon * lat + 0.2 * math.sqrt(abs(lon))) + ret += (20.0 * math.sin(6.0 * lon * PI) + 20.0 * math.sin(2.0 * lon * PI)) * 2.0 / 3.0 + ret += (20.0 * math.sin(lat * PI) + 40.0 * math.sin(lat / 3.0 * PI)) * 2.0 / 3.0 + ret += (160.0 * math.sin(lat / 12.0 * PI) + 320.0 * math.sin(lat * PI / 30.0)) * 2.0 / 3.0 + return ret + +def transform_lon(lon, lat): + """辅助函数: 进行经度转换""" + ret = (300.0 + lon + 2.0 * lat + 0.1 * lon * lon + + 0.1 * lon * lat + 0.1 * math.sqrt(abs(lon))) + ret += (20.0 * math.sin(6.0 * lon * PI) + 20.0 * math.sin(2.0 * lon * PI)) * 2.0 / 3.0 + ret += (20.0 * math.sin(lon * PI) + 40.0 * math.sin(lon / 3.0 * PI)) * 2.0 / 3.0 + ret += (150.0 * math.sin(lon / 12.0 * PI) + 300.0 * math.sin(lon / 30.0 * PI)) * 2.0 / 3.0 + return ret + +def cam2word(p0,pUAV,yaw,delta=1.55e-3 * 4056.0/1920,pitch=-45,f=4.5,camH=50e3,igW=1920,igH=1080): + + pitch = pitch/180.0*np.pi + sinp = np.sin(pitch );cosp= np.cos(pitch) + p0_new = ImageCorToCamCor(p0,igW,igH) + Xc0 = p0_new[0]*delta;Zc0 = p0_new[1]*delta; + + #(Zw0,Xw0)--相对于光心,X,Z并未校正到正东和正北。 + #f=4.5*f/24.00 + Zw0=camH*( -f*sinp + Zc0*cosp )/( f*cosp + Zc0*sinp)*1e-3 + Xw0= camH*Xc0/(f*cosp + Zc0*sinp)*1e-3 + #print(' %4.0f %4.0f %4.8f %4.8f %4.8f %4.8f f:%.2f'%( p0[0],p0[1], Xc0, Zc0,Xw0,Zw0,f ) ) + #yaw定义为拍摄方向,即图片的高方位(Z方向)偏离正北的方向,北偏东为正。 + yaw_rad = yaw/180.0*np.pi + siny=np.sin(yaw_rad);cosy=np.cos(yaw_rad) + Zx0_rot = Xw0*cosy + Zw0*siny + pUAV[0] + Zw0_rot = -Xw0*siny + Zw0*cosy + pUAV[1] + + + return Zx0_rot,Zw0_rot + +def location( point,igW,igH,PlanWgs84,PlanH,yaw,delta,pitch,focal,outFormat='wgs84'): + ''' + 输入图像中点的X,Y坐标,及无人机相关信息、相机相关信息,输出该点的Wgs84经纬度坐标 + point--点在图像上的坐标,左上角为(0,0),X方向为宽度方向,Y方向为高度方向 + igW--图像的宽度 + igH--图像的高度 + PlanWgs84--无人机的Wgs84坐标,(lon,lat),(经度,纬度) + PlanH--无人机拍照时的相对高度,用mm表示 + yaw--云台的yaw + delta--单个像素的长度值,用mm表示。 + pitch--无人的pitch + focal--真实焦距,用mm表示 + ''' + PlanX,PlanY = wgs_to_mercator(PlanWgs84[0],PlanWgs84[1]) + #print('location:',PlanX,PlanY) + #PlanX,PlanY--东西、南北方向的墨卡托投影坐标 + #print( 'line268:',point,PlanX,PlanY,yaw, delta,pitch,focal,PlanH,igW,igH ) + cor_world = cam2word( point,(PlanX,PlanY),yaw, delta,pitch,focal,PlanH,igW,igH) + cor_world = mercator_to_wgs(cor_world[0], cor_world[1]) + if outFormat=='GCJ02' or outFormat=='gcj02': + cor_world = wgs84_to_gcj02(cor_world[0], cor_world[1]) + + return cor_world + +def locate_byMqtt(box,igW,igH,camParas,outFormat='wgs84'): + #camParas--{'lon': 3479.8250608, 'lat': 3566.7630802, 'gpssingal': 4, 'satcount': 6896, 'alt': 3.256, 'hspeed': 86.0, 'vspeed': 4.447911, 'ysingal': 0, 'tsingal': 0, 'voltage': 24.971, 'flytime': 0, 'datetime': 1739315683895, 'yaw': 70.243252, 'roll': -0.89436062, 'pitch': 0.89897547, 'armed': 'false', 'mode': 'stabilize', 'distToHome': 7.132033, 'deviceid': 'THJSQ03A2302KSPYGJ2G', 'mileage': '0', 'altasl': 21.26, 'altasl2': -20.74, 'landing_target_x': 0, 'landing_target_y': 0, 'landing_target_z': 0} + #模型输出的点的格式是-[(486, 264), (505, 264), (505, 290), (486, 290)] + + box_np = np.array(box); + point = int(np.mean( box_np[:,0] )) , int(np.mean( box_np[:,1] )) + PlanWgs84 = (float(camParas['lon']),float(camParas['lat'])) # + PlanH = float(camParas['alt'])# + yaw = float(camParas['camerayaw']) + #delta = camParas[''] + delta = 1.55e-3 * 4056.0/1920 + pitch = float(camParas['camerapitch']) + #focal = camParas[''] + focal = 3.5 + + out = location( point,igW,igH,PlanWgs84,PlanH,yaw,delta,pitch,focal,outFormat='wgs84') + return out + +if __name__=="__main__": + srt="videos/DJI_20221220133918_0001_W_0.SRT" + videoUrl = "videos/DJI_20221220133918_0001_W.MP4" + imgOut= "videos/imgs" + fpbeg=17273;fpend=17830 + nums = list(range(fpbeg,fpend,16)) + #generateNewSRT(srt) + #captureImages(videoUrl,nums,imgOut) + + process(videoUrl,srt,nums,imW=1920,imH=1080,txtDir='videos/labels' ) + #draw_results() + + #rotate_example() + #rotate_example3() \ No newline at end of file diff --git a/util/LogUtils.py b/util/LogUtils.py new file mode 100644 index 0000000..4aefeb6 --- /dev/null +++ b/util/LogUtils.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +import sys +from os import makedirs +from os.path import join, exists +from loguru import logger +from util.RWUtils import getConfigs + + +# 初始化日志配置 +def init_log(base_dir, env): + log_config = getConfigs(join(base_dir, 'config/logger/dsp_%s_logger.yml' % env)) + # 判断日志文件是否存在,不存在创建 + base_path = join(base_dir, log_config.get("base_path")) + if not exists(base_path): + makedirs(base_path) + # 移除日志设置 + logger.remove(handler_id=None) + # 打印日志到文件 + if bool(log_config.get("enable_file_log")): + logger.add(join(base_path, log_config.get("log_name")), + rotation=log_config.get("rotation"), + retention=log_config.get("retention"), + format=log_config.get("log_fmt"), + level=log_config.get("level"), + enqueue=True, + encoding=log_config.get("encoding")) + # 控制台输出 + if bool(log_config.get("enable_stderr")): + logger.add(sys.stderr, + format=log_config.get("log_fmt"), + level=log_config.get("level"), + enqueue=True) diff --git a/util/MinioSdk.py b/util/MinioSdk.py new file mode 100644 index 0000000..9cd17ff --- /dev/null +++ b/util/MinioSdk.py @@ -0,0 +1,121 @@ +# -*- coding: utf-8 -*- +from json import loads +from os.path import join,basename +from traceback import format_exc +import oss2 +import string,random,os +import time +from common.YmlConstant import minio_yml_path +from minio import Minio +from loguru import logger +from exception.CustomerException import ServiceException +from enums.ExceptionEnum import ExceptionType +from util.RWUtils import getConfigs +import filetype,cv2,io +import numpy as np + +class MinioSdk: + + __slots__ = ('minioClient', '__request_id', '__config') + + def __init__(self, *args): + base_dir, env, self.__request_id = args + self.minioClient = None + self.__config = getConfigs(join(base_dir, minio_yml_path % env)) + self.get_minioClient() + + def get_minioClient(self): + if self.minioClient is None: + self.minioClient = Minio( + endpoint=self.__config["endpoint"], + access_key=self.__config["access_key"], + secret_key=self.__config["secret_key"], + secure=self.__config["secure"] + ) + + def get_bucknetName_from_filename(self,localPath): + if isinstance(localPath,np.ndarray): + return self.__config["image_bucket"],'jpg' + ret = filetype.guess(localPath) + if 'video' in ret.mime: + return self.__config["video_bucket"],ret.mime + elif 'image' in ret.mime: + return self.__config["image_bucket"],ret.mime + else: + logger.warning("上传文件到格式不是图片,或者视频, requestId:{}", self.__request_id) + return self.__config["image_bucket"],'.oth' + def create_bucknet(self,bucketName): + if not self.minioClient.bucket_exists(bucketName): + self.minioClient.make_bucket(bucketName) + + def put_object(self, localPath, remotePath): + #localPath--本地文件路径,带有后缀---或者是字节流 + #remotePath--远程文件的名字,不带文件夹,不带后缀(为了与原OSS保持一致) + request_id = self.__request_id + logger.info("开始上传文件到oss, requestId:{}", request_id) + bucketName,mime = self.get_bucknetName_from_filename(localPath) + + self.create_bucknet(bucketName) + if '/' not in remotePath: + remoteUrl=join( self.__config["file_dir"] , request_id,remotePath ) + else: remoteUrl = join(self.__config["file_dir"] , remotePath) + max_retries = 3 + retry_count = 0 + while True: + try: + self.get_minioClient() + + if isinstance(localPath,np.ndarray): + image_bytes = io.BytesIO(localPath) + #image_bytes = localPath.tobytes() + # 上传图片数据流 + ret = self.minioClient.put_object(bucketName, remoteUrl,image_bytes, len(localPath)) + else: + if 'video' in mime:# + newLocalpath = os.path.join( os.path.dirname(localPath), ''.join(random.sample(string.ascii_letters ,32))+'.mp4' ) + cmd1 = 'ffmpeg -i %s -vcodec libx264 -acodec copy %s'%(localPath, newLocalpath ) + os.system(cmd1 ) + cmd2 = 'mv %s %s'%(newLocalpath,localPath ) + os.system(cmd2 ) + ret = self.minioClient.fput_object(bucketName, remoteUrl,localPath,content_type=mime) + #print('-----line72: mime:',mime) + + #outurl='http://'+self.__config["endpoint"]+'/'+bucketName+'/'+remoteUrl + outurl=self.__config["domain"]+'/'+bucketName+'/'+remoteUrl + logger.info("上传文件到minio成功! requestId:{},bucketName:{},objectName:{},remoteUrl:{}", request_id,ret.bucket_name,ret.object_name,outurl) + return outurl + except Exception as e: + retry_count += 1 + time.sleep(1) + self.minioClient = None + logger.info("上传文件到minio失败, 重试次数:{}, requestId:{}", retry_count, request_id) + if retry_count > max_retries: + logger.error("上传文件到oss重试失败:{}, requestId:{}", format_exc(), request_id) + raise e + +if __name__ == "__main__": + + base_dir, env, request_id = '/home/th/WJ/test/tuoheng_alg','test','1122334455667788' + #localPath = '/home/th/WJ/data/XunHe/ai_online.mp4' + localPath = '/home/th/WJ/data/XunHe/ai_online_avc1.mp4' + #localPath = '/home/th/WJ/DSP2/AIdemo2/images/cityRoad/DJI_0019_142.jpg' + + + remotePath='or.mp4' + minioSdk = MinioSdk(base_dir, env, request_id ) + + ##上传cv2编码后的图像np数组 + #image_array = cv2.imread( localPath ) + #_, localPath = cv2.imencode('.jpg', image_array) + + + minioSdk.put_object(localPath, remotePath) + + + + #http://minio.t-aaron.com:9000/image/1122334455667788/or_.oth + + #http://minio.t-aaron.com:9000/image/messageId/t2.jpg + #messageId/t2.jpg' + + # print(aa.get_play_info('6928821035b171ee9f3b6632b68f0102')) diff --git a/util/ModelUtils.py b/util/ModelUtils.py new file mode 100644 index 0000000..26c7086 --- /dev/null +++ b/util/ModelUtils.py @@ -0,0 +1,644 @@ +# -*- coding: utf-8 -*- +import sys +from pickle import dumps, loads +from traceback import format_exc +import time + +import cv2 +from loguru import logger + +from common.Constant import COLOR +from enums.BaiduSdkEnum import VehicleEnum +from enums.ExceptionEnum import ExceptionType +from enums.ModelTypeEnum import ModelType, BAIDU_MODEL_TARGET_CONFIG +from exception.CustomerException import ServiceException +from util.ImgBaiduSdk import AipBodyAnalysisClient, AipImageClassifyClient +from util.PlotsUtils import get_label_arrays, get_label_array_dict +from util.TorchUtils import select_device + +sys.path.extend(['..', '../AIlib2']) +from AI import AI_process, AI_process_forest, get_postProcess_para, ocr_process, AI_process_N, AI_process_C +from stdc import stdcModel +from segutils.segmodel import SegModel +from models.experimental import attempt_load +from obbUtils.shipUtils import OBB_infer +from obbUtils.load_obb_model import load_model_decoder_OBB +import torch +import tensorrt as trt +from utilsK.jkmUtils import pre_process, post_process, get_return_data +from DMPR import DMPRModel +FONT_PATH = "../AIlib2/conf/platech.ttf" + + +# 河道模型、河道检测模型、交通模型、人员落水模型、城市违章公共模型 +class OneModel: + __slots__ = "model_conf" + + def __init__(self, device, allowedList=None, requestId=None, modeType=None, gpu_name=None, base_dir=None, env=None): + try: + logger.info("########################加载{}########################, requestId:{}", modeType.value[2], + requestId) + par = modeType.value[4](str(device), gpu_name) + mode, postPar, segPar = par.get('mode', 'others'), par.get('postPar'), par.get('segPar') + names = par['labelnames'] + postFile = par['postFile'] + rainbows = postFile["rainbows"] + new_device = select_device(par.get('device')) + half = new_device.type != 'cpu' + Detweights = par['Detweights'] + with open(Detweights, "rb") as f, trt.Runtime(trt.Logger(trt.Logger.ERROR)) as runtime: + model = runtime.deserialize_cuda_engine(f.read()) + par['segPar']['seg_nclass'] = par['seg_nclass'] + Segweights = par['Segweights'] + if Segweights: + if modeType.value[3] == 'cityMangement3': + segmodel = DMPRModel(weights=Segweights, par=par['segPar']) + else: + segmodel = stdcModel(weights=Segweights, par=par['segPar']) + else: + segmodel = None + objectPar = { + 'half': half, + 'device': new_device, + 'conf_thres': postFile["conf_thres"], + 'ovlap_thres_crossCategory': postFile.get("ovlap_thres_crossCategory"), + 'iou_thres': postFile["iou_thres"], + 'allowedList': [], + 'segRegionCnt': par['segRegionCnt'], + 'trtFlag_det': par['trtFlag_det'], + 'trtFlag_seg': par['trtFlag_seg'] + } + model_param = { + "model": model, + "segmodel": segmodel, + "objectPar": objectPar, + "segPar": segPar, + "mode": mode, + "postPar": postPar + } + self.model_conf = (modeType, model_param, allowedList, names, rainbows) + except Exception: + logger.error("模型加载异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) + +class cityManagementModel: + __slots__ = "model_conf" + + def __init__(self, device, allowedList=None, requestId=None, modeType=None, gpu_name=None, base_dir=None, env=None): + try: + logger.info("########################加载{}########################, requestId:{}", modeType.value[2], + requestId) + par = modeType.value[4](str(device), gpu_name) + postProcess = par['postProcess'] + names = par['labelnames'] + postFile = par['postFile'] + rainbows = postFile["rainbows"] + modelList=[ modelPar['model'](weights=modelPar['weight'],par=modelPar['par']) for modelPar in par['models'] ] + model_param = { + "modelList": modelList, + "postProcess": postProcess, + } + self.model_conf = (modeType, model_param, allowedList, names, rainbows) + except Exception: + logger.error("模型加载异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) + +def detSeg_demo2(args): + model_conf, frame, request_id = args + modelList, postProcess = model_conf[1]['modelList'], model_conf[1]['postProcess'] + try: + result = [[ None, None, AI_process_N([frame], modelList, postProcess)[0] ] ] # 为了让返回值适配统一的接口而写的shi + return result + except ServiceException as s: + raise s + except Exception: + # self.num += 1 + # cv2.imwrite('/home/th/tuo_heng/dev/img%s.jpg' % str(self.num), frame) + logger.error("算法模型分析异常:{}, requestId:{}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + + +def model_process(args): + model_conf, frame, request_id = args + model_param, names, rainbows = model_conf[1], model_conf[3], model_conf[4] + # modeType, model_param, allowedList, names, rainbows = model_conf + # segmodel, names, label_arraylist, rainbows, objectPar, font, segPar, mode, postPar, requestId = args + # model_param['digitFont'] = digitFont + # model_param['label_arraylist'] = label_arraylist + # model_param['font_config'] = font_config + try: + return AI_process([frame], model_param['model'], model_param['segmodel'], names, model_param['label_arraylist'], + rainbows, objectPar=model_param['objectPar'], font=model_param['digitFont'], + segPar=loads(dumps(model_param['segPar'])), mode=model_param['mode'], + postPar=model_param['postPar']) + except ServiceException as s: + raise s + except Exception: + # self.num += 1 + # cv2.imwrite('/home/th/tuo_heng/dev/img%s.jpg' % str(self.num), frame) + logger.error("算法模型分析异常:{}, requestId:{}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + + +# 森林模型、车辆模型、行人模型、烟火模型、 钓鱼模型、航道模型、乡村模型、城管模型公共模型 +class TwoModel: + __slots__ = "model_conf" + + def __init__(self, device1, allowedList=None, requestId=None, modeType=None, gpu_name=None, base_dir=None, + env=None): + s = time.time() + try: + logger.info("########################加载{}########################, requestId:{}", modeType.value[2], + requestId) + par = modeType.value[4](str(device1), gpu_name) + device = select_device(par.get('device')) + names = par['labelnames'] + half = device.type != 'cpu' + Detweights = par['Detweights'] + with open(Detweights, "rb") as f, trt.Runtime(trt.Logger(trt.Logger.ERROR)) as runtime: + model = runtime.deserialize_cuda_engine(f.read()) + segmodel = None + postFile = par['postFile'] + conf_thres = postFile["conf_thres"] + iou_thres = postFile["iou_thres"] + rainbows = postFile["rainbows"] + otc = postFile.get("ovlap_thres_crossCategory") + model_param = { + "model": model, + "segmodel": segmodel, + "half": half, + "device": device, + "conf_thres": conf_thres, + "iou_thres": iou_thres, + "trtFlag_det": par['trtFlag_det'], + "otc": otc + } + self.model_conf = (modeType, model_param, allowedList, names, rainbows) + except Exception: + logger.error("模型加载异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) + logger.info("模型初始化时间:{}, requestId:{}", time.time() - s, requestId) + + +def forest_process(args): + model_conf, frame, request_id = args + model_param, names, rainbows = model_conf[1], model_conf[3], model_conf[4] + try: + return AI_process_forest([frame], model_param['model'], model_param['segmodel'], names, + model_param['label_arraylist'], rainbows, model_param['half'], model_param['device'], + model_param['conf_thres'], model_param['iou_thres'], [], font=model_param['digitFont'], + trtFlag_det=model_param['trtFlag_det'], SecNms=model_param['otc']) + except ServiceException as s: + raise s + except Exception: + # self.num += 1 + # cv2.imwrite('/home/th/tuo_heng/dev/img%s.jpg' % str(self.num), frame) + logger.error("算法模型分析异常:{}, requestId:{}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + +class MultiModel: + __slots__ = "model_conf" + + def __init__(self, device1, allowedList=None, requestId=None, modeType=None, gpu_name=None, base_dir=None, + env=None): + s = time.time() + try: + logger.info("########################加载{}########################, requestId:{}", modeType.value[2], + requestId) + par = modeType.value[4](str(device1), gpu_name) + postProcess = par['postProcess'] + names = par['labelnames'] + postFile = par['postFile'] + rainbows = postFile["rainbows"] + modelList=[ modelPar['model'](weights=modelPar['weight'],par=modelPar['par']) for modelPar in par['models'] ] + model_param = { + "modelList": modelList, + "postProcess": postProcess, + } + self.model_conf = (modeType, model_param, allowedList, names, rainbows) + except Exception: + logger.error("模型加载异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) + logger.info("模型初始化时间:{}, requestId:{}", time.time() - s, requestId) + +def channel2_process(args): + model_conf, frame, request_id = args + modelList, postProcess = model_conf[1]['modelList'], model_conf[1]['postProcess'] + try: + start = time.time() + result = [[None, None, AI_process_C([frame], modelList, postProcess)[0]]] # 为了让返回值适配统一的接口而写的shi + # print("AI_process_C use time = {}".format(time.time()-start)) + return result + except ServiceException as s: + raise s + except Exception: + logger.error("算法模型分析异常:{}, requestId:{}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + +def get_label_arraylist(*args): + width, height, names, rainbows = args + # line = int(round(0.002 * (height + width) / 2) + 1) + line = max(1, int(round(width / 1920 * 3))) + label = ' 0.95' + tf = max(line - 1, 1) + fontScale = line * 0.33 + text_width, text_height = cv2.getTextSize(label, 0, fontScale=fontScale, thickness=tf)[0] + # fontsize = int(width / 1920 * 40) + numFontSize = float(format(width / 1920 * 1.1, '.1f')) + digitFont = {'line_thickness': line, + 'boxLine_thickness': line, + 'fontSize': numFontSize, + 'waterLineColor': (0, 255, 255), + 'segLineShow': False, + 'waterLineWidth': line, + 'wordSize': text_height, + 'label_location': 'leftTop'} + label_arraylist = get_label_arrays(names, rainbows, fontSize=text_height, fontPath=FONT_PATH) + return digitFont, label_arraylist, (line, text_width, text_height, fontScale, tf) + + +# 船只模型 +class ShipModel: + __slots__ = "model_conf" + + def __init__(self, device1, allowedList=None, requestId=None, modeType=None, gpu_name=None, base_dir=None, + env=None): + s = time.time() + try: + logger.info("########################加载{}########################, requestId:{}", modeType.value[2], + requestId) + par = modeType.value[4](str(device1), gpu_name) + model, decoder2 = load_model_decoder_OBB(par) + par['decoder'] = decoder2 + names = par['labelnames'] + rainbows = par['postFile']["rainbows"] + model_param = { + "model": model, + "par": par + } + self.model_conf = (modeType, model_param, allowedList, names, rainbows) + except Exception: + logger.exception("模型加载异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) + logger.info("模型初始化时间:{}, requestId:{}", time.time() - s, requestId) + + +def obb_process(args): + model_conf, frame, request_id = args + model_param = model_conf[1] + # font_config, frame, names, label_arrays, rainbows, model, par, requestId = args + try: + return OBB_infer(model_param["model"], frame, model_param["par"]) + except ServiceException as s: + raise s + except Exception: + # self.num += 1 + # cv2.imwrite('/home/th/tuo_heng/dev/img%s.jpg' % str(self.num), frame) + logger.error("算法模型分析异常:{}, requestId:{}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + + +# 车牌分割模型、健康码、行程码分割模型 +class IMModel: + __slots__ = "model_conf" + + def __init__(self, device, allowedList=None, requestId=None, modeType=None, gpu_name=None, base_dir=None, + env=None): + try: + logger.info("########################加载{}########################, requestId:{}", modeType.value[2], + requestId) + img_type = 'code' + if ModelType.PLATE_MODEL == modeType: + img_type = 'plate' + par = { + 'code': {'weights': '../AIlib2/weights/conf/jkm/health_yolov5s_v3.jit', 'img_type': 'code', 'nc': 10}, + 'plate': {'weights': '../AIlib2/weights/conf/jkm/plate_yolov5s_v3.jit', 'img_type': 'plate', 'nc': 1}, + 'conf_thres': 0.4, + 'iou_thres': 0.45, + 'device': 'cuda:%s' % device, + 'plate_dilate': (0.5, 0.3) + } + + new_device = torch.device(par['device']) + model = torch.jit.load(par[img_type]['weights']) + logger.info("########################加载 ../AIlib2/weights/conf/jkm/plate_yolov5s_v3.jit 成功 ########################, requestId:{}", + requestId) + self.model_conf = (modeType, allowedList, new_device, model, par, img_type) + except Exception: + logger.error("模型加载异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) + + +def im_process(args): + frame, device, model, par, img_type, requestId = args + try: + img, padInfos = pre_process(frame, device) + pred = model(img) + boxes = post_process(pred, padInfos, device, conf_thres=par['conf_thres'], + iou_thres=par['iou_thres'], nc=par[img_type]['nc']) # 后处理 + dataBack = get_return_data(frame, boxes, modelType=img_type, plate_dilate=par['plate_dilate']) + print('-------line351----:',dataBack) + return dataBack + except ServiceException as s: + raise s + except Exception: + logger.error("算法模型分析异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + + +# 百度AI图片识别模型 +class BaiduAiImageModel: + __slots__ = "model_conf" + + def __init__(self, device=None, allowedList=None, requestId=None, modeType=None, gpu_name=None, base_dir=None, + env=None): + try: + logger.info("########################加载{}########################, requestId:{}", modeType.value[2], + requestId) + # 人体检测与属性识别、 人流量统计客户端 + aipBodyAnalysisClient = AipBodyAnalysisClient(base_dir, env) + # 车辆检测检测客户端 + aipImageClassifyClient = AipImageClassifyClient(base_dir, env) + rainbows = COLOR + vehicle_names = [VehicleEnum.CAR.value[1], VehicleEnum.TRICYCLE.value[1], VehicleEnum.MOTORBIKE.value[1], + VehicleEnum.CARPLATE.value[1], VehicleEnum.TRUCK.value[1], VehicleEnum.BUS.value[1]] + person_names = ['人'] + self.model_conf = (modeType, aipImageClassifyClient, aipBodyAnalysisClient, allowedList, rainbows, + vehicle_names, person_names, requestId) + except Exception: + logger.exception("模型加载异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) + + +def get_baidu_label_arraylist(*args): + width, height, vehicle_names, person_names, rainbows = args + # line = int(round(0.002 * (height + width) / 2) + 1) + line = max(1, int(round(width / 1920 * 3) + 1)) + label = ' 0.97' + tf = max(line, 1) + fontScale = line * 0.33 + text_width, text_height = cv2.getTextSize(label, 0, fontScale=fontScale, thickness=tf)[0] + vehicle_label_arrays = get_label_arrays(vehicle_names, rainbows, fontSize=text_height, fontPath=FONT_PATH) + person_label_arrays = get_label_arrays(person_names, rainbows, fontSize=text_height, fontPath=FONT_PATH) + font_config = (line, text_width, text_height, fontScale, tf) + return vehicle_label_arrays, person_label_arrays, font_config + + +def baidu_process(args): + target, url, aipImageClassifyClient, aipBodyAnalysisClient, request_id = args + try: + # [target, url, aipImageClassifyClient, aipBodyAnalysisClient, requestId] + baiduEnum = BAIDU_MODEL_TARGET_CONFIG.get(target) + if baiduEnum is None: + raise ServiceException(ExceptionType.DETECTION_TARGET_TYPES_ARE_NOT_SUPPORTED.value[0], + ExceptionType.DETECTION_TARGET_TYPES_ARE_NOT_SUPPORTED.value[1] + + " target: " + target) + return baiduEnum.value[2](aipImageClassifyClient, aipBodyAnalysisClient, url, request_id) + except ServiceException as s: + raise s + except Exception: + logger.error("算法模型分析异常:{}, requestId:{}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + + +def one_label(width, height, model_conf): + # modeType, model_param, allowedList, names, rainbows = model_conf + names = model_conf[3] + rainbows = model_conf[4] + model_param = model_conf[1] + digitFont, label_arraylist, font_config = get_label_arraylist(width, height, names, rainbows) + model_param['digitFont'] = digitFont + model_param['label_arraylist'] = label_arraylist + model_param['font_config'] = font_config + +def dynamics_label(width, height, model_conf): + # modeType, model_param, allowedList, names, rainbows = model_conf + names = model_conf[3] + rainbows = model_conf[4] + model_param = model_conf[1] + digitFont, label_arraylist, font_config = get_label_arraylist(width, height, names, rainbows) + line = max(1, int(round(width / 1920 * 3))) + label = ' 0.95' + tf = max(line - 1, 1) + fontScale = line * 0.33 + _, text_height = cv2.getTextSize(label, 0, fontScale=fontScale, thickness=tf)[0] + label_dict = get_label_array_dict(rainbows, fontSize=text_height, fontPath=FONT_PATH) + model_param['digitFont'] = digitFont + model_param['label_arraylist'] = label_arraylist + model_param['font_config'] = font_config + model_param['label_dict'] = label_dict +def baidu_label(width, height, model_conf): + # modeType, aipImageClassifyClient, aipBodyAnalysisClient, allowedList, rainbows, + # vehicle_names, person_names, requestId + vehicle_names = model_conf[5] + person_names = model_conf[6] + rainbows = model_conf[4] + vehicle_label_arrays, person_label_arrays, font_config = get_baidu_label_arraylist(width, height, vehicle_names, + person_names, rainbows) + return vehicle_label_arrays, person_label_arrays, font_config + + +MODEL_CONFIG = { + # 加载河道模型 + ModelType.WATER_SURFACE_MODEL.value[1]: ( + lambda x, y, r, t, z, h: OneModel(x, y, r, ModelType.WATER_SURFACE_MODEL, t, z, h), + ModelType.WATER_SURFACE_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 加载森林模型 + # ModelType.FOREST_FARM_MODEL.value[1]: ( + # lambda x, y, r, t, z, h: TwoModel(x, y, r, ModelType.FOREST_FARM_MODEL, t, z, h), + # ModelType.FOREST_FARM_MODEL, + # lambda x, y, z: one_label(x, y, z), + # lambda x: forest_process(x) + # ), + ModelType.FOREST_FARM_MODEL.value[1]: ( + lambda x, y, r, t, z, h: cityManagementModel(x, y, r, ModelType.FOREST_FARM_MODEL, t, z, h), + ModelType.FOREST_FARM_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: detSeg_demo2(x) + ), + + # 加载交通模型 + ModelType.TRAFFIC_FARM_MODEL.value[1]: ( + lambda x, y, r, t, z, h: OneModel(x, y, r, ModelType.TRAFFIC_FARM_MODEL, t, z, h), + ModelType.TRAFFIC_FARM_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 加载防疫模型 + ModelType.EPIDEMIC_PREVENTION_MODEL.value[1]: ( + lambda x, y, r, t, z, h: IMModel(x, y, r, ModelType.EPIDEMIC_PREVENTION_MODEL, t, z, h), + ModelType.EPIDEMIC_PREVENTION_MODEL, + None, + lambda x: im_process(x)), + # 加载车牌模型 + ModelType.PLATE_MODEL.value[1]: ( + lambda x, y, r, t, z, h: IMModel(x, y, r, ModelType.PLATE_MODEL, t, z, h), + ModelType.PLATE_MODEL, + None, + lambda x: im_process(x)), + # 加载车辆模型 + ModelType.VEHICLE_MODEL.value[1]: ( + lambda x, y, r, t, z, h: TwoModel(x, y, r, ModelType.VEHICLE_MODEL, t, z, h), + ModelType.VEHICLE_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: forest_process(x) + ), + # 加载行人模型 + ModelType.PEDESTRIAN_MODEL.value[1]: ( + lambda x, y, r, t, z, h: TwoModel(x, y, r, ModelType.PEDESTRIAN_MODEL, t, z, h), + ModelType.PEDESTRIAN_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: forest_process(x)), + # 加载烟火模型 + ModelType.SMOGFIRE_MODEL.value[1]: ( + lambda x, y, r, t, z, h: TwoModel(x, y, r, ModelType.SMOGFIRE_MODEL, t, z, h), + ModelType.SMOGFIRE_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: forest_process(x)), + # 加载钓鱼游泳模型 + ModelType.ANGLERSWIMMER_MODEL.value[1]: ( + lambda x, y, r, t, z, h: TwoModel(x, y, r, ModelType.ANGLERSWIMMER_MODEL, t, z, h), + ModelType.ANGLERSWIMMER_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: forest_process(x)), + # 加载乡村模型 + ModelType.COUNTRYROAD_MODEL.value[1]: ( + lambda x, y, r, t, z, h: TwoModel(x, y, r, ModelType.COUNTRYROAD_MODEL, t, z, h), + ModelType.COUNTRYROAD_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: forest_process(x)), + # 加载船只模型 + ModelType.SHIP_MODEL.value[1]: ( + lambda x, y, r, t, z, h: ShipModel(x, y, r, ModelType.SHIP_MODEL, t, z, h), + ModelType.SHIP_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: obb_process(x)), + # 百度AI图片识别模型 + ModelType.BAIDU_MODEL.value[1]: ( + lambda x, y, r, t, z, h: BaiduAiImageModel(x, y, r, ModelType.BAIDU_MODEL, t, z, h), + ModelType.BAIDU_MODEL, + lambda x, y, z: baidu_label(x, y, z), + lambda x: baidu_process(x)), + # 航道模型 + ModelType.CHANNEL_EMERGENCY_MODEL.value[1]: ( + lambda x, y, r, t, z, h: TwoModel(x, y, r, ModelType.CHANNEL_EMERGENCY_MODEL, t, z, h), + ModelType.CHANNEL_EMERGENCY_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: forest_process(x)), + # 河道检测模型 + ModelType.RIVER2_MODEL.value[1]: ( + lambda x, y, r, t, z, h: OneModel(x, y, r, ModelType.RIVER2_MODEL, t, z, h), + ModelType.RIVER2_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x)), + # 城管模型 + ModelType.CITY_MANGEMENT_MODEL.value[1]: ( + lambda x, y, r, t, z, h: cityManagementModel(x, y, r, ModelType.CITY_MANGEMENT_MODEL, t, z, h), + ModelType.CITY_MANGEMENT_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: detSeg_demo2(x) + ), + # 人员落水模型 + ModelType.DROWING_MODEL.value[1]: ( + lambda x, y, r, t, z, h: OneModel(x, y, r, ModelType.DROWING_MODEL, t, z, h), + ModelType.DROWING_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 城市违章模型 + ModelType.NOPARKING_MODEL.value[1]: ( + lambda x, y, r, t, z, h: OneModel(x, y, r, ModelType.NOPARKING_MODEL, t, z, h), + ModelType.NOPARKING_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 车辆违停模型 + ModelType.ILLPARKING_MODEL.value[1]: ( + lambda x, y, r, t, z, h: OneModel(x, y, r, ModelType.ILLPARKING_MODEL, t, z, h), + ModelType.ILLPARKING_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 城市公路模型 + ModelType.CITYROAD_MODEL.value[1]: ( + lambda x, y, r, t, z, h: TwoModel(x, y, r, ModelType.CITYROAD_MODEL, t, z, h), + ModelType.CITYROAD_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: forest_process(x)), + # 加载坑槽模型 + ModelType.POTHOLE_MODEL.value[1]: ( + lambda x, y, r, t, z, h: TwoModel(x, y, r, ModelType.POTHOLE_MODEL, t, z, h), + ModelType.POTHOLE_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: forest_process(x) + ), + # 加载船只综合检测模型 + ModelType.CHANNEL2_MODEL.value[1]: ( + lambda x, y, r, t, z, h: MultiModel(x, y, r, ModelType.CHANNEL2_MODEL, t, z, h), + ModelType.CHANNEL2_MODEL, + lambda x, y, z: dynamics_label(x, y, z), + lambda x: channel2_process(x) + ), + # 河道检测模型 + ModelType.RIVERT_MODEL.value[1]: ( + lambda x, y, r, t, z, h: OneModel(x, y, r, ModelType.RIVERT_MODEL, t, z, h), + ModelType.RIVERT_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x)), + # 加载森林人群模型 + ModelType.FORESTCROWD_FARM_MODEL.value[1]: ( + lambda x, y, r, t, z, h: cityManagementModel(x, y, r, ModelType.FORESTCROWD_FARM_MODEL, t, z, h), + ModelType.FORESTCROWD_FARM_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: detSeg_demo2(x) + ), + # 加载交通模型 + ModelType.TRAFFICFORDSJ_FARM_MODEL.value[1]: ( + lambda x, y, r, t, z, h: OneModel(x, y, r, ModelType.TRAFFIC_FARM_MODEL, t, z, h), + ModelType.TRAFFIC_FARM_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 加载智慧工地模型 + ModelType.SMARTSITE_MODEL.value[1]: ( + lambda x, y, r, t, z, h: cityManagementModel(x, y, r, ModelType.SMARTSITE_MODEL, t, z, h), + ModelType.SMARTSITE_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: detSeg_demo2(x) + ), + + # 加载垃圾模型 + ModelType.RUBBISH_MODEL.value[1]: ( + lambda x, y, r, t, z, h: cityManagementModel(x, y, r, ModelType.RUBBISH_MODEL, t, z, h), + ModelType.RUBBISH_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: detSeg_demo2(x) + ), + + # 加载烟花模型 + ModelType.FIREWORK_MODEL.value[1]: ( + lambda x, y, r, t, z, h: cityManagementModel(x, y, r, ModelType.FIREWORK_MODEL, t, z, h), + ModelType.FIREWORK_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: detSeg_demo2(x) + ), + + +} diff --git a/util/ModelUtils2.py b/util/ModelUtils2.py new file mode 100644 index 0000000..67efcbb --- /dev/null +++ b/util/ModelUtils2.py @@ -0,0 +1,442 @@ +# -*- coding: utf-8 -*- +import sys +from json import dumps, loads +from traceback import format_exc + +import cv2 +from loguru import logger + +from common.Constant import COLOR +from enums.BaiduSdkEnum import VehicleEnum +from enums.ExceptionEnum import ExceptionType +from enums.ModelTypeEnum2 import ModelType2, BAIDU_MODEL_TARGET_CONFIG2 +from exception.CustomerException import ServiceException +from util.ImgBaiduSdk import AipBodyAnalysisClient, AipImageClassifyClient +from util.PlotsUtils import get_label_arrays +from util.TorchUtils import select_device +import time +import torch +import tensorrt as trt + +sys.path.extend(['..', '../AIlib2']) +from AI import AI_process, get_postProcess_para, get_postProcess_para_dic, AI_det_track, AI_det_track_batch, AI_det_track_batch_N +from stdc import stdcModel +from utilsK.jkmUtils import pre_process, post_process, get_return_data +from obbUtils.shipUtils import OBB_infer, OBB_tracker, draw_obb, OBB_tracker_batch +from obbUtils.load_obb_model import load_model_decoder_OBB +from trackUtils.sort import Sort +from trackUtils.sort_obb import OBB_Sort +from DMPR import DMPRModel + +FONT_PATH = "../AIlib2/conf/platech.ttf" + + +class Model: + __slots__ = "model_conf" + + def __init__(self, device, allowedList=None, requestId=None, modeType=None, gpu_name=None, base_dir=None, env=None): + try: + logger.info("########################加载{}########################, requestId:{}", modeType.value[2], + requestId) + par = modeType.value[4](str(device), gpu_name) + trackPar = par['trackPar'] + names = par['labelnames'] + detPostPar = par['postFile'] + rainbows = detPostPar["rainbows"] + #第一步加载模型 + modelList=[ modelPar['model'](weights=modelPar['weight'],par=modelPar['par']) for modelPar in par['models'] ] + #第二步准备跟踪参数 + trackPar=par['trackPar'] + sort_tracker = Sort(max_age=trackPar['sort_max_age'], + min_hits=trackPar['sort_min_hits'], + iou_threshold=trackPar['sort_iou_thresh']) + postProcess = par['postProcess'] + model_param = { + "modelList": modelList, + "postProcess": postProcess, + "sort_tracker": sort_tracker, + "trackPar": trackPar, + } + self.model_conf = (modeType, model_param, allowedList, names, rainbows) + except Exception: + logger.error("模型加载异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) + +def get_label_arraylist(*args): + width, height, names, rainbows = args + # line = int(round(0.002 * (height + width) / 2) + 1) + line = max(1, int(round(width / 1920 * 3))) + tf = max(line, 1) + fontScale = line * 0.33 + text_width, text_height = cv2.getTextSize(' 0.95', 0, fontScale=fontScale, thickness=tf)[0] + label_arraylist = get_label_arrays(names, rainbows, fontSize=text_height, fontPath=FONT_PATH) + return label_arraylist, (line, text_width, text_height, fontScale, tf) + + +""" +输入: + imgarray_list--图像列表 + iframe_list -- 帧号列表 + modelPar--模型参数,字典,modelPar={'det_Model':,'seg_Model':} + processPar--字典,存放检测相关参数,'half', 'device', 'conf_thres', 'iou_thres','trtFlag_det' + sort_tracker--对象,初始化的跟踪对象。为了保持一致,即使是单帧也要有。 + trackPar--跟踪参数,关键字包括:det_cnt,windowsize + segPar--None,分割模型相关参数。如果用不到,则为None +输入:retResults,timeInfos + retResults:list + retResults[0]--imgarray_list + retResults[1]--所有结果用numpy格式,所有的检测结果,包括8类,每列分别是x1, y1, x2, y2, conf, detclass,iframe,trackId + retResults[2]--所有结果用list表示,其中每一个元素为一个list,表示每一帧的检测结果,每一个结果是由多个list构成,每个list表示一个框,格式为[ cls , x0 ,y0 ,x1 ,y1 ,conf,ifrmae,trackId ],如 retResults[2][j][k]表示第j帧的第k个框。 +""" + + +def model_process(args): + # (modeType, model_param, allowedList, names, rainbows) + imgarray_list, iframe_list, model_param, request_id = args + try: + return AI_det_track_batch_N(imgarray_list, iframe_list, + model_param['modelList'], + model_param['postProcess'], + model_param['sort_tracker'], + model_param['trackPar']) + except ServiceException as s: + raise s + except Exception: + # self.num += 1 + # cv2.imwrite('/home/th/tuo_heng/dev/img%s.jpg' % str(self.num), frame) + logger.error("算法模型分析异常: {}, requestId: {}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + + +# 船只模型 +class ShipModel: + __slots__ = "model_conf" + + def __init__(self, device, allowedList=None, requestId=None, modeType=None, gpu_name=None, base_dir=None, env=None): + s = time.time() + try: + logger.info("########################加载船只模型########################, requestId:{}", requestId) + par = modeType.value[4](str(device), gpu_name) + obbModelPar = par['obbModelPar'] + model, decoder2 = load_model_decoder_OBB(obbModelPar) + obbModelPar['decoder'] = decoder2 + names = par['labelnames'] + rainbows = par['postFile']["rainbows"] + trackPar = par['trackPar'] + sort_tracker = OBB_Sort(max_age=trackPar['sort_max_age'], min_hits=trackPar['sort_min_hits'], + iou_threshold=trackPar['sort_iou_thresh']) + modelPar = {'obbmodel': model} + segPar = None + model_param = { + "modelPar": modelPar, + "obbModelPar": obbModelPar, + "sort_tracker": sort_tracker, + "trackPar": trackPar, + "segPar": segPar + } + self.model_conf = (modeType, model_param, allowedList, names, rainbows) + except Exception: + logger.exception("模型加载异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) + logger.info("模型初始化时间:{}, requestId:{}", time.time() - s, requestId) + + +def obb_process(args): + imgarray_list, iframe_list, model_param, request_id = args + try: + return OBB_tracker_batch(imgarray_list, iframe_list, model_param['modelPar'], model_param['obbModelPar'], + model_param['sort_tracker'], model_param['trackPar'], model_param['segPar']) + except ServiceException as s: + raise s + except Exception: + # self.num += 1 + # cv2.imwrite('/home/th/tuo_heng/dev/img%s.jpg' % str(self.num), frame) + logger.error("算法模型分析异常:{}, requestId:{}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + + +# 车牌分割模型、健康码、行程码分割模型 +class IMModel: + __slots__ = "model_conf" + + def __init__(self, device, allowedList=None, requestId=None, modeType=None, gpu_name=None, base_dir=None, env=None): + try: + logger.info("########################加载{}########################, requestId:{}", modeType.value[2], + requestId) + img_type = 'code' + if ModelType2.PLATE_MODEL == modeType: + img_type = 'plate' + par = { + 'code': {'weights': '../AIlib2/weights/conf/jkm/health_yolov5s_v3.jit', 'img_type': 'code', 'nc': 10}, + 'plate': {'weights': '../AIlib2/weights/conf/jkm/plate_yolov5s_v3.jit', 'img_type': 'plate', 'nc': 1}, + 'conf_thres': 0.4, + 'iou_thres': 0.45, + 'device': 'cuda:%s' % device, + 'plate_dilate': (0.5, 0.3) + } + new_device = torch.device(par['device']) + model = torch.jit.load(par[img_type]['weights']) + model_param = { + "device": new_device, + "model": model, + "par": par, + "img_type": img_type + } + self.model_conf = (modeType, model_param, allowedList) + except Exception: + logger.error("模型加载异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) + + +def im_process(args): + model_param, frame, request_id = args + device, par, img_type = model_param['device'], model_param['par'], model_param['img_type'] + try: + img, padInfos = pre_process(frame, device) + pred = model_param['model'](img) + boxes = post_process(pred, padInfos, device, conf_thres=par['conf_thres'], + iou_thres=par['iou_thres'], nc=par[img_type]['nc']) # 后处理 + dataBack = get_return_data(frame, boxes, modelType=img_type, plate_dilate=par['plate_dilate']) + return dataBack + except ServiceException as s: + raise s + except Exception: + logger.error("算法模型分析异常:{}, requestId:{}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + + +# 百度AI图片识别模型 +class BaiduAiImageModel: + __slots__ = "model_conf" + + def __init__(self, device=None, allowedList=None, requestId=None, modeType=None, gpu_name=None, base_dir=None, + env=None): + try: + logger.info("########################加载{}########################, requestId:{}", modeType.value[2], + requestId) + aipBodyAnalysisClient = AipBodyAnalysisClient(base_dir, env) + aipImageClassifyClient = AipImageClassifyClient(base_dir, env) + rainbows = COLOR + vehicle_names = [VehicleEnum.CAR.value[1], VehicleEnum.TRICYCLE.value[1], VehicleEnum.MOTORBIKE.value[1], + VehicleEnum.CARPLATE.value[1], VehicleEnum.TRUCK.value[1], VehicleEnum.BUS.value[1]] + person_names = ['人'] + model_param = { + "vehicle_client": aipImageClassifyClient, + "person_client": aipBodyAnalysisClient, + } + self.model_conf = (modeType, model_param, allowedList, (vehicle_names, person_names), rainbows) + except Exception: + logger.exception("模型加载异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) + + +def baidu_process(args): + model_param, target, url, request_id = args + try: + baiduEnum = BAIDU_MODEL_TARGET_CONFIG2.get(target) + if baiduEnum is None: + raise ServiceException(ExceptionType.DETECTION_TARGET_TYPES_ARE_NOT_SUPPORTED.value[0], + ExceptionType.DETECTION_TARGET_TYPES_ARE_NOT_SUPPORTED.value[1] + + " target: " + target) + return baiduEnum.value[2](model_param['vehicle_client'], model_param['person_client'], url, request_id) + except ServiceException as s: + raise s + except Exception: + logger.error("算法模型分析异常:{}, requestId:{}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + + +def get_baidu_label_arraylist(*args): + width, height, vehicle_names, person_names, rainbows = args + # line = int(round(0.002 * (height + width) / 2) + 1) + line = max(1, int(round(width / 1920 * 3) + 1)) + label = ' 0.97' + tf = max(line, 1) + fontScale = line * 0.33 + text_width, text_height = cv2.getTextSize(label, 0, fontScale=fontScale, thickness=tf)[0] + vehicle_label_arrays = get_label_arrays(vehicle_names, rainbows, fontSize=text_height, fontPath=FONT_PATH) + person_label_arrays = get_label_arrays(person_names, rainbows, fontSize=text_height, fontPath=FONT_PATH) + font_config = (line, text_width, text_height, fontScale, tf) + return vehicle_label_arrays, person_label_arrays, font_config + + +def one_label(width, height, model_config): + # (modeType, model_param, allowedList, names, rainbows) + names = model_config[3] + rainbows = model_config[4] + label_arraylist, font_config = get_label_arraylist(width, height, names, rainbows) + model_config[1]['label_arraylist'] = label_arraylist + model_config[1]['font_config'] = font_config + + +def baidu_label(width, height, model_config): + # modeType, model_param, allowedList, (vehicle_names, person_names), rainbows + vehicle_names = model_config[3][0] + person_names = model_config[3][1] + rainbows = model_config[4] + vehicle_label_arrays, person_label_arrays, font_config = get_baidu_label_arraylist(width, height, vehicle_names, + person_names, rainbows) + model_config[1]['vehicle_label_arrays'] = vehicle_label_arrays + model_config[1]['person_label_arrays'] = person_label_arrays + model_config[1]['font_config'] = font_config + + + + +def model_process1(args): + imgarray_list, iframe_list, model_param, request_id = args + model_conf, frame, request_id = args + model_param, names, rainbows = model_conf[1], model_conf[3], model_conf[4] + # modeType, model_param, allowedList, names, rainbows = model_conf + # segmodel, names, label_arraylist, rainbows, objectPar, font, segPar, mode, postPar, requestId = args + # model_param['digitFont'] = digitFont + # model_param['label_arraylist'] = label_arraylist + # model_param['font_config'] = font_config + try: + return AI_process([frame], model_param['model'], model_param['segmodel'], names, model_param['label_arraylist'], + rainbows, objectPar=model_param['objectPar'], font=model_param['digitFont'], + segPar=loads(dumps(model_param['segPar'])), mode=model_param['mode'], + postPar=model_param['postPar']) + except ServiceException as s: + raise s + except Exception: + # self.num += 1 + # cv2.imwrite('/home/th/tuo_heng/dev/img%s.jpg' % str(self.num), frame) + logger.error("算法模型分析异常:{}, requestId:{}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + + +MODEL_CONFIG2 = { + # 加载河道模型 + ModelType2.WATER_SURFACE_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.WATER_SURFACE_MODEL, t, z, h), + ModelType2.WATER_SURFACE_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 加载森林模型 + ModelType2.FOREST_FARM_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.FOREST_FARM_MODEL, t, z, h), + ModelType2.FOREST_FARM_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 加载交通模型 + ModelType2.TRAFFIC_FARM_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.TRAFFIC_FARM_MODEL, t, z, h), + ModelType2.TRAFFIC_FARM_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 加载防疫模型 + ModelType2.EPIDEMIC_PREVENTION_MODEL.value[1]: ( + lambda x, y, r, t, z, h: IMModel(x, y, r, ModelType2.EPIDEMIC_PREVENTION_MODEL, t, z, h), + ModelType2.EPIDEMIC_PREVENTION_MODEL, + None, + lambda x: im_process(x)), + # 加载车牌模型 + ModelType2.PLATE_MODEL.value[1]: ( + lambda x, y, r, t, z, h: IMModel(x, y, r, ModelType2.PLATE_MODEL, t, z, h), + ModelType2.PLATE_MODEL, + None, + lambda x: im_process(x)), + # 加载车辆模型 + ModelType2.VEHICLE_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.VEHICLE_MODEL, t, z, h), + ModelType2.VEHICLE_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 加载行人模型 + ModelType2.PEDESTRIAN_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.PEDESTRIAN_MODEL, t, z, h), + ModelType2.PEDESTRIAN_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x)), + # 加载烟火模型 + ModelType2.SMOGFIRE_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.SMOGFIRE_MODEL, t, z, h), + ModelType2.SMOGFIRE_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x)), + # 加载钓鱼游泳模型 + ModelType2.ANGLERSWIMMER_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.ANGLERSWIMMER_MODEL, t, z, h), + ModelType2.ANGLERSWIMMER_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x)), + # 加载乡村模型 + ModelType2.COUNTRYROAD_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.COUNTRYROAD_MODEL, t, z, h), + ModelType2.COUNTRYROAD_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x)), + # 加载船只模型 + ModelType2.SHIP_MODEL.value[1]: ( + lambda x, y, r, t, z, h: ShipModel(x, y, r, ModelType2.SHIP_MODEL, t, z, h), + ModelType2.SHIP_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: obb_process(x)), + # 百度AI图片识别模型 + ModelType2.BAIDU_MODEL.value[1]: ( + lambda x, y, r, t, z, h: BaiduAiImageModel(x, y, r, ModelType2.BAIDU_MODEL, t, z, h), + ModelType2.BAIDU_MODEL, + lambda x, y, z: baidu_label(x, y, z), + lambda x: baidu_process(x)), + # 航道模型 + ModelType2.CHANNEL_EMERGENCY_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.CHANNEL_EMERGENCY_MODEL, t, z, h), + ModelType2.CHANNEL_EMERGENCY_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x)), + # 河道检测模型 + ModelType2.RIVER2_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.RIVER2_MODEL, t, z, h), + ModelType2.RIVER2_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x)), + # 城管模型 + ModelType2.CITY_MANGEMENT_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.CITY_MANGEMENT_MODEL, t, z, h), + ModelType2.CITY_MANGEMENT_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 人员落水模型 + ModelType2.DROWING_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.DROWING_MODEL, t, z, h), + ModelType2.DROWING_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 城市违章模型 + ModelType2.NOPARKING_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.NOPARKING_MODEL, t, z, h), + ModelType2.NOPARKING_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 城市公路模型 + ModelType2.CITYROAD_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.CITYROAD_MODEL, t, z, h), + ModelType2.CITYROAD_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 加载坑槽模型 + ModelType2.POTHOLE_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.POTHOLE_MODEL, t, z, h), + ModelType2.POTHOLE_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), +} diff --git a/util/MyConnectionPool.py b/util/MyConnectionPool.py new file mode 100644 index 0000000..d65037c --- /dev/null +++ b/util/MyConnectionPool.py @@ -0,0 +1,227 @@ +# -*- coding: UTF-8 -*- +import pymysql +from loguru import logger +from dbutils.pooled_db import PooledDB + + +""" +@功能:创建数据库连接池 +""" + + +class MyConnectionPool(object): + __pool = None + + def __init__(self, content): + self.conn = self.__getConn(content) + self.cursor = self.conn.cursor() + + # 创建数据库连接conn和游标cursor + # def __enter__(self): + # self.conn = self.__getconn() + # self.cursor = self.conn.cursor() + + # 创建数据库连接池 + def __getconn(self, content): + if self.__pool is None: + self.__pool = PooledDB( + creator=pymysql, + mincached=int(content["mysql"]["db_min_cached"]), + maxcached=int(content["mysql"]["db_max_cached"]), + maxshared=int(content["mysql"]["db_max_shared"]), + maxconnections=int(content["mysql"]["db_max_connecyions"]), + blocking=content["mysql"]["db_blocking"], + maxusage=content["mysql"]["db_max_usage"], + setsession=content["mysql"]["db_set_session"], + host=content["mysql"][content["dsp"]["active"]]["host"], + port=content["mysql"][content["dsp"]["active"]]["port"], + user=content["mysql"][content["dsp"]["active"]]["username"], + passwd=content["mysql"][content["dsp"]["active"]]["password"], + db=content["mysql"][content["dsp"]["active"]]["dbname"], + use_unicode=False, + charset=content["mysql"]["db_charset"] + ) + return self.__pool.connection() + + # 释放连接池资源 + # def __exit__(self, exc_type, exc_val, exc_tb): + # self.cursor.close() + # self.conn.close() + + # 关闭连接归还给链接池 + def close(self): + self.cursor.close() + self.conn.close() + + # 从连接池中取出一个连接 + def getconn(self, content): + conn = self.__getconn(content) + cursor = conn.cursor() + return cursor, conn + + +# 获取连接池,实例化 +def get_my_connection(content): + return MyConnectionPool(content) + + +''' + 执行语句查询有结果返回结果没有返回0;增/删/改返回变更数据条数,没有返回0 +''' + + +class MySqLHelper(object): + def __init__(self, content): + logger.info("开始加载数据库连接池!") + self.db = get_my_connection(content) + logger.info("加载数据库连接池完成!") + + def __new__(cls, *args, **kwargs): + if not hasattr(cls, 'inst'): # 单例 + cls.inst = super(MySqLHelper, cls).__new__(cls, *args, **kwargs) + return cls.inst + + # 封装执行命令 + def execute(self, sql, param=None, autoclose=False): + """ + 【主要判断是否有参数和是否执行完就释放连接】 + :param sql: 字符串类型,sql语句 + :param param: sql语句中要替换的参数"select %s from tab where id=%s" 其中的%s就是参数 + :param autoclose: 是否关闭连接 + :return: 返回连接conn和游标cursor + """ + cursor, conn = self.db.getconn() # 从连接池获取连接 + count = 0 + try: + # count : 为改变的数据条数 + if param: + count = cursor.execute(sql, param) + else: + count = cursor.execute(sql) + conn.commit() + if autoclose: + self.close(cursor, conn) + except Exception as e: + pass + return cursor, conn, count + + # 执行多条命令 + # def executemany(self, lis): + # """ + # :param lis: 是一个列表,里面放的是每个sql的字典'[{"sql":"xxx","param":"xx"}....]' + # :return: + # """ + # cursor, conn = self.db.getconn() + # try: + # for order in lis: + # sql = order['sql'] + # param = order['param'] + # if param: + # cursor.execute(sql, param) + # else: + # cursor.execute(sql) + # conn.commit() + # self.close(cursor, conn) + # return True + # except Exception as e: + # print(e) + # conn.rollback() + # self.close(cursor, conn) + # return False + + # 释放连接 + def close(self, cursor, conn): + logger.info("开始释放数据库连接!") + cursor.close() + conn.close() + logger.info("释放数据库连接完成!") + + # 查询所有 + def selectall(self, sql, param=None): + try: + cursor, conn, count = self.execute(sql, param) + res = cursor.fetchall() + return res + except Exception as e: + logger.error("查询所有数据异常:") + logger.exception(e) + self.close(cursor, conn) + return count + + # 查询单条 + def selectone(self, sql, param=None): + try: + cursor, conn, count = self.execute(sql, param) + res = cursor.fetchone() + self.close(cursor, conn) + return res + except Exception as e: + logger.error("查询单条数据异常:") + logger.exception(e) + self.close(cursor, conn) + return count + + # 增加 + def insertone(self, sql, param): + try: + cursor, conn, count = self.execute(sql, param) + # _id = cursor.lastrowid() # 获取当前插入数据的主键id,该id应该为自动生成为好 + conn.commit() + self.close(cursor, conn) + return count + # 防止表中没有id返回0 + # if _id == 0: + # return True + # return _id + except Exception as e: + logger.error("新增数据异常:") + logger.exception(e) + conn.rollback() + self.close(cursor, conn) + return count + + # 增加多行 + def insertmany(self, sql, param): + """ + :param sql: + :param param: 必须是元组或列表[(),()]或((),()) + :return: + """ + cursor, conn, count = self.db.getconn() + try: + cursor.executemany(sql, param) + conn.commit() + return count + except Exception as e: + logger.error("增加多条数据异常:") + logger.exception(e) + conn.rollback() + self.close(cursor, conn) + return count + + # 删除 + def delete(self, sql, param=None): + try: + cursor, conn, count = self.execute(sql, param) + self.close(cursor, conn) + return count + except Exception as e: + logger.error("删除数据异常:") + logger.exception(e) + conn.rollback() + self.close(cursor, conn) + return count + + # 更新 + def update(self, sql, param=None): + try: + cursor, conn, count = self.execute(sql, param) + conn.commit() + self.close(cursor, conn) + return count + except Exception as e: + logger.error("更新数据异常:") + logger.exception(e) + conn.rollback() + self.close(cursor, conn) + return count diff --git a/util/OcrBaiduSdk.py b/util/OcrBaiduSdk.py new file mode 100644 index 0000000..3e11ca6 --- /dev/null +++ b/util/OcrBaiduSdk.py @@ -0,0 +1,147 @@ +import time +import traceback +from os.path import join + +import cv2 +from aip import AipOcr +from loguru import logger + +from common.YmlConstant import baidu_yml_path +from enums.BaiduSdkEnum import BAIDUERRORDATA +from enums.ExceptionEnum import ExceptionType +from exception.CustomerException import ServiceException +from util.RWUtils import getConfigs + + +class OcrBaiduSdk: + + __slots__ = ('client', "__config") + + def __init__(self, base_dir, env): + self.client = None + self.__config = getConfigs(join(base_dir, baidu_yml_path % env)) + self.init_client() + + def init_client(self): + if self.client is None: + self.client = AipOcr(str(self.__config["orc"]["APP_ID"]), + self.__config["orc"]["API_KEY"], + self.__config["orc"]["SECRET_KEY"]) + + ''' + { + "log_id": 2471272194, + "words_result_num": 2, + "words_result": + [ + {"words": " TSINGTAO"}, + {"words": "青島睥酒"} + ] + } + ''' + + def universal_text_recognition(self, image, request_id): + reply_num = 0 + reply_value = None + while True: + try: + or_result, or_image = cv2.imencode(".jpg", image) + options = { + "language_type": "CHN_ENG", + "detect_direction": "true", + "detect_language": "true", + "probability": "true" + } + res_image = self.client.basicGeneral(or_image.tobytes(), options) + error_code = res_image.get("error_code") + if error_code: + enum = BAIDUERRORDATA.get(error_code) + # 如果异常编码未知, 返回空值 + if enum is None: + logger.error("百度云人流量统计异常!error_code:{}, request_id: {}", error_code, request_id) + return None + # 重试指定次数后,还是异常,输出统一内部异常 + if enum.value[3] == 0: + if reply_value is None: + reply_value = enum.value[4] + logger.error("百度云人流量统计异常!error_code:{}, error_msg:{}, reply_num:{}, request_id: {}", + enum.value[0], enum.value[2], reply_num, request_id) + raise Exception() + # 重试指定次数后,还是异常,输出对应的异常 + if enum.value[3] == 1: + if reply_value is None: + reply_value = enum.value[4] + raise ServiceException(str(enum.value[0]), enum.value[2]) + # 重试指定次数后,还是异常,输出空 + if enum.value[3] == 2: + if reply_value is None: + reply_value = enum.value[4] + if reply_num >= reply_value: + return None + raise Exception() + return res_image + except Exception as e: + time.sleep(1) + reply_num += 0.5 + self.init_client() + if reply_num > reply_value: + if isinstance(e, ServiceException): + raise ServiceException(e.code, e.msg) + logger.error("通用文字识别失败: {}, request_id: {}", traceback.format_exc(), request_id) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + + ''' + { + "log_id": 3583925545, + "words_result": { + "color": "blue", + "number": "苏HS7766" + } + } + ''' + def license_plate_recognition(self, image, request_id): + reply_num = 0 + reply_value = None + while True: + try: + or_result, or_image = cv2.imencode(".jpg", image) + res_image = self.client.licensePlate(or_image.tobytes(), {"multi_detect": "true"}) + error_code = res_image.get("error_code") + if error_code: + enum = BAIDUERRORDATA.get(error_code) + # 如果异常编码未知, 返回空值 + if enum is None: + logger.error("百度云人流量统计异常!error_code:{}, request_id: {}", error_code, request_id) + return None + # 重试指定次数后,还是异常,输出统一内部异常 + if enum.value[3] == 0: + if reply_value is None: + reply_value = enum.value[4] + logger.error("百度云人流量统计异常!error_code:{}, error_msg:{}, reply_num:{}, request_id: {}", + enum.value[0], enum.value[2], reply_num, request_id) + raise Exception() + # 重试指定次数后,还是异常,输出对应的异常 + if enum.value[3] == 1: + if reply_value is None: + reply_value = enum.value[4] + raise ServiceException(str(enum.value[0]), enum.value[2]) + # 重试指定次数后,还是异常,输出空 + if enum.value[3] == 2: + if reply_value is None: + reply_value = enum.value[4] + if reply_num >= reply_value: + return None + raise Exception() + return res_image + except Exception as e: + time.sleep(1) + reply_num += 1 + self.init_client() + if reply_num > reply_value: + if isinstance(e, ServiceException): + raise ServiceException(e.code, e.msg) + logger.error("车牌识别失败: {}, request_id: {}", traceback.format_exc(), request_id) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + diff --git a/util/PlotsUtils.py b/util/PlotsUtils.py new file mode 100644 index 0000000..ddbbce3 --- /dev/null +++ b/util/PlotsUtils.py @@ -0,0 +1,258 @@ +import cv2 +import numpy as np +from PIL import Image, ImageDraw, ImageFont +import unicodedata +FONT_PATH = "../AIlib2/conf/platech.ttf" + +zhFont = ImageFont.truetype(FONT_PATH, 20, encoding="utf-8") + +def get_label_array(color=None, label=None, font=None, fontSize=40, unify=False): + if unify: + x, y, width, height = font.getbbox("标") # 统一数组大小 + else: + 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, -1), 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) + scale = height / fontSize + im_array = cv2.resize(im_array, (0, 0), fx=scale, fy=scale) + return im_array + + +def get_label_arrays(labelNames, colors, fontSize=40, fontPath="platech.ttf"): + font = ImageFont.truetype(fontPath, fontSize, encoding='utf-8') + label_arraylist = [get_label_array(colors[i % 20], label_name, font, fontSize) for i, label_name in + enumerate(labelNames)] + return label_arraylist + +def get_label_array_dict(colors, fontSize=40, fontPath="platech.ttf"): + font = ImageFont.truetype(fontPath, fontSize, encoding='utf-8') + all_chinese_characters = [] + for char in range(0x4E00, 0x9FFF + 1): # 中文 + chinese_character = chr(char) + if unicodedata.category(chinese_character) == 'Lo': + all_chinese_characters.append(chinese_character) + for char in range(0x0041, 0x005B): # 大写字母 + all_chinese_characters.append(chr(char)) + for char in range(0x0061, 0x007B): # 小写字母 + all_chinese_characters.append(chr(char)) + for char in range(0x0030, 0x003A): # 数字 + all_chinese_characters.append(chr(char)) + zh_dict = {} + for code in all_chinese_characters: + arr = get_label_array(colors[2], code, font, fontSize, unify=True) + zh_dict[code] = arr + return zh_dict + + +def xywh2xyxy(box): + if not isinstance(box[0], (list, tuple, np.ndarray)): + xc, yc, w, h = int(box[0]), int(box[1]), int(box[2]), int(box[3]) + bw, bh = int(w / 2), int(h / 2) + lt, yt, rt, yr = xc - bw, yc - bh, xc + bw, yc + bh + box = [(lt, yt), (rt, yt), (rt, yr), (lt, yr)] + return box + +def xywh2xyxy2(param): + if not isinstance(param[0], (list, tuple, np.ndarray)): + xc, yc, x2, y2 = int(param[0]), int(param[1]), int(param[2]), int(param[3]) + return [(xc, yc), (x2, yc), (x2, y2), (xc, y2)], float(param[4]), int(param[5]) + # bw, bh = int(w / 2), int(h / 2) + # lt, yt, rt, yr = xc - bw, yc - bh, xc + bw, yc + bh + # return [(lt, yt), (rt, yt), (rt, yr), (lt, yr)] + return np.asarray(param[0][0:4], np.int32), float(param[1]), int(param[2]) + + +def draw_painting_joint(box, img, label_array, score=0.5, color=None, config=None, isNew=False): + # 识别问题描述图片的高、宽 + lh, lw = label_array.shape[0:2] + # 图片的长度和宽度 + imh, imw = img.shape[0:2] + box = xywh2xyxy(box) + # 框框左上的位置 + x0, y1 = box[0][0], box[0][1] + # if score_location == 'leftTop': + # x0, y1 = box[0][0], box[0][1] + # # 框框左下的位置 + # elif score_location == 'leftBottom': + # x0, y1 = box[3][0], box[3][1] + # else: + # x0, y1 = box[0][0], box[0][1] + # x1 框框左上x位置 + 描述的宽 + # y0 框框左上y位置 - 描述的高 + x1, y0 = x0 + lw, y1 - lh + # 如果y0小于0, 说明超过上边框 + if y0 < 0: + y0 = 0 + # y1等于文字高度 + y1 = y0 + lh + # 如果y1框框的高大于图片高度 + if y1 > imh: + # y1等于图片高度 + y1 = imh + # y0等于y1减去文字高度 + y0 = y1 - lh + # 如果x0小于0 + if x0 < 0: + x0 = 0 + x1 = x0 + lw + if x1 > imw: + x1 = imw + x0 = x1 - lw + # box_tl = max(int(round(imw / 1920 * 3)), 1) or round(0.002 * (imh + imw) / 2) + 1 + ''' + 1. img(array) 为ndarray类型(可以为cv.imread)直接读取的数据 + 2. box(array):为所画多边形的顶点坐标 + 3. 所画四边形是否闭合,通常为True + 4. color(tuple):BGR三个通道的值 + 5. thickness(int):画线的粗细 + 6. shift:顶点坐标中小数的位数 + ''' + tl = config[0] + box1 = np.asarray(box, np.int32) + cv2.polylines(img, [box1], True, color, tl) + img[y0:y1, x0:x1, :] = label_array + pts_cls = [(x0, y0), (x1, y1)] + # 把英文字符score画到类别旁边 + # tl = max(int(round(imw / 1920 * 3)), 1) or round(0.002 * (imh + imw) / 2) + 1 + label = ' %.2f' % score + # tf = max(tl, 1) + # fontScale = float(format(imw / 1920 * 1.1, '.2f')) or tl * 0.33 + # fontScale = tl * 0.33 + ''' + 1. text:要计算大小的文本内容,类型为字符串。 + 2. fontFace:字体类型,例如cv2.FONT_HERSHEY_SIMPLEX等。 + 3. fontScale:字体大小的缩放因子,例如1.2表示字体大小增加20%。 + 4. thickness:文本线条的粗细,以像素为单位。 + 5. (text_width, text_height):给定文本在指定字体、字体大小、线条粗细下所占用的像素宽度和高度。 + ''' + # t_size = cv2.getTextSize(label, 0, fontScale=fontScale, thickness=tf)[0] + t_size = (config[1], config[2]) + # if socre_location=='leftTop': + p1, p2 = (pts_cls[1][0], pts_cls[0][1]), (pts_cls[1][0] + t_size[0], pts_cls[1][1]) + ''' + 1. img:要绘制矩形的图像 + 2. pt1:矩形框的左上角坐标,可以是一个包含两个整数的元组或列表,例如(x1, y1)或[x1, y1]。 + 3. pt2:矩形框的右下角坐标,可以是一个包含两个整数的元组或列表,例如(x2, y2)或[x2, y2]。 + 4. color:矩形框的颜色,可以是一个包含三个整数的元组或列表,例如(255, 0, 0)表示蓝色,或一个标量值,例如255表示白色。颜色顺序为BGR。 + 5. thickness:线条的粗细,以像素为单位。如果为负值,则表示要绘制填充矩形。默认值为1。 + 6. lineType:线条的类型,可以是cv2.LINE_AA表示抗锯齿线条,或cv2.LINE_4表示4连通线条,或cv2.LINE_8表示8连通线条。默认值为cv2.LINE_8。 + 7. shift:坐标点小数点位数。默认值为0。 + ''' + cv2.rectangle(img, p1, p2, color, -1, cv2.LINE_AA) + p3 = pts_cls[1][0], pts_cls[1][1] - (lh - t_size[1]) // 2 + ''' + 1. img:要在其上绘制文本的图像 + 2. text:要绘制的文本内容,类型为字符串 + 3. org:文本起始位置的坐标,可以是一个包含两个整数的元组或列表,例如(x, y)或[x, y]。 + 4. fontFace:字体类型,例如cv2.FONT_HERSHEY_SIMPLEX等。 + 5. fontScale:字体大小的缩放因子,例如1.2表示字体大小增加20%。 + 6. color:文本的颜色,可以是一个包含三个整数的元组或列表,例如(255, 0, 0)表示蓝色,或一个标量值,例如255表示白色。颜色顺序为BGR。 + 7. thickness:文本线条的粗细,以像素为单位。默认值为1。 + 8. lineType:线条的类型,可以是cv2.LINE_AA表示抗锯齿线条,或cv2.LINE_4表示4连通线条,或cv2.LINE_8表示8连通线条。默认值为cv2.LINE_8。 + 9. bottomLeftOrigin:文本起始位置是否为左下角。如果为True,则文本起始位置为左下角,否则为左上角。默认值为False。 + ''' + if isNew: + cv2.putText(img, label, p3, 0, config[3], [0, 0, 0], thickness=config[4], lineType=cv2.LINE_AA) + else: + cv2.putText(img, label, p3, 0, config[3], [225, 255, 255], thickness=config[4], lineType=cv2.LINE_AA) + return img, box + +# 动态标签 +def draw_name_joint(box, img, label_array_dict, score=0.5, color=None, config=None, name=""): + label_array = None + for zh in name: + if zh in label_array_dict: + if label_array is None: + label_array = label_array_dict[zh] + else: + label_array = np.concatenate((label_array,label_array_dict[zh]), axis= 1) + # 识别问题描述图片的高、宽 + if label_array is None: + lh, lw = 0, 0 + else: + lh, lw = label_array.shape[0:2] + # 图片的长度和宽度 + imh, imw = img.shape[0:2] + box = xywh2xyxy(box) + # 框框左上的位置 + x0, y1 = box[0][0], box[0][1] + x1, y0 = x0 + lw, y1 - lh + # 如果y0小于0, 说明超过上边框 + if y0 < 0: + y0 = 0 + # y1等于文字高度 + y1 = y0 + lh + # 如果y1框框的高大于图片高度 + if y1 > imh: + # y1等于图片高度 + y1 = imh + # y0等于y1减去文字高度 + y0 = y1 - lh + # 如果x0小于0 + if x0 < 0: + x0 = 0 + x1 = x0 + lw + if x1 > imw: + x1 = imw + x0 = x1 - lw + tl = config[0] + box1 = np.asarray(box, np.int32) + cv2.polylines(img, [box1], True, color, tl) + if label_array is not None: + img[y0:y1, x0:x1, :] = label_array + pts_cls = [(x0, y0), (x1, y1)] + # 把英文字符score画到类别旁边 + # tl = max(int(round(imw / 1920 * 3)), 1) or round(0.002 * (imh + imw) / 2) + 1 + label = ' %.2f' % score + t_size = (config[1], config[2]) + # if socre_location=='leftTop': + p1, p2 = (pts_cls[1][0], pts_cls[0][1]), (pts_cls[1][0] + t_size[0], pts_cls[1][1]) + cv2.rectangle(img, p1, p2, color, -1, cv2.LINE_AA) + p3 = pts_cls[1][0], pts_cls[1][1] - (lh - t_size[1]) // 2 + cv2.putText(img, label, p3, 0, config[3], [225, 255, 255], thickness=config[4], lineType=cv2.LINE_AA) + return img, box + + +def filterBox(det0, det1, pix_dis): + # det0为 (m1, 11) 矩阵 + # det1为 (m2, 12) 矩阵 + if len(det0.shape) == 1: + det0 = det0[np.newaxis,...] + if len(det1.shape) == 1: + det1 = det1[np.newaxis,...] + det1 = det1[...,0:11].copy() + m, n = det0.size, det1.size + if not m: + return det0 + # 在det0的列方向加一个元素flag代表该目标框中心点是否在之前目标框内(0代表不在,其他代表在) + flag = np.zeros([len(det0), 1]) + det0 = np.concatenate([det0, flag], axis=1) + det0_copy = det0.copy() + # det1_copy = det1.copy() + if not n: + return det0 + # det0转成 (m1, m2, 12) 的矩阵 + # det1转成 (m1, m2, 12) 的矩阵 + # det0与det1在第3维方向上拼接(6 + 7 = 13) + det0 = det0[:, np.newaxis, :].repeat(det1.shape[0], 1) + det1 = det1[np.newaxis, ...].repeat(det0.shape[0], 0) + joint_det = np.concatenate((det1, det0), axis=2) + # 分别求det0和det1的x1, y1, x2, y2(水平框的左上右下角点) + x1, y1, x2, y2 = joint_det[..., 0], joint_det[..., 1], joint_det[..., 4], joint_det[..., 5] + x3, y3, x4, y4 = joint_det[..., 11], joint_det[..., 12], joint_det[..., 15], joint_det[..., 16] + + x2_c, y2_c = (x1+x2)//2, (y1+y2)//2 + x_c, y_c = (x3+x4)//2, (y3+y4)//2 + dis = (x2_c - x_c)**2 + (y2_c - y_c)**2 + mask = (joint_det[..., 9] == joint_det[..., 20]) & (dis <= pix_dis**2) + + # 类别相同 & 中心点在上一帧的框内 判断为True + res = np.sum(mask, axis=1) + det0_copy[..., -1] = res + return det0_copy \ No newline at end of file diff --git a/util/PushStreamUtils.py b/util/PushStreamUtils.py new file mode 100644 index 0000000..91564da --- /dev/null +++ b/util/PushStreamUtils.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +import time +from traceback import format_exc + +import subprocess as sp + +from loguru import logger +from exception.CustomerException import ServiceException +from enums.ExceptionEnum import ExceptionType + + +class PushStreamUtil: + __slots__ = ('pullUrl', 'pushUrl', 'requestId', "push_stream_sp", "start_time") + + def __init__(self, pullUrl=None, pushUrl=None, requestId=None): + self.pullUrl = pullUrl + self.pushUrl = pushUrl + self.requestId = requestId + self.push_stream_sp = None + self.start_time = time.time() + + def close_push_stream_sp(self): + logger.info("开始关闭推流管道, requestId:{}", self.requestId) + if self.push_stream_sp: + logger.info("尝试关闭推流管道, requestId:{}", self.requestId) + self.push_stream_sp.terminate() + self.push_stream_sp.wait() + if self.push_stream_sp and self.push_stream_sp.poll() is None: + logger.error("尝试关闭推流管道失败, requestId:{}", self.requestId) + self.push_stream_sp.communicate(input=b"q\n", timeout=30) + if self.push_stream_sp and self.push_stream_sp.poll() is not None: + logger.info("尝试关闭推流管道成功, requestId:{}", self.requestId) + self.push_stream_sp = None + if self.push_stream_sp and self.push_stream_sp.poll() is not None: + logger.info("尝试关闭推流管道成功, requestId:{}", self.requestId) + self.push_stream_sp = None + else: + logger.info("推流管道已关闭, requestId:{}", self.requestId) + + # 构建 cv2 + def start_push_stream(self): + try: + if self.push_stream_sp: + return + if self.pullUrl is None or len(self.pullUrl) == 0: + logger.error("推流地址不能为空, requestId:{}", self.requestId) + raise ServiceException(ExceptionType.PULL_STREAM_URL_EXCEPTION.value[0], + ExceptionType.PULL_STREAM_URL_EXCEPTION.value[1]) + if self.pushUrl is None or len(self.pushUrl) == 0: + logger.error("推流地址不能为空, requestId:{}", self.requestId) + raise ServiceException(ExceptionType.PUSH_STREAM_URL_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_URL_EXCEPTION.value[1]) + command = ['ffmpeg', '-re', '-y', "-an", "-hide_banner"] + if self.pullUrl.startswith("rtsp://"): + command.extend(['-timeout', '20000000', '-rtsp_transport', 'tcp']) + if self.pullUrl.startswith("rtmp://") or self.pullUrl.startswith("http"): + command.extend(['-rw_timeout', '20000000']) + command.extend(['-i', self.pullUrl, + '-c:v', 'copy', + '-b:v', '4000k', + '-bufsize', '4000k', + '-f', 'flv', + self.pushUrl]) + logger.info("推流指令:{}, requestId:{}", command, self.requestId) + self.push_stream_sp = sp.Popen(command, stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE, shell=False) + except ServiceException as s: + self.close_push_stream_sp() + logger.error("构建p管道异常: {}, requestId:{}", s.msg, self.requestId) + raise s + except Exception as e: + self.close_push_stream_sp() + logger.error("初始化推流管道异常:{}, requestId:{}", format_exc(), self.requestId) + raise e + diff --git a/util/QueRiver.py b/util/QueRiver.py new file mode 100644 index 0000000..3eb78d2 --- /dev/null +++ b/util/QueRiver.py @@ -0,0 +1,346 @@ +from kafka import KafkaProducer, KafkaConsumer +from kafka.errors import kafka_errors +import traceback +import json, base64,os +import numpy as np +from multiprocessing import Process,Queue +import time,cv2,string,random +import subprocess as sp + +import matplotlib.pyplot as plt +from utils.datasets import LoadStreams, LoadImages +from models.experimental import attempt_load +from utils.general import check_img_size, check_requirements, check_imshow, non_max_suppression, apply_classifier, scale_coords, xyxy2xywh, strip_optimizer, set_logging, increment_path +import torch,sys +#from segutils.segmodel import SegModel,get_largest_contours +#sys.path.extend(['../yolov5/segutils']) + +from segutils.segWaterBuilding import SegModel,get_largest_contours,illBuildings + +#from segutils.core.models.bisenet import BiSeNet +from segutils.core.models.bisenet import BiSeNet_MultiOutput + +from utils.plots import plot_one_box,plot_one_box_PIL,draw_painting_joint,get_label_arrays,get_websource +from collections import Counter +#import matplotlib + +import matplotlib.pyplot as plt +# get_labelnames,get_label_arrays,post_process_,save_problem_images,time_str +#FP_DEBUG=open('debut.txt','w') +def bsJpgCode(image_ori): + jpgCode = cv2.imencode('.jpg',image_ori)[-1]###np.array,(4502009,1) + bsCode = str(base64.b64encode(jpgCode))[2:-1] ###str,长6002680 + return bsCode +def bsJpgDecode(bsCode): + bsDecode = base64.b64decode(bsCode)###types,长4502009 + npString = np.frombuffer(bsDecode,np.uint8)###np.array,(长4502009,) + jpgDecode = cv2.imdecode(npString,cv2.IMREAD_COLOR)###np.array,(3000,4000,3) + return jpgDecode +def get_ms(time0,time1): + str_time ='%.2f ms'%((time1-time0)*1000) + return str_time +rainbows=[ + (0,0,255),(0,255,0),(255,0,0),(255,0,255),(255,255,0),(255,127,0),(255,0,127), + (127,255,0),(0,255,127),(0,127,255),(127,0,255),(255,127,255),(255,255,127), + (127,255,255),(0,255,255),(255,127,255),(127,255,255), + (0,127,0),(0,0,127),(0,255,255) + ] + + +def get_labelnames(labelnames): + with open(labelnames,'r') as fp: + namesjson=json.load(fp) + names_fromfile=namesjson['labelnames'] + names = names_fromfile + return names + +def check_stream(stream): + cap = cv2.VideoCapture(stream) + if cap.isOpened(): + return True + else: + return False +##### +def drawWater(pred,image_array0,river={'color':(0,255,255),'line_width':3,'segRegionCnt':2}):####pred是模型的输出,只有水分割的任务 + ##画出水体区域 + contours, hierarchy = cv2.findContours(pred,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) + water = pred.copy(); water[:,:] = 0 + + if len(contours)==0: + return image_array0,water + max_ids = get_largest_contours(contours,river['segRegionCnt']); + for max_id in max_ids: + cv2.fillPoly(water, [contours[max_id][:,0,:]], 1) + cv2.drawContours(image_array0,contours,max_id,river['color'],river['line_width'] ) + return image_array0,water + + +def scale_back(boxes,padInfos): + top, left,r = padInfos[0:3] + + boxes[:,0] = (boxes[:,0] - left) * r + + boxes[:,2] = (boxes[:,2] - left) * r + boxes[:,1] = (boxes[:,1] - top) * r + boxes[:,3] = (boxes[:,3] - top) * r + return boxes + +def img_pad(img, size, pad_value=[114,114,114]): + ###填充成固定尺寸 + H,W,_ = img.shape + r = max(H/size[0], W/size[1]) + img_r = cv2.resize(img, (int(W/r), int(H/r))) + tb = size[0] - img_r.shape[0] + lr = size[1] - img_r.shape[1] + top = int(tb/2) + bottom = tb - top + left = int(lr/2) + right = lr - left + pad_image = cv2.copyMakeBorder(img_r, top, bottom, left, right, cv2.BORDER_CONSTANT,value=pad_value) + return pad_image,(top, left,r) + +def post_process_(datas,conf_thres, iou_thres,names,label_arraylist,rainbows,iframe,ObjectPar={ 'object_config':[0,1,2,3,4], 'slopeIndex':[5,6,7] ,'segmodel':True,'segRegionCnt':1 },font={ 'line_thickness':None, 'fontSize':None,'boxLine_thickness':None,'waterLineColor':(0,255,255),'waterLineWidth':3},padInfos=None ): + object_config,slopeIndex,segmodel,segRegionCnt=ObjectPar['object_config'],ObjectPar['slopeIndex'],ObjectPar['segmodel'],ObjectPar['segRegionCnt'] + ##输入dataset genereate 生成的数据,model预测的结果pred,nms参数 + ##主要操作NMS ---> 坐标转换 ---> 画图 + ##输出原图、AI处理后的图、检测结果 + time0=time.time() + path, img, im0s, vid_cap ,pred,seg_pred= datas[0:6]; + #segmodel=True + pred = non_max_suppression(pred, conf_thres, iou_thres, classes=None, agnostic=False) + time1=time.time() + i=0;det=pred[0]###一次检测一张图片 + time1_1 = time.time() + #p, s, im0 = path[i], '%g: ' % i, im0s[i].copy() + p, s, im0 = path[i], '%g: ' % i, im0s[i] + time1_2 = time.time() + gn = torch.tensor(im0.shape)[[1, 0, 1, 0]] # normalization gain whwh + time1_3 = time.time() + det_xywh=[]; + #im0_brg=cv2.cvtColor(im0,cv2.COLOR_RGB2BGR); + if segmodel: + if len(seg_pred)==2: + im0,water = illBuildings(seg_pred,im0) + else: + river={ 'color':font['waterLineColor'],'line_width':font['waterLineWidth'],'segRegionCnt':segRegionCnt } + im0,water = drawWater(seg_pred,im0,river) + time2=time.time() + #plt.imshow(im0);plt.show() + if len(det)>0: + # Rescale boxes from img_size to im0 size + if not padInfos: + det[:, :4] = scale_coords(img.shape[2:], det[:, :4],im0.shape).round() + else: + #print('####line131:',det[:, :]) + det[:, :4] = scale_back( det[:, :4],padInfos).round() + #print('####line133:',det[:, :]) + #用seg模型,确定有效检测匡及河道轮廓线 + if segmodel: + cls_indexs = det[:, 5].clone().cpu().numpy().astype(np.int32) + ##判断哪些目标属于岸坡的 + slope_flag = np.array([x in slopeIndex for x in cls_indexs ] ) + + det_c = det.clone(); det_c=det_c.cpu().numpy() + try: + area_factors = np.array([np.sum(water[int(x[1]):int(x[3]), int(x[0]):int(x[2])] )*1.0/(1.0*(x[2]-x[0])*(x[3]-x[1])+0.00001) for x in det_c] ) + except: + print('*****************************line143: error:',det_c) + water_flag = np.array(area_factors>0.1) + det = det[water_flag|slope_flag]##如果是水上目标,则需要与水的iou超过0.1;如果是岸坡目标,则直接保留。 + #对检测匡绘图 + for *xyxy, conf, cls in reversed(det): + xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh + cls_c = cls.cpu().numpy() + if int(cls_c) not in object_config: ###如果不是所需要的目标,则不显示 + continue + conf_c = conf.cpu().numpy() + line = [float(cls_c), *xywh, float(conf_c)] # label format + det_xywh.append(line) + label = f'{names[int(cls)]} {conf:.2f}' + + im0 = draw_painting_joint(xyxy,im0,label_arraylist[int(cls)],score=conf,color=rainbows[int(cls)%20],font=font) + time3=time.time() + strout='nms:%s drawWater:%s,copy:%s,toTensor:%s,detDraw:%s '%(get_ms(time0,time1),get_ms(time1,time2),get_ms(time1_1,time1_2),get_ms(time1_2,time1_3), get_ms(time2,time3) ) + return [im0s[0],im0,det_xywh,iframe],strout + + + +def preprocess(par): + print('#####process:',par['name']) + ##负责读取视频,生成原图及供检测的使用图,numpy格式 + #source='rtmp://liveplay.yunhengzhizao.cn/live/demo_HD5M' + #img_size=640; stride=32 + while True: + cap = cv2.VideoCapture(par['source']) + iframe = 0 + if cap.isOpened(): + print( '#### read %s success!'%(par['source'])) + try: + dataset = LoadStreams(par['source'], img_size=640, stride=32) + for path, img, im0s, vid_cap in dataset: + datas=[path, img, im0s, vid_cap,iframe] + par['queOut'].put(datas) + iframe +=1 + except Exception as e: + print('###read error:%s '%(par['source'])) + time.sleep(10) + iframe = 0 + + else: + print('###read error:%s '%(par['source'] )) + time.sleep(10) + iframe = 0 + +def gpu_process(par): + print('#####process:',par['name']) + half=True + ##gpu运算,检测模型 + weights = par['weights'] + device = par['device'] + print('###line127:',par['device']) + model = attempt_load(par['weights'], map_location=par['device']) # load FP32 model + if half: + model.half() + + ##gpu运算,分割模型 + seg_nclass = par['seg_nclass'] + seg_weights = par['seg_weights'] + + #segmodel = SegModel(nclass=seg_nclass,weights=seg_weights,device=device) + + + nclass = [2,2] + Segmodel = BiSeNet_MultiOutput(nclass) + weights='weights/segmentation/WaterBuilding.pth' + segmodel = SegModel(model=Segmodel,nclass=nclass,weights=weights,device='cuda:0',multiOutput=True) + while True: + if not par['queIn'].empty(): + time0=time.time() + datas = par['queIn'].get() + path, img, im0s, vid_cap,iframe = datas[0:5] + time1=time.time() + img = torch.from_numpy(img).to(device) + img = img.half() if half else img.float() # uint8 to fp16/32 + img /= 255.0 # 0 - 255 to 0.0 - 1.0 + time2 = time.time() + pred = model(img,augment=False)[0] + time3 = time.time() + seg_pred = segmodel.eval(im0s[0],outsize=None,smooth_kernel=20) + time4 = time.time() + fpStr= 'process:%s ,iframe:%d,getdata:%s,copygpu:%s,dettime:%s,segtime:%s , time:%s, queLen:%d '%( par['name'],iframe,get_ms(time0,time1) ,get_ms(time1,time2) ,get_ms(time2,time3) ,get_ms(time3,time4),get_ms(time0,time4) ,par['queIn'].qsize() ) + #FP_DEBUG.write( fpStr+'\n' ) + datasOut = [path, img, im0s, vid_cap,pred,seg_pred,iframe] + par['queOut'].put(datasOut) + if par['debug']: + print('#####process:',par['name'],' line107') + else: + time.sleep(1/300) +def get_cls(array): + dcs = Counter(array) + keys = list(dcs.keys()) + values = list(dcs.values()) + max_index = values.index(max(values)) + cls = int(keys[max_index]) + return cls +def save_problem_images(post_results,iimage_cnt,names,streamName='live-THSAHD5M',outImaDir='problems/images_tmp',imageTxtFile=False): + ## [cls, x,y,w,h, conf] + problem_image=[[] for i in range(6)] + + + dets_list = [x[2] for x in post_results] + + mean_scores=[ np.array(x)[:,5].mean() for x in dets_list ] ###mean conf + + best_index = mean_scores.index(max(mean_scores)) ##获取该批图片里,问题图片的index + best_frame = post_results[ best_index][3] ##获取绝对帧号 + img_send = post_results[best_index][1]##AI处理后的图 + img_bak = post_results[best_index][0]##原图 + cls_max = get_cls( x[0] for x in dets_list[best_index] ) + + + time_str = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) + uid=''.join(random.sample(string.ascii_letters + string.digits, 16)) + #ori_name = '2022-01-20-15-57-36_frame-368-720_type-漂浮物_qVh4zI08ZlwJN9on_s-live-THSAHD5M_OR.jpg' + #2022-01-13-15-07-57_frame-9999-9999_type-结束_9999999999999999_s-off-XJRW20220110115904_AI.jpg + outnameOR= '%s/%s_frame-%d-%d_type-%s_%s_s-%s_AI.jpg'%(outImaDir,time_str,best_frame,iimage_cnt,names[cls_max],uid,streamName) + outnameAR= '%s/%s_frame-%d-%d_type-%s_%s_s-%s_OR.jpg'%(outImaDir,time_str,best_frame,iimage_cnt,names[cls_max],uid,streamName) + + cv2.imwrite(outnameOR,img_send) + cv2.imwrite(outnameAR,img_bak) + if imageTxtFile: + outnameOR_txt = outnameOR.replace('.jpg','.txt') + fp=open(outnameOR_txt,'w');fp.write(outnameOR+'\n');fp.close() + outnameAI_txt = outnameAR.replace('.jpg','.txt') + fp=open(outnameAI_txt,'w');fp.write(outnameAR+'\n');fp.close() + + parOut = {}; parOut['imgOR'] = img_send; parOut['imgAR'] = img_send; parOut['uid']=uid + parOut['imgORname']=os.path.basename(outnameOR);parOut['imgARname']=os.path.basename(outnameAR); + parOut['time_str'] = time_str;parOut['type'] = names[cls_max] + return parOut + + + + +def post_process(par): + + print('#####process:',par['name']) + ###post-process参数 + conf_thres,iou_thres,classes=par['conf_thres'],par['iou_thres'],par['classes'] + labelnames=par['labelnames'] + rainbows=par['rainbows'] + fpsample = par['fpsample'] + names=get_labelnames(labelnames) + label_arraylist = get_label_arrays(names,rainbows,outfontsize=40) + iimage_cnt = 0 + post_results=[] + while True: + if not par['queIn'].empty(): + time0=time.time() + datas = par['queIn'].get() + iframe = datas[6] + if par['debug']: + print('#####process:',par['name'],' line129') + p_result,timeOut = post_process_(datas,conf_thres, iou_thres,names,label_arraylist,rainbows,iframe) + par['queOut'].put(p_result) + ##输出结果 + + + + ##每隔 fpsample帧处理一次,如果有问题就保存图片 + if (iframe % fpsample == 0) and (len(post_results)>0) : + #print('####line204:',iframe,post_results) + save_problem_images(post_results,iframe,names) + post_results=[] + + if len(p_result[2] )>0: ## + #post_list = p_result.append(iframe) + post_results.append(p_result) + #print('####line201:',type(p_result)) + + time1=time.time() + outstr='process:%s ,iframe:%d,%s , time:%s, queLen:%d '%( par['name'],iframe,timeOut,get_ms(time0,time1) ,par['queIn'].qsize() ) + #FP_DEBUG.write(outstr +'\n') + #print( 'process:%s ,iframe:%d,%s , time:%s, queLen:%d '%( par['name'],iframe,timeOut,get_ms(time0,time1) ,par['queIn'].qsize() ) ) + else: + time.sleep(1/300) + + +def save_logfile(name,txt): + if os.path.exists(name): + fp=open(name,'r+') + else: + fp=open(name,'w') + + fp.write('%s %s \n'%(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),txt)) + fp.close() +def time_str(): + return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + + + +if __name__=='__main__': + jsonfile='config/queRiver.json' + #image_encode_decode() + work_stream(jsonfile) + #par={'name':'preprocess'} + #preprocess(par) diff --git a/util/QueUtil.py b/util/QueUtil.py new file mode 100644 index 0000000..4fb8334 --- /dev/null +++ b/util/QueUtil.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +from time import time +from traceback import format_exc + +from loguru import logger + +from enums.ExceptionEnum import ExceptionType +from exception.CustomerException import ServiceException + + +def get_no_block_queue(queue): + try: + return queue.get(block=False) + except Exception: + return None + + +def put_queue(queue, result, block=True, timeout=None, is_ex=False): + try: + queue.put(result, block=block, timeout=timeout) + except Exception: + logger.error("添加队列异常:{}", format_exc()) + if is_ex: + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + + +def put_queue_result(queue, result, block=True, timeout=None): + try: + queue.put(result, block=block, timeout=timeout) + return True + except Exception: + logger.error("添加队列异常:{}", format_exc()) + return False + + +def clear_queue(queue): + c_time = time() + while True: + if time() - c_time > 120: + logger.error("清空队列失败, 情况队列超时!") + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + get_no_block_queue(queue) + if queue.empty() or queue.qsize() == 0: + break + # try: + # queue.get_nowait() + # except Exception: + # break diff --git a/util/RWUtils.py b/util/RWUtils.py new file mode 100644 index 0000000..86d5923 --- /dev/null +++ b/util/RWUtils.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from json import loads + +from ruamel.yaml import safe_load + + +def getConfigs(path, read_type='yml'): + with open(path, 'r', encoding="utf-8") as f: + if read_type == 'json': + return loads(f.read()) + if read_type == 'yml': + return safe_load(f) + raise Exception('路径: %s未获取配置信息' % path) + + +def readFile(file, ty="rb"): + with open(file, ty) as f: + return f.read() + diff --git a/util/TimeUtils.py b/util/TimeUtils.py new file mode 100644 index 0000000..64c9516 --- /dev/null +++ b/util/TimeUtils.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +import time +import datetime + +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__": +# print(now_date_to_str(YMDHMSF)) diff --git a/util/TorchUtils.py b/util/TorchUtils.py new file mode 100644 index 0000000..fc87839 --- /dev/null +++ b/util/TorchUtils.py @@ -0,0 +1,315 @@ +# YOLOv5 PyTorch utils + +import datetime + +import math +import os +import platform +import subprocess +import time +from contextlib import contextmanager +from copy import deepcopy +from pathlib import Path +from loguru import logger +import torch +import torch.backends.cudnn as cudnn +import torch.nn as nn +import torch.nn.functional as F +import torchvision + +try: + import thop # for FLOPS computation +except ImportError: + thop = None + + +@contextmanager +def torch_distributed_zero_first(local_rank: int): + """ + Decorator to make all processes in distributed training wait for each local_master to do something. + """ + if local_rank not in [-1, 0]: + torch.distributed.barrier() + yield + if local_rank == 0: + torch.distributed.barrier() + + +def init_torch_seeds(seed=0): + # Speed-reproducibility tradeoff https://pytorch.org/docs/stable/notes/randomness.html + torch.manual_seed(seed) + if seed == 0: # slower, more reproducible + cudnn.benchmark, cudnn.deterministic = False, True + else: # faster, less reproducible + cudnn.benchmark, cudnn.deterministic = True, False + + +# 文件最后修改时间 +def date_modified(path=__file__): + # return human-readable file modification date, i.e. '2021-3-26' + t = datetime.datetime.fromtimestamp(Path(path).stat().st_mtime) + return f'{t.year}-{t.month}-{t.day}' + + +def git_describe(path=Path(__file__).parent): # path must be a directory + # return human-readable git description, i.e. v5.0-5-g3e25f1e https://git-scm.com/docs/git-describe + # -C 指定GIT仓库的路径 + # describe: 命令名,表示获取最近的Git标签信息。 + # tags: 选项,表示只考虑标签。 + # long: 选项,表示使用完整的Git SHA-1哈希值来描述提交。 + # always: 选项,表示如果没有Git标签,则使用Git哈希值来描述提交。 + s = f'git -C {path} describe --tags --long --always' + try: + return subprocess.check_output(s, shell=True, stderr=subprocess.STDOUT).decode()[:-1] + except subprocess.CalledProcessError as e: + return '' + + +def select_device(device='0'): + logger.info("当前torch版本: {}", torch.__version__) + # 设置环境变量 + os.environ['CUDA_VISIBLE_DEVICES'] = device + assert torch.cuda.is_available(), f'CUDA unavailable, invalid device {device} requested' + return torch.device('cuda:%s' % device) + + +# def select_device(device='', batch_size=None): +# # device = 'cpu' or '0' or '0,1,2,3' +# s = f'YOLOv5 🚀 {git_describe() or date_modified()} torch {torch.__version__} ' # string +# cpu = device.lower() == 'cpu' +# if cpu: +# os.environ['CUDA_VISIBLE_DEVICES'] = '-1' # force torch.cuda.is_available() = False +# elif device: # non-cpu device requested +# os.environ['CUDA_VISIBLE_DEVICES'] = device # set environment variable +# assert torch.cuda.is_available(), f'CUDA unavailable, invalid device {device} requested' # check availability +# +# cuda = not cpu and torch.cuda.is_available() +# if cuda: +# n = torch.cuda.device_count() +# if n > 1 and batch_size: # check that batch_size is compatible with device_count +# assert batch_size % n == 0, f'batch-size {batch_size} not multiple of GPU count {n}' +# space = ' ' * len(s) +# for i, d in enumerate(device.split(',') if device else range(n)): +# p = torch.cuda.get_device_properties(i) +# s += f"{'' if i == 0 else space}CUDA:{d} ({p.name}, {p.total_memory / 1024 ** 2}MB)\n" # bytes to MB +# else: +# s += 'CPU\n' +# logger.info(s.encode().decode('ascii', 'ignore') if platform.system() == 'Windows' else s) # emoji-safe +# return torch.device('cuda:0' if cuda else 'cpu') + + +def time_synchronized(): + # pytorch-accurate time + if torch.cuda.is_available(): + torch.cuda.synchronize() + return time.time() + + +def profile(x, ops, n=100, device=None): + # profile a pytorch module or list of modules. Example usage: + # x = torch.randn(16, 3, 640, 640) # input + # m1 = lambda x: x * torch.sigmoid(x) + # m2 = nn.SiLU() + # profile(x, [m1, m2], n=100) # profile speed over 100 iterations + + device = device or torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') + x = x.to(device) + x.requires_grad = True + print(torch.__version__, device.type, torch.cuda.get_device_properties(0) if device.type == 'cuda' else '') + print(f"\n{'Params':>12s}{'GFLOPS':>12s}{'forward (ms)':>16s}{'backward (ms)':>16s}{'input':>24s}{'output':>24s}") + for m in ops if isinstance(ops, list) else [ops]: + m = m.to(device) if hasattr(m, 'to') else m # device + m = m.half() if hasattr(m, 'half') and isinstance(x, torch.Tensor) and x.dtype is torch.float16 else m # type + dtf, dtb, t = 0., 0., [0., 0., 0.] # dt forward, backward + try: + flops = thop.profile(m, inputs=(x,), verbose=False)[0] / 1E9 * 2 # GFLOPS + except: + flops = 0 + + for _ in range(n): + t[0] = time_synchronized() + y = m(x) + t[1] = time_synchronized() + try: + _ = y.sum().backward() + t[2] = time_synchronized() + except: # no backward method + t[2] = float('nan') + dtf += (t[1] - t[0]) * 1000 / n # ms per op forward + dtb += (t[2] - t[1]) * 1000 / n # ms per op backward + + s_in = tuple(x.shape) if isinstance(x, torch.Tensor) else 'list' + s_out = tuple(y.shape) if isinstance(y, torch.Tensor) else 'list' + p = sum(list(x.numel() for x in m.parameters())) if isinstance(m, nn.Module) else 0 # parameters + print(f'{p:12}{flops:12.4g}{dtf:16.4g}{dtb:16.4g}{str(s_in):>24s}{str(s_out):>24s}') + + +def is_parallel(model): + return type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) + + +def intersect_dicts(da, db, exclude=()): + # Dictionary intersection of matching keys and shapes, omitting 'exclude' keys, using da values + return {k: v for k, v in da.items() if k in db and not any(x in k for x in exclude) and v.shape == db[k].shape} + + +def initialize_weights(model): + for m in model.modules(): + t = type(m) + if t is nn.Conv2d: + pass # nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') + elif t is nn.BatchNorm2d: + m.eps = 1e-3 + m.momentum = 0.03 + elif t in [nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6]: + m.inplace = True + + +def find_modules(model, mclass=nn.Conv2d): + # Finds layer indices matching module class 'mclass' + return [i for i, m in enumerate(model.module_list) if isinstance(m, mclass)] + + +def sparsity(model): + # Return global model sparsity + a, b = 0., 0. + for p in model.parameters(): + a += p.numel() + b += (p == 0).sum() + return b / a + + +def prune(model, amount=0.3): + # Prune model to requested global sparsity + import torch.nn.utils.prune as prune + print('Pruning model... ', end='') + for name, m in model.named_modules(): + if isinstance(m, nn.Conv2d): + prune.l1_unstructured(m, name='weight', amount=amount) # prune + prune.remove(m, 'weight') # make permanent + print(' %.3g global sparsity' % sparsity(model)) + + +def fuse_conv_and_bn(conv, bn): + # Fuse convolution and batchnorm layers https://tehnokv.com/posts/fusing-batchnorm-and-conv/ + fusedconv = nn.Conv2d(conv.in_channels, + conv.out_channels, + kernel_size=conv.kernel_size, + stride=conv.stride, + padding=conv.padding, + groups=conv.groups, + bias=True).requires_grad_(False).to(conv.weight.device) + + # prepare filters + w_conv = conv.weight.clone().view(conv.out_channels, -1) + w_bn = torch.diag(bn.weight.div(torch.sqrt(bn.eps + bn.running_var))) + fusedconv.weight.copy_(torch.mm(w_bn, w_conv).view(fusedconv.weight.shape)) + + # prepare spatial bias + b_conv = torch.zeros(conv.weight.size(0), device=conv.weight.device) if conv.bias is None else conv.bias + b_bn = bn.bias - bn.weight.mul(bn.running_mean).div(torch.sqrt(bn.running_var + bn.eps)) + fusedconv.bias.copy_(torch.mm(w_bn, b_conv.reshape(-1, 1)).reshape(-1) + b_bn) + + return fusedconv + + +def model_info(model, verbose=False, img_size=640): + # Model information. img_size may be int or list, i.e. img_size=640 or img_size=[640, 320] + n_p = sum(x.numel() for x in model.parameters()) # number parameters + n_g = sum(x.numel() for x in model.parameters() if x.requires_grad) # number gradients + if verbose: + print('%5s %40s %9s %12s %20s %10s %10s' % ('layer', 'name', 'gradient', 'parameters', 'shape', 'mu', 'sigma')) + for i, (name, p) in enumerate(model.named_parameters()): + name = name.replace('module_list.', '') + print('%5g %40s %9s %12g %20s %10.3g %10.3g' % + (i, name, p.requires_grad, p.numel(), list(p.shape), p.mean(), p.std())) + + try: # FLOPS + from thop import profile + stride = max(int(model.stride.max()), 32) if hasattr(model, 'stride') else 32 + img = torch.zeros((1, model.yaml.get('ch', 3), stride, stride), device=next(model.parameters()).device) # input + flops = profile(deepcopy(model), inputs=(img,), verbose=False)[0] / 1E9 * 2 # stride GFLOPS + img_size = img_size if isinstance(img_size, list) else [img_size, img_size] # expand if int/float + fs = ', %.1f GFLOPS' % (flops * img_size[0] / stride * img_size[1] / stride) # 640x640 GFLOPS + except (ImportError, Exception): + fs = '' + + logger.info(f"Model Summary: {len(list(model.modules()))} layers, {n_p} parameters, {n_g} gradients{fs}") + + +def load_classifier(name='resnet101', n=2): + # Loads a pretrained model reshaped to n-class output + model = torchvision.models.__dict__[name](pretrained=True) + + # ResNet model properties + # input_size = [3, 224, 224] + # input_space = 'RGB' + # input_range = [0, 1] + # mean = [0.485, 0.456, 0.406] + # std = [0.229, 0.224, 0.225] + + # Reshape output to n classes + filters = model.fc.weight.shape[1] + model.fc.bias = nn.Parameter(torch.zeros(n), requires_grad=True) + model.fc.weight = nn.Parameter(torch.zeros(n, filters), requires_grad=True) + model.fc.out_features = n + return model + + +def scale_img(img, ratio=1.0, same_shape=False, gs=32): # img(16,3,256,416) + # scales img(bs,3,y,x) by ratio constrained to gs-multiple + if ratio == 1.0: + return img + else: + h, w = img.shape[2:] + s = (int(h * ratio), int(w * ratio)) # new size + img = F.interpolate(img, size=s, mode='bilinear', align_corners=False) # resize + if not same_shape: # pad/crop img + h, w = [math.ceil(x * ratio / gs) * gs for x in (h, w)] + return F.pad(img, [0, w - s[1], 0, h - s[0]], value=0.447) # value = imagenet mean + + +def copy_attr(a, b, include=(), exclude=()): + # Copy attributes from b to a, options to only include [...] and to exclude [...] + for k, v in b.__dict__.items(): + if (len(include) and k not in include) or k.startswith('_') or k in exclude: + continue + else: + setattr(a, k, v) + + +class ModelEMA: + """ Model Exponential Moving Average from https://github.com/rwightman/pytorch-image-models + Keep a moving average of everything in the model state_dict (parameters and buffers). + This is intended to allow functionality like + https://www.tensorflow.org/api_docs/python/tf/train/ExponentialMovingAverage + A smoothed version of the weights is necessary for some training schemes to perform well. + This class is sensitive where it is initialized in the sequence of model init, + GPU assignment and distributed training wrappers. + """ + + def __init__(self, model, decay=0.9999, updates=0): + # Create EMA + self.ema = deepcopy(model.module if is_parallel(model) else model).eval() # FP32 EMA + # if next(model.parameters()).device.type != 'cpu': + # self.ema.half() # FP16 EMA + self.updates = updates # number of EMA updates + self.decay = lambda x: decay * (1 - math.exp(-x / 2000)) # decay exponential ramp (to help early epochs) + for p in self.ema.parameters(): + p.requires_grad_(False) + + def update(self, model): + # Update EMA parameters + with torch.no_grad(): + self.updates += 1 + d = self.decay(self.updates) + + msd = model.module.state_dict() if is_parallel(model) else model.state_dict() # model state_dict + for k, v in self.ema.state_dict().items(): + if v.dtype.is_floating_point: + v *= d + v += (1. - d) * msd[k].detach() + + def update_attr(self, model, include=(), exclude=('process_group', 'reducer')): + # Update EMA attributes + copy_attr(self.ema, model, include, exclude) diff --git a/util/__init__.py b/util/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/util/__pycache__/AliyunSdk.cpython-38.pyc b/util/__pycache__/AliyunSdk.cpython-38.pyc new file mode 100644 index 0000000..ff407b8 Binary files /dev/null and b/util/__pycache__/AliyunSdk.cpython-38.pyc differ diff --git a/util/__pycache__/CpuUtils.cpython-38.pyc b/util/__pycache__/CpuUtils.cpython-38.pyc new file mode 100644 index 0000000..8380bad Binary files /dev/null and b/util/__pycache__/CpuUtils.cpython-38.pyc differ diff --git a/util/__pycache__/Cv2Utils.cpython-38.pyc b/util/__pycache__/Cv2Utils.cpython-38.pyc new file mode 100644 index 0000000..e879d50 Binary files /dev/null and b/util/__pycache__/Cv2Utils.cpython-38.pyc differ diff --git a/util/__pycache__/FileUtils.cpython-38.pyc b/util/__pycache__/FileUtils.cpython-38.pyc new file mode 100644 index 0000000..0fe7fa8 Binary files /dev/null and b/util/__pycache__/FileUtils.cpython-38.pyc differ diff --git a/util/__pycache__/GPUtils.cpython-38.pyc b/util/__pycache__/GPUtils.cpython-38.pyc new file mode 100644 index 0000000..46b5a42 Binary files /dev/null and b/util/__pycache__/GPUtils.cpython-38.pyc differ diff --git a/util/__pycache__/ImageUtils.cpython-310.pyc b/util/__pycache__/ImageUtils.cpython-310.pyc new file mode 100644 index 0000000..74f8546 Binary files /dev/null and b/util/__pycache__/ImageUtils.cpython-310.pyc differ diff --git a/util/__pycache__/ImageUtils.cpython-38.pyc b/util/__pycache__/ImageUtils.cpython-38.pyc new file mode 100644 index 0000000..44a32f2 Binary files /dev/null and b/util/__pycache__/ImageUtils.cpython-38.pyc differ diff --git a/util/__pycache__/ImgBaiduSdk.cpython-38.pyc b/util/__pycache__/ImgBaiduSdk.cpython-38.pyc new file mode 100644 index 0000000..99f5be9 Binary files /dev/null and b/util/__pycache__/ImgBaiduSdk.cpython-38.pyc differ diff --git a/util/__pycache__/KafkaUtils.cpython-38.pyc b/util/__pycache__/KafkaUtils.cpython-38.pyc new file mode 100644 index 0000000..96daf51 Binary files /dev/null and b/util/__pycache__/KafkaUtils.cpython-38.pyc differ diff --git a/util/__pycache__/LocationUtils.cpython-38.pyc b/util/__pycache__/LocationUtils.cpython-38.pyc new file mode 100644 index 0000000..e1d16ee Binary files /dev/null and b/util/__pycache__/LocationUtils.cpython-38.pyc differ diff --git a/util/__pycache__/LogUtils.cpython-38.pyc b/util/__pycache__/LogUtils.cpython-38.pyc new file mode 100644 index 0000000..d6eeb6e Binary files /dev/null and b/util/__pycache__/LogUtils.cpython-38.pyc differ diff --git a/util/__pycache__/MinioSdk.cpython-38.pyc b/util/__pycache__/MinioSdk.cpython-38.pyc new file mode 100644 index 0000000..1d3dd41 Binary files /dev/null and b/util/__pycache__/MinioSdk.cpython-38.pyc differ diff --git a/util/__pycache__/ModelUtils.cpython-38.pyc b/util/__pycache__/ModelUtils.cpython-38.pyc new file mode 100644 index 0000000..2381de6 Binary files /dev/null and b/util/__pycache__/ModelUtils.cpython-38.pyc differ diff --git a/util/__pycache__/ModelUtils2.cpython-38.pyc b/util/__pycache__/ModelUtils2.cpython-38.pyc new file mode 100644 index 0000000..29b6a09 Binary files /dev/null and b/util/__pycache__/ModelUtils2.cpython-38.pyc differ diff --git a/util/__pycache__/OcrBaiduSdk.cpython-38.pyc b/util/__pycache__/OcrBaiduSdk.cpython-38.pyc new file mode 100644 index 0000000..e8af1ec Binary files /dev/null and b/util/__pycache__/OcrBaiduSdk.cpython-38.pyc differ diff --git a/util/__pycache__/PlotsUtils.cpython-38.pyc b/util/__pycache__/PlotsUtils.cpython-38.pyc new file mode 100644 index 0000000..db14438 Binary files /dev/null and b/util/__pycache__/PlotsUtils.cpython-38.pyc differ diff --git a/util/__pycache__/PushStreamUtils.cpython-38.pyc b/util/__pycache__/PushStreamUtils.cpython-38.pyc new file mode 100644 index 0000000..1d96aec Binary files /dev/null and b/util/__pycache__/PushStreamUtils.cpython-38.pyc differ diff --git a/util/__pycache__/QueUtil.cpython-38.pyc b/util/__pycache__/QueUtil.cpython-38.pyc new file mode 100644 index 0000000..dec6224 Binary files /dev/null and b/util/__pycache__/QueUtil.cpython-38.pyc differ diff --git a/util/__pycache__/RWUtils.cpython-38.pyc b/util/__pycache__/RWUtils.cpython-38.pyc new file mode 100644 index 0000000..28455a7 Binary files /dev/null and b/util/__pycache__/RWUtils.cpython-38.pyc differ diff --git a/util/__pycache__/TimeUtils.cpython-38.pyc b/util/__pycache__/TimeUtils.cpython-38.pyc new file mode 100644 index 0000000..1a50bb9 Binary files /dev/null and b/util/__pycache__/TimeUtils.cpython-38.pyc differ diff --git a/util/__pycache__/TorchUtils.cpython-38.pyc b/util/__pycache__/TorchUtils.cpython-38.pyc new file mode 100644 index 0000000..fedd5ab Binary files /dev/null and b/util/__pycache__/TorchUtils.cpython-38.pyc differ diff --git a/util/__pycache__/__init__.cpython-310.pyc b/util/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..20efd09 Binary files /dev/null and b/util/__pycache__/__init__.cpython-310.pyc differ diff --git a/util/__pycache__/__init__.cpython-38.pyc b/util/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..bf6d77c Binary files /dev/null and b/util/__pycache__/__init__.cpython-38.pyc differ diff --git a/vodsdk/AliyunVodUploader.py b/vodsdk/AliyunVodUploader.py new file mode 100644 index 0000000..d181947 --- /dev/null +++ b/vodsdk/AliyunVodUploader.py @@ -0,0 +1,746 @@ +# -*- coding: UTF-8 -*- +import json +import oss2 +import base64 + +import time + +from aliyunsdkcore import client +from aliyunsdkvod.request.v20170321 import CreateUploadVideoRequest +from aliyunsdkvod.request.v20170321 import RefreshUploadVideoRequest +from aliyunsdkvod.request.v20170321 import CreateUploadImageRequest +from aliyunsdkvod.request.v20170321 import CreateUploadAttachedMediaRequest + +from vodsdk.AliyunVodUtils import * +from loguru import logger + +VOD_MAX_TITLE_LENGTH = 128 +VOD_MAX_DESCRIPTION_LENGTH = 1024 + + +class AliyunVodUploader: + + __slots__ = ( + '__requestId', + '__accessKeyId', + '__accessKeySecret', + '__ecsRegion', + '__vodApiRegion', + '__connTimeout', + '__bucketClient', + '__maxRetryTimes', + '__vodClient', + '__EnableCrc', + '__multipartThreshold', + '__multipartPartSize', + '__multipartThreadsNum' + ) + + def __init__(self, accessKeyId, accessKeySecret, requestId, ecsRegionId=None): + """ + constructor for VodUpload + :param accessKeyId: string, access key id + :param accessKeySecret: string, access key secret + :param ecsRegion: string, 部署迁移脚本的ECS所在的Region,详细参考:https://help.aliyun.com/document_detail/40654.html,如:cn-beijing + :return + """ + self.__requestId = requestId + # LogUtils.init_log(context) + self.__accessKeyId = accessKeyId + self.__accessKeySecret = accessKeySecret + self.__ecsRegion = ecsRegionId + self.__vodApiRegion = None + self.__connTimeout = 60 + self.__bucketClient = None + self.__maxRetryTimes = 5 + self.__vodClient = None + self.__EnableCrc = True + + # 分片上传参数 + self.__multipartThreshold = 10 * 1024 * 1024 # 分片上传的阈值,超过此值开启分片上传 + self.__multipartPartSize = 10 * 1024 * 1024 # 分片大小,单位byte + self.__multipartThreadsNum = 3 # 分片上传时并行上传的线程数,暂时为串行上传,不支持并行,后续会支持。 + # 设置apiRegion为cn-shanghai, 初始化客户端self.__vodClient + self.setApiRegion('cn-shanghai') + logger.info("初始化阿里云视频上传sdk,连接超时时间:{}, 重试次数:{}, requestId:{}", self.__connTimeout, + self.__maxRetryTimes, requestId) + + def setApiRegion(self, apiRegion): + """ + 设置VoD的接入地址,中国大陆为cn-shanghai,海外支持ap-southeast-1(新加坡)等区域,详情参考:https://help.aliyun.com/document_detail/98194.html + :param apiRegion: 接入地址的Region英文表示 + :return: + """ + self.__vodApiRegion = apiRegion + self.__vodClient = self.__initVodClient() + + def __initVodClient(self): + return client.AcsClient(self.__accessKeyId, self.__accessKeySecret, self.__vodApiRegion, + auto_retry=True, max_retry_time=self.__maxRetryTimes, timeout=self.__connTimeout) + + def setMultipartUpload(self, multipartThreshold=10 * 1024 * 1024, multipartPartSize=10 * 1024 * 1024, + multipartThreadsNum=1): + if multipartThreshold > 0: + self.__multipartThreshold = multipartThreshold + if multipartPartSize > 0: + self.__multipartPartSize = multipartPartSize + if multipartThreadsNum > 0: + self.__multipartThreadsNum = multipartThreadsNum + + def setEnableCrc(self, isEnable=False): + self.__EnableCrc = True if isEnable else False + + @catch_error + def uploadLocalVideo(self, uploadVideoRequest, startUploadCallback=None): + """ + 上传本地视频或音频文件到点播,最大支持48.8TB的单个文件,暂不支持断点续传 + :param uploadVideoRequest: UploadVideoRequest类的实例,注意filePath为本地文件的绝对路径 + :param startUploadCallback为获取到上传地址和凭证(uploadInfo)后开始进行文件上传时的回调,可用于记录上传日志等;uploadId为设置的上传ID,可用于关联导入视频。 + :return + """ + uploadInfo = self.__createUploadVideo(uploadVideoRequest) + if startUploadCallback: + startUploadCallback(uploadVideoRequest.uploadId, uploadInfo) + headers = self.__getUploadHeaders(uploadVideoRequest) + self.__uploadOssObjectWithRetry(uploadVideoRequest.filePath, uploadInfo['UploadAddress']['FileName'], + uploadInfo, headers) + return uploadInfo + + @catch_error + def uploadWebVideo(self, uploadVideoRequest, startUploadCallback=None): + """ + 上传网络视频或音频文件到点播,最大支持48.8TB的单个文件(需本地磁盘空间足够);会先下载到本地临时目录,再上传到点播存储 + :param uploadVideoRequest: UploadVideoRequest类的实例,注意filePath为网络文件的URL地址 + :return + """ + # 下载文件 + uploadVideoRequest = self.__downloadWebMedia(uploadVideoRequest) + + # 上传到点播 + uploadInfo = self.__createUploadVideo(uploadVideoRequest) + if startUploadCallback: + startUploadCallback(uploadVideoRequest.uploadId, uploadInfo) + headers = self.__getUploadHeaders(uploadVideoRequest) + self.__uploadOssObjectWithRetry(uploadVideoRequest.filePath, uploadInfo['UploadAddress']['FileName'], + uploadInfo, headers) + + # 删除本地临时文件 + os.remove(uploadVideoRequest.filePath) + + return uploadInfo['VideoId'] + + @catch_error + def uploadLocalM3u8(self, uploadVideoRequest, sliceFilePaths=None): + """ + 上传本地m3u8视频或音频文件到点播,m3u8文件和分片文件默认在同一目录 + :param uploadVideoRequest: UploadVideoRequest类的实例,注意filePath为本地m3u8索引文件的绝对路径, + 且m3u8文件的分片信息必须是相对地址,不能含有URL或本地绝对路径 + :param sliceFilePaths: list, 分片文件的本地路径列表,例如:['/opt/m3u8_video/sample_001.ts', '/opt/m3u8_video/sample_002.ts'] + sliceFilePaths为None时,会按照同一目录去解析分片地址;如不在同一目录等原因导致解析有误,可自行组装分片地址 + :return + """ + + if sliceFilePaths is None: + sliceFilePaths = self.parseLocalM3u8(uploadVideoRequest.filePath) + + if (not isinstance(sliceFilePaths, list)) or len(sliceFilePaths) <= 0: + raise AliyunVodException('InvalidM3u8SliceFile', 'M3u8 slice files invalid', + 'sliceFilePaths invalid or m3u8 index file error') + + # 上传到点播的m3u8索引文件会重写,以此确保分片地址都为相对地址 + downloader = AliyunVodDownloader() + m3u8LocalDir = downloader.getSaveLocalDir() + '/' + AliyunVodUtils.getStringMd5(uploadVideoRequest.fileName) + downloader.setSaveLocalDir(m3u8LocalDir) + m3u8LocalPath = m3u8LocalDir + '/' + os.path.basename(uploadVideoRequest.fileName) + self.__rewriteM3u8File(uploadVideoRequest.filePath, m3u8LocalPath, True) + + # 获取上传凭证 + uploadVideoRequest.setFilePath(m3u8LocalPath) + uploadInfo = self.__createUploadVideo(uploadVideoRequest) + uploadAddress = uploadInfo['UploadAddress'] + headers = self.__getUploadHeaders(uploadVideoRequest) + + # 依次上传分片文件 + for sliceFilePath in sliceFilePaths: + tempFilePath, sliceFileName = AliyunVodUtils.getFileBriefPath(sliceFilePath) + self.__uploadOssObjectWithRetry(sliceFilePath, uploadAddress['ObjectPrefix'] + sliceFileName, uploadInfo, + headers) + + # 上传m3u8文件 + self.__uploadOssObjectWithRetry(m3u8LocalPath, uploadAddress['FileName'], uploadInfo, headers) + + # 删除重写到本地的m3u8文件 + if os.path.exists(m3u8LocalPath): + os.remove(m3u8LocalPath) + if not os.listdir(m3u8LocalDir): + os.rmdir(m3u8LocalDir) + + return uploadInfo['VideoId'] + + @catch_error + def uploadWebM3u8(self, uploadVideoRequest, sliceFileUrls=None): + """ + 上传网络m3u8视频或音频文件到点播,需本地磁盘空间足够,会先下载到本地临时目录,再上传到点播存储 + :param uploadVideoRequest: UploadVideoRequest类的实例,注意filePath为m3u8网络文件的URL地址 + :param sliceFileUrls: list, 分片文件的url,例如:['http://host/sample_001.ts', 'http://host/sample_002.ts'] + sliceFileUrls为None时,会按照同一前缀解析分片地址;如分片路径和m3u8索引文件前缀不同等原因导致解析有误,可自行组装分片地址 + :return + """ + if sliceFileUrls is None: + sliceFileUrls = self.parseWebM3u8(uploadVideoRequest.filePath) + + if (not isinstance(sliceFileUrls, list)) or len(sliceFileUrls) <= 0: + raise AliyunVodException('InvalidM3u8SliceFile', 'M3u8 slice urls invalid', + 'sliceFileUrls invalid or m3u8 index file error') + + # 下载m3u8文件和所有ts分片文件到本地;上传到点播的m3u8索引文件会重写,以此确保分片地址都为相对地址 + downloader = AliyunVodDownloader() + m3u8LocalDir = downloader.getSaveLocalDir() + '/' + AliyunVodUtils.getStringMd5(uploadVideoRequest.fileName) + downloader.setSaveLocalDir(m3u8LocalDir) + m3u8LocalPath = m3u8LocalDir + '/' + os.path.basename(uploadVideoRequest.fileName) + self.__rewriteM3u8File(uploadVideoRequest.filePath, m3u8LocalPath, False) + + sliceList = [] + for sliceFileUrl in sliceFileUrls: + tempFilePath, sliceFileName = AliyunVodUtils.getFileBriefPath(sliceFileUrl) + err, sliceLocalPath = downloader.downloadFile(sliceFileUrl, sliceFileName) + if sliceLocalPath is None: + raise AliyunVodException('FileDownloadError', 'Download M3u8 File Error', '') + sliceList.append((sliceLocalPath, sliceFileName)) + + # 获取上传凭证 + uploadVideoRequest.setFilePath(m3u8LocalPath) + uploadInfo = self.__createUploadVideo(uploadVideoRequest) + uploadAddress = uploadInfo['UploadAddress'] + headers = self.__getUploadHeaders(uploadVideoRequest) + + # 依次上传分片文件 + for sliceFile in sliceList: + self.__uploadOssObjectWithRetry(sliceFile[0], uploadAddress['ObjectPrefix'] + sliceFile[1], uploadInfo, + headers) + + # 上传m3u8文件 + self.__uploadOssObjectWithRetry(m3u8LocalPath, uploadAddress['FileName'], uploadInfo, headers) + + # 删除下载到本地的m3u8文件和分片文件 + if os.path.exists(m3u8LocalPath): + os.remove(m3u8LocalPath) + for sliceFile in sliceList: + if os.path.exists(sliceFile[0]): + os.remove(sliceFile[0]) + if not os.listdir(m3u8LocalDir): + os.rmdir(m3u8LocalDir) + + return uploadInfo['VideoId'] + + @catch_error + def uploadImage(self, uploadImageRequest, isLocalFile=True): + """ + 上传图片文件到点播,不支持断点续传;该接口可支持上传本地图片或网络图片 + :param uploadImageRequest: UploadImageRequest,注意filePath为本地文件的绝对路径或网络文件的URL地址 + :param isLocalFile: bool, 是否为本地文件。True:本地文件,False:网络文件 + :return + """ + # 网络图片需要先下载到本地 + if not isLocalFile: + uploadImageRequest = self.__downloadWebMedia(uploadImageRequest) + + # 上传到点播 + uploadInfo = self.__createUploadImage(uploadImageRequest) + self.__uploadOssObject(uploadImageRequest.filePath, uploadInfo['UploadAddress']['FileName'], uploadInfo, None) + + # 删除本地临时文件 + if not isLocalFile: + os.remove(uploadImageRequest.filePath) + + return uploadInfo['ImageId'], uploadInfo['ImageURL'] + + @catch_error + def uploadAttachedMedia(self, uploadAttachedRequest, isLocalFile=True): + """ + 上传辅助媒资文件(如水印、字幕文件)到点播,不支持断点续传;该接口可支持上传本地或网络文件 + :param uploadAttachedRequest: UploadAttachedMediaRequest,注意filePath为本地文件的绝对路径或网络文件的URL地址 + :param isLocalFile: bool, 是否为本地文件。True:本地文件,False:网络文件 + :return + """ + # 网络文件需要先下载到本地 + if not isLocalFile: + uploadAttachedRequest = self.__downloadWebMedia(uploadAttachedRequest) + + # 上传到点播 + uploadInfo = self.__createUploadAttachedMedia(uploadAttachedRequest) + self.__uploadOssObject(uploadAttachedRequest.filePath, uploadInfo['UploadAddress']['FileName'], uploadInfo, + None) + + # 删除本地临时文件 + if not isLocalFile: + os.remove(uploadAttachedRequest.filePath) + + result = {'MediaId': uploadInfo['MediaId'], 'MediaURL': uploadInfo['MediaURL'], + 'FileURL': uploadInfo['FileURL']} + return result + + @catch_error + def parseWebM3u8(self, m3u8FileUrl): + """ + 解析网络m3u8文件得到所有分片文件地址,原理是将m3u8地址前缀拼接ts分片名称作为后者的下载url,适用于url不带签名或分片与m3u8文件签名相同的情况 + 本函数解析时会默认分片文件和m3u8文件位于同一目录,如不是则请自行拼接分片文件的地址列表 + :param m3u8FileUrl: string, m3u8网络文件url,例如:http://host/sample.m3u8 + :return sliceFileUrls + """ + sliceFileUrls = [] + res = requests.get(m3u8FileUrl) + res.raise_for_status() + for line in res.iter_lines(): + if line.startswith('#'): + continue + sliceFileUrl = AliyunVodUtils.replaceFileName(m3u8FileUrl, line.strip()) + sliceFileUrls.append(sliceFileUrl) + + return sliceFileUrls + + @catch_error + def parseLocalM3u8(self, m3u8FilePath): + """ + 解析本地m3u8文件得到所有分片文件地址,原理是将m3u8地址前缀拼接ts分片名称作为后者的本地路径 + 本函数解析时会默认分片文件和m3u8文件位于同一目录,如不是则请自行拼接分片文件的地址列表 + :param m3u8FilePath: string, m3u8本地文件路径,例如:/opt/videos/sample.m3u8 + :return sliceFilePaths + """ + sliceFilePaths = [] + m3u8FilePath = AliyunVodUtils.toUnicode(m3u8FilePath) + for line in open(m3u8FilePath): + if line.startswith('#'): + continue + sliceFileName = line.strip() + sliceFilePath = AliyunVodUtils.replaceFileName(m3u8FilePath, sliceFileName) + sliceFilePaths.append(sliceFilePath) + + return sliceFilePaths + + # 定义进度条回调函数;consumedBytes: 已经上传的数据量,totalBytes:总数据量 + def uploadProgressCallback(self, consumedBytes, totalBytes): + try: + if totalBytes: + rate = int(100 * (float(consumedBytes) / float(totalBytes))) + else: + rate = 0 + logger.info('视频上传中: {} bytes, percent:{}{}, requestId:{}', consumedBytes, format(rate), '%', + self.__requestId) + except Exception as e: + logger.exception("打印视频上传进度回调方法异常: {}", e) + # print("[%s]uploaded %s bytes, percent %s%s" % ( + # AliyunVodUtils.getCurrentTimeStr(), consumedBytes, format(rate), '%')) + # sys.stdout.flush() + + def __downloadWebMedia(self, request): + + # 下载媒体文件到本地临时目录 + downloader = AliyunVodDownloader() + localFileName = "%s.%s" % (AliyunVodUtils.getStringMd5(request.fileName), request.mediaExt) + fileUrl = request.filePath + err, localFilePath = downloader.downloadFile(fileUrl, localFileName) + if err < 0: + raise AliyunVodException('FileDownloadError', 'Download File Error', '') + + # 重新设置上传请求对象 + request.setFilePath(localFilePath) + return request + + def __rewriteM3u8File(self, srcM3u8File, dstM3u8File, isSrcLocal=True): + newM3u8Text = '' + if isSrcLocal: + for line in open(AliyunVodUtils.toUnicode(srcM3u8File)): + item = self.__processM3u8Line(line) + if item is not None: + newM3u8Text += item + "\n" + else: + res = requests.get(srcM3u8File) + res.raise_for_status() + for line in res.iter_lines(): + item = self.__processM3u8Line(line) + if item is not None: + newM3u8Text += item + "\n" + + AliyunVodUtils.mkDir(dstM3u8File) + with open(dstM3u8File, 'w') as f: + f.write(newM3u8Text) + + def __processM3u8Line(self, line): + item = line.strip() + if len(item) <= 0: + return None + + if item.startswith('#'): + return item + + tempFilePath, fileName = AliyunVodUtils.getFileBriefPath(item) + return fileName + + def __requestUploadInfo(self, request, mediaType): + request.set_accept_format('JSON') + result = json.loads(self.__vodClient.do_action_with_exception(request).decode('utf-8')) + result['OriUploadAddress'] = result['UploadAddress'] + result['OriUploadAuth'] = result['UploadAuth'] + + result['UploadAddress'] = json.loads(base64.b64decode(result['OriUploadAddress']).decode('utf-8')) + result['UploadAuth'] = json.loads(base64.b64decode(result['OriUploadAuth']).decode('utf-8')) + + result['MediaType'] = mediaType + if mediaType == 'video': + result['MediaId'] = result['VideoId'] + elif mediaType == 'image': + result['MediaId'] = result['ImageId'] + result['MediaURL'] = result['ImageURL'] + return result + + # 获取视频上传地址和凭证 + def __createUploadVideo(self, uploadVideoRequest): + request = CreateUploadVideoRequest.CreateUploadVideoRequest() + title = AliyunVodUtils.subString(uploadVideoRequest.title, VOD_MAX_TITLE_LENGTH) + request.set_Title(title) + request.set_FileName(uploadVideoRequest.fileName) + + if uploadVideoRequest.description: + description = AliyunVodUtils.subString(uploadVideoRequest.description, VOD_MAX_DESCRIPTION_LENGTH) + request.set_Description(description) + if uploadVideoRequest.coverURL: + request.set_CoverURL(uploadVideoRequest.coverURL) + if uploadVideoRequest.tags: + request.set_Tags(uploadVideoRequest.tags) + if uploadVideoRequest.cateId: + request.set_CateId(uploadVideoRequest.cateId) + if uploadVideoRequest.templateGroupId: + request.set_TemplateGroupId(uploadVideoRequest.templateGroupId) + if uploadVideoRequest.storageLocation: + request.set_StorageLocation(uploadVideoRequest.storageLocation) + if uploadVideoRequest.userData: + request.set_UserData(uploadVideoRequest.userData) + if uploadVideoRequest.appId: + request.set_AppId(uploadVideoRequest.appId) + if uploadVideoRequest.workflowId: + request.set_WorkflowId(uploadVideoRequest.workflowId) + # 根据request发送请求阿里云 + result = self.__requestUploadInfo(request, 'video') + # logger.info("CreateUploadVideo, 获取响应体: {}, requestId:{}", result, self.__requestId) + logger.info("CreateUploadVideo, FilePath: {}, VideoId: {}, requestId:{}", uploadVideoRequest.filePath, + result['VideoId'], self.__requestId) + return result + + # 刷新上传凭证 + def __refresh_upload_video(self, videoId): + request = RefreshUploadVideoRequest.RefreshUploadVideoRequest(); + request.set_VideoId(videoId) + + result = self.__requestUploadInfo(request, 'video') + logger.info("RefreshUploadVideo, VideoId:{}, requestId:{}", result['VideoId'], self.__requestId) + return result + + # 获取图片上传地址和凭证 + def __createUploadImage(self, uploadImageRequest): + request = CreateUploadImageRequest.CreateUploadImageRequest() + + request.set_ImageType(uploadImageRequest.imageType) + request.set_ImageExt(uploadImageRequest.imageExt) + if uploadImageRequest.title: + title = AliyunVodUtils.subString(uploadImageRequest.title, VOD_MAX_TITLE_LENGTH) + request.set_Title(title) + if uploadImageRequest.description: + description = AliyunVodUtils.subString(uploadImageRequest.description, VOD_MAX_DESCRIPTION_LENGTH) + request.set_Description(description) + if uploadImageRequest.tags: + request.set_Tags(uploadImageRequest.tags) + if uploadImageRequest.cateId: + request.set_CateId(uploadImageRequest.cateId) + if uploadImageRequest.storageLocation: + request.set_StorageLocation(uploadImageRequest.storageLocation) + if uploadImageRequest.userData: + request.set_UserData(uploadImageRequest.userData) + if uploadImageRequest.appId: + request.set_AppId(uploadImageRequest.appId) + if uploadImageRequest.workflowId: + request.set_WorkflowId(uploadImageRequest.workflowId) + + result = self.__requestUploadInfo(request, 'image') + logger.info("CreateUploadImage, FilePath: %s, ImageId: %s, ImageUrl: %s" % ( + uploadImageRequest.filePath, result['ImageId'], result['ImageURL'])) + return result + + def __createUploadAttachedMedia(self, uploadAttachedRequest): + request = CreateUploadAttachedMediaRequest.CreateUploadAttachedMediaRequest() + request.set_BusinessType(uploadAttachedRequest.businessType) + request.set_MediaExt(uploadAttachedRequest.mediaExt) + + if uploadAttachedRequest.title: + title = AliyunVodUtils.subString(uploadAttachedRequest.title, VOD_MAX_TITLE_LENGTH) + request.set_Title(title) + if uploadAttachedRequest.description: + description = AliyunVodUtils.subString(uploadAttachedRequest.description, VOD_MAX_DESCRIPTION_LENGTH) + request.set_Description(description) + if uploadAttachedRequest.tags: + request.set_Tags(uploadAttachedRequest.tags) + if uploadAttachedRequest.cateId: + request.set_CateId(uploadAttachedRequest.cateId) + if uploadAttachedRequest.storageLocation: + request.set_StorageLocation(uploadAttachedRequest.storageLocation) + if uploadAttachedRequest.userData: + request.set_UserData(uploadAttachedRequest.userData) + if uploadAttachedRequest.appId: + request.set_AppId(uploadAttachedRequest.appId) + if uploadAttachedRequest.workflowId: + request.set_WorkflowId(uploadAttachedRequest.workflowId) + + result = self.__requestUploadInfo(request, 'attached') + logger.info("CreateUploadImage, FilePath: %s, MediaId: %s, MediaURL: %s" % ( + uploadAttachedRequest.filePath, result['MediaId'], result['MediaURL'])) + return result + + def __getUploadHeaders(self, uploadVideoRequest): + if uploadVideoRequest.isShowWatermark is None: + return None + else: + userData = "{\"Vod\":{\"UserData\":{\"IsShowWaterMark\": \"%s\"}}}" % (uploadVideoRequest.isShowWatermark) + return {'x-oss-notification': base64.b64encode(userData, 'utf-8')} + + # uploadType,可选:multipart, put, web + def __uploadOssObjectWithRetry(self, filePath, object, uploadInfo, headers=None): + retryTimes = 0 + while retryTimes < self.__maxRetryTimes: + try: + return self.__uploadOssObject(filePath, object, uploadInfo, headers) + except OssError as e: + # 上传凭证过期需要重新获取凭证 + if e.code == 'SecurityTokenExpired' or e.code == 'InvalidAccessKeyId': + uploadInfo = self.__refresh_upload_video(uploadInfo['MediaId']) + except Exception as e: + raise e + except: + raise AliyunVodException('UnkownError', repr(e), traceback.format_exc()) + finally: + retryTimes += 1 + else: + raise Exception("重试超过限制") + + def __uploadOssObject(self, filePath, object, uploadInfo, headers=None): + self.__createOssClient(uploadInfo['UploadAuth'], uploadInfo['UploadAddress']) + """ + p = os.path.dirname(os.path.realpath(__file__)) + store = os.path.dirname(p) + '/osstmp' + return oss2.resumable_upload(self.__bucketClient, object, filePath, + store=oss2.ResumableStore(root=store), headers=headers, + multipart_threshold=self.__multipartThreshold, part_size=self.__multipartPartSize, + num_threads=self.__multipartThreadsNum, progress_callback=self.uploadProgressCallback) + """ + uploader = _VodResumableUploader(self.__bucketClient, filePath, object, uploadInfo, headers, + self.uploadProgressCallback, self.__refreshUploadAuth, + requestId=self.__requestId) + uploader.setMultipartInfo(self.__multipartThreshold, self.__multipartPartSize, self.__multipartThreadsNum) + uploader.setClientId(self.__accessKeyId) + res = uploader.upload() + + uploadAddress = uploadInfo['UploadAddress'] + bucketHost = uploadAddress['Endpoint'].replace('://', '://' + uploadAddress['Bucket'] + ".") + logger.info("UploadFile {} Finish, MediaId: {}, FilePath: {}, Destination: {}/{}, requestId:{}", + uploadInfo['MediaType'], uploadInfo['MediaId'], filePath, bucketHost, object, self.__requestId) + return res + + # 使用上传凭证和地址信息初始化OSS客户端(注意需要先Base64解码并Json Decode再传入) + # 如果上传的ECS位于点播相同的存储区域(如上海),则可以指定internal为True,通过内网上传更快且免费 + def __createOssClient(self, uploadAuth, uploadAddress): + auth = oss2.StsAuth(uploadAuth['AccessKeyId'], uploadAuth['AccessKeySecret'], uploadAuth['SecurityToken']) + endpoint = AliyunVodUtils.convertOssInternal(uploadAddress['Endpoint'], self.__ecsRegion) + self.__bucketClient = oss2.Bucket(auth, endpoint, uploadAddress['Bucket'], + connect_timeout=self.__connTimeout, enable_crc=self.__EnableCrc) + return self.__bucketClient + + def __refreshUploadAuth(self, videoId): + uploadInfo = self.__refresh_upload_video(videoId) + uploadAuth = uploadInfo['UploadAuth'] + uploadAddress = uploadInfo['UploadAddress'] + return self.__createOssClient(uploadAuth, uploadAddress) + + +from oss2 import SizedFileAdapter, determine_part_size +from oss2.models import PartInfo +from aliyunsdkcore.utils import parameter_helper as helper + + +class _VodResumableUploader: + def __init__(self, bucket, filePath, object, uploadInfo, headers, progressCallback, refreshAuthCallback, + requestId=None): + self.__bucket = bucket + self.__filePath = filePath + self.__object = object + self.__uploadInfo = uploadInfo + self.__totalSize = None + self.__headers = headers + self.__mtime = os.path.getmtime(filePath) + self.__progressCallback = progressCallback + self.__refreshAuthCallback = refreshAuthCallback + + self.__threshold = None + self.__partSize = None + self.__threadsNum = None + self.__uploadId = 0 + + self.__record = {} + self.__finishedSize = 0 + self.__finishedParts = [] + self.__filePartHash = None + self.__clientId = None + self.__requestId = requestId + + def setMultipartInfo(self, threshold, partSize, threadsNum): + self.__threshold = threshold + self.__partSize = partSize + self.__threadsNum = threadsNum + + def setClientId(self, clientId): + self.__clientId = clientId + + def upload(self): + self.__totalSize = os.path.getsize(self.__filePath) + logger.info("上传视频路径: {}, 视频大小: {}, requestId:{}", self.__filePath, self.__totalSize, self.__requestId) + if self.__threshold and self.__totalSize <= self.__threshold: + return self.simpleUpload() + else: + return self.multipartUpload() + + def simpleUpload(self): + with open(AliyunVodUtils.toUnicode(self.__filePath), 'rb') as f: + result = self.__bucket.put_object(self.__object, f, headers=self.__headers, progress_callback=None) + if self.__uploadInfo['MediaType'] == 'video': + self.__reportUploadProgress('put', 1, self.__totalSize) + + return result + + def multipartUpload(self): + psize = oss2.determine_part_size(self.__totalSize, preferred_size=self.__partSize) + + # 初始化分片 + self.__uploadId = self.__bucket.init_multipart_upload(self.__object).upload_id + + startTime = time.time() + expireSeconds = 2500 # 上传凭证有效期3000秒,提前刷新 + # 逐个上传分片 + with open(AliyunVodUtils.toUnicode(self.__filePath), 'rb') as fileObj: + partNumber = 1 + offset = 0 + + while offset < self.__totalSize: + uploadSize = min(psize, self.__totalSize - offset) + # logger.info("UploadPart, FilePath: %s, VideoId: %s, UploadId: %s, PartNumber: %s, PartSize: %s" % (self.__fileName, self.__videoId, self.__uploadId, partNumber, uploadSize)) + result = self.__upload_part(partNumber, fileObj, uploadSize) + # print(result.request_id) + self.__finishedParts.append(PartInfo(partNumber, result.etag)) + offset += uploadSize + partNumber += 1 + + # 上传进度回调 + self.__progressCallback(offset, self.__totalSize) + + if self.__uploadInfo['MediaType'] == 'video': + # 上报上传进度 + self.__reportUploadProgress('multipart', partNumber - 1, offset) + # 检测上传凭证是否过期 + nowTime = time.time() + if nowTime - startTime >= expireSeconds: + self.__bucket = self.__refreshAuthCallback(self.__uploadInfo['MediaId']) + startTime = nowTime + + # 完成分片上传 + self.__complete_multipart_upload() + return result + + def __upload_part(self, partNumber, fileObj, uploadSize): + retry_num = 0 + while True: + try: + return self.__bucket.upload_part(self.__object, self.__uploadId, partNumber, + SizedFileAdapter(fileObj, uploadSize)) + except Exception as e: + logger.error("阿里云分片上传异常报错: {}, 当前重试次数:{} requestId:{}", str(e), retry_num + 1, self.__requestId) + if retry_num > 3: + raise Exception("阿里云分片上传异常") + except: + logger.error("阿里云完成分片上传异常报错, 当前重试次数:{}, requestId:{}", retry_num + 1, self.__requestId) + if retry_num > 3: + raise Exception("阿里云分片上传异常") + finally: + retry_num += 1 + time.sleep(1) + + def __complete_multipart_upload(self): + retry_num = 0 + while True: + try: + self.__bucket.complete_multipart_upload(self.__object, self.__uploadId, self.__finishedParts, + headers=self.__headers) + break + except Exception as e: + logger.error("阿里云完成分片上传异常报错: {}, 当前重试次数:{}, requestId:{}", str(e), retry_num + 1, self.__requestId) + if retry_num > 5: + raise Exception("阿里云完成分片上传异常") + except: + logger.error("阿里云完成分片上传异常报错, 当前重试次数:{}, requestId:{}", retry_num + 1, self.__requestId) + if retry_num > 5: + raise Exception("阿里云完成分片上传异常") + finally: + time.sleep(1) + retry_num += 1 + + def __reportUploadProgress(self, uploadMethod, donePartsCount, doneBytes): + retry_num = 5 + current_num = 0 + while True: + try: + reportHost = 'vod.cn-shanghai.aliyuncs.com' + sdkVersion = '1.3.1' + reportKey = 'HBL9nnSwhtU2$STX' + + uploadPoint = {'upMethod': uploadMethod, 'partSize': self.__partSize, 'doneBytes': doneBytes} + timestamp = int(time.time()) + authInfo = AliyunVodUtils.getStringMd5("%s|%s|%s" % (self.__clientId, reportKey, timestamp)) + + fields = {'Action': 'ReportUploadProgress', 'Format': 'JSON', 'Version': '2017-03-21', + 'Timestamp': helper.get_iso_8061_date(), 'SignatureNonce': helper.get_uuid(), + 'VideoId': self.__uploadInfo['MediaId'], 'Source': 'PythonSDK', 'ClientId': self.__clientId, + 'BusinessType': 'UploadVideo', 'TerminalType': 'PC', 'DeviceModel': 'Server', + 'AppVersion': sdkVersion, 'AuthTimestamp': timestamp, 'AuthInfo': authInfo, + + 'FileName': self.__filePath, + 'FileHash': self.__getFilePartHash(self.__clientId, self.__filePath, self.__totalSize), + 'FileSize': self.__totalSize, 'FileCreateTime': timestamp, 'UploadRatio': 0, + 'UploadId': self.__uploadId, + 'DonePartsCount': donePartsCount, 'PartSize': self.__partSize, + 'UploadPoint': json.dumps(uploadPoint), + 'UploadAddress': self.__uploadInfo['OriUploadAddress'] + } + requests.post('http://' + reportHost, fields, timeout=30) + break + except Exception as e: + current_num += 1 + time.sleep(1) + logger.error("vod上报视频进度异常: {}, 当前重试次数:{}, requestId:{}", repr(e), current_num, + self.__requestId) + if current_num > retry_num: + logger.error("vod上报视频重试失败 {}, requestId:{}", repr(e), self.__requestId) + raise e + + def __getFilePartHash(self, clientId, filePath, fileSize): + if self.__filePartHash: + return self.__filePartHash + + length = 1 * 1024 * 1024 + if fileSize < length: + length = fileSize + + try: + fp = open(AliyunVodUtils.toUnicode(filePath), 'rb') + strVal = fp.read(length) + self.__filePartHash = AliyunVodUtils.getStringMd5(strVal, False) + fp.close() + except: + self.__filePartHash = "%s|%s|%s" % (clientId, filePath, self.__mtime) + + return self.__filePartHash diff --git a/vodsdk/AliyunVodUtils.py b/vodsdk/AliyunVodUtils.py new file mode 100644 index 0000000..a2f2c81 --- /dev/null +++ b/vodsdk/AliyunVodUtils.py @@ -0,0 +1,327 @@ +# -*- coding: UTF-8 -*- +import os, sys +import hashlib +import datetime +import functools +import logging +from loguru import logger +from oss2.exceptions import OssError +from aliyunsdkcore.acs_exception.exceptions import ServerException +from aliyunsdkcore.acs_exception.exceptions import ClientException +import traceback +import requests + +if sys.version_info[0] == 3: + import urllib.parse +else: + from urllib import unquote + +VOD_PRINT_INFO_LOG_SWITCH = 1 + + +class AliyunVodLog: + """ + VOD日志类,基于logging实现 + """ + + @staticmethod + def printLogStr(msg, *args, **kwargs): + if VOD_PRINT_INFO_LOG_SWITCH: + print("[%s]%s" % (AliyunVodUtils.getCurrentTimeStr(), msg)) + + @staticmethod + def info(msg, *args, **kwargs): + logging.info(msg, *args, **kwargs) + AliyunVodLog.printLogStr(msg, *args, **kwargs) + + @staticmethod + def error(msg, *args, **kwargs): + logging.error(msg, *args, **kwargs) + AliyunVodLog.printLogStr(msg, *args, **kwargs) + + @staticmethod + def warning(msg, *args, **kwargs): + logging.warning(msg, *args, **kwargs) + AliyunVodLog.printLogStr(msg, *args, **kwargs) + + +class AliyunVodUtils: + """ + VOD上传SDK的工具类,提供截取字符串、获取扩展名、获取文件名等静态函数 + """ + + # 截取字符串,在不超过最大字节数前提下确保中文字符不被截断出现乱码(先转换成unicode,再取子串,然后转换成utf-8) + @staticmethod + def subString(strVal, maxBytes, charSet='utf-8'): + i = maxBytes + if sys.version_info[0] == 3: + while len(strVal.encode(charSet)) > maxBytes: + if i < 0: + return '' + strVal = strVal[:i] + i -= 1 + else: + while len(strVal) > maxBytes: + if i < 0: + return '' + strVal = strVal.decode(charSet)[:i].encode(charSet) + i -= 1 + return strVal + + @staticmethod + def getFileExtension(fileName): + end = fileName.rfind('?') + if end <= 0: + end = len(fileName) + + i = fileName.rfind('.') + if i >= 0: + return fileName[i + 1:end].lower() + else: + return None + + # urldecode + @staticmethod + def urlDecode(fileUrl): + if sys.version_info[0] == 3: + return urllib.parse.unquote(fileUrl) + else: + return unquote(fileUrl) + + # urlencode + @staticmethod + def urlEncode(fileUrl): + if sys.version_info[0] == 3: + return urllib.parse.urlencode(fileUrl) + else: + return urllib.urlencode(fileUrl) + + # 获取Url的摘要地址(去除?后的参数,如果有)以及文件名 + @staticmethod + def getFileBriefPath(fileUrl): + # fileUrl = AliyunVodUtils.urlDecode(fileUrl) + i = fileUrl.rfind('?') + if i > 0: + briefPath = fileUrl[:i] + else: + briefPath = fileUrl + + briefName = os.path.basename(briefPath) + return briefPath, AliyunVodUtils.urlDecode(briefName) + + @staticmethod + def getStringMd5(strVal, isEncode=True): + m = hashlib.md5() + m.update(strVal.encode('utf-8') if isEncode else strVal) + return m.hexdigest() + + @staticmethod + def getCurrentTimeStr(): + now = datetime.datetime.now() + return now.strftime("%Y-%m-%d %H:%M:%S") + + # 将oss地址转换为内网地址(如果脚本部署的ecs与oss bucket在同一区域) + @staticmethod + def convertOssInternal(ossUrl, ecsRegion=None, isVpc=False): + if (not ossUrl) or (not ecsRegion): + return ossUrl + + availableRegions = ['cn-qingdao', 'cn-beijing', 'cn-zhangjiakou', 'cn-huhehaote', 'cn-hangzhou', 'cn-shanghai', + 'cn-shenzhen', + 'cn-hongkong', 'ap-southeast-1', 'ap-southeast-2', 'ap-southeast-3', + 'ap-northeast-1', 'us-west-1', 'us-east-1', 'eu-central-1', 'me-east-1'] + if ecsRegion not in availableRegions: + return ossUrl + + ossUrl = ossUrl.replace("https:", "http:") + if isVpc: + return ossUrl.replace("oss-%s.aliyuncs.com" % (ecsRegion), "vpc100-oss-%s.aliyuncs.com" % (ecsRegion)) + else: + return ossUrl.replace("oss-%s.aliyuncs.com" % (ecsRegion), "oss-%s-internal.aliyuncs.com" % (ecsRegion)) + + # 把输入转换为unicode + @staticmethod + def toUnicode(data): + if isinstance(data, bytes): + return data.decode('utf-8') + else: + return data + + # 替换路径中的文件名;考虑分隔符为"/" 或 "\"(windows) + @staticmethod + def replaceFileName(filePath, replace): + if len(filePath) <= 0 or len(replace) <= 0: + return filePath + + filePath = AliyunVodUtils.urlDecode(filePath) + separator = '/' + start = filePath.rfind(separator) + if start < 0: + separator = '\\' + start = filePath.rfind(separator) + if start < 0: + return None + + result = "%s%s%s" % (filePath[0:start], separator, replace) + return result + + # 创建文件中的目录 + @staticmethod + def mkDir(filePath): + if len(filePath) <= 0: + return -1 + + separator = '/' + i = filePath.rfind(separator) + if i < 0: + separator = '\\' + i = filePath.rfind(separator) + if i < 0: + return -2 + + dirs = filePath[:i] + if os.path.exists(dirs) and os.path.isdir(dirs): + return 0 + + os.makedirs(dirs) + return 1 + + +class AliyunVodException(Exception): + """ + VOD上传SDK的异常类,做统一的异常处理,外部捕获此异常即可 + """ + + def __init__(self, type, code, msg, http_status=None, request_id=None): + Exception.__init__(self) + self.type = type or 'UnkownError' + self.code = code + self.message = msg + self.http_status = http_status or 'NULL' + self.request_id = request_id or 'NULL' + + def __str__(self): + return "Type: %s, Code: %s, Message: %s, HTTPStatus: %s, RequestId: %s" % ( + self.type, self.code, self.message, str(self.http_status), self.request_id) + + +def catch_error(method): + """ + 装饰器,将内部异常转换成统一的异常类AliyunVodException + """ + + @functools.wraps(method) + def wrapper(self, *args, **kwargs): + try: + return method(self, *args, **kwargs) + except ServerException as e: + logger.error("阿里云ServerException异常, error_code: {}, error_msg:{}, status:{}, requestId:{}", + e.get_error_code(), e.get_error_msg(), e.get_http_status(), self.__requestId) + # 可能原因:AK错误、账号无权限、参数错误等 + raise AliyunVodException('ServerException', e.get_error_code(), e.get_error_msg(), e.get_http_status(), + e.get_request_id()) + except ClientException as e: + logger.error("阿里云ClientException异常, error_code: {}, error_msg:{}, requestId:{}", e.get_error_code(), + e.get_error_msg(), self.__requestId) + # 可能原因:本地网络故障(如不能连接外网)等 + raise AliyunVodException('ClientException', e.get_error_code(), e.get_error_msg()) + except OssError as e: + logger.error("阿里云OssError异常, error_code: {}, error_msg:{}, status:{}, requestId:{}", e.code, e.message, + e.status, self.__requestId) + # 可能原因:上传凭证过期等 + raise AliyunVodException('OssError', e.code, e.message, e.status, e.request_id) + except IOError as e: + logger.error("阿里云IOError异常: {}, requestId:{}", traceback.format_exc(), self.__requestId) + # 可能原因:文件URL不能访问、本地文件无法读取等 + raise AliyunVodException('IOError', repr(e), traceback.format_exc()) + except OSError as e: + logger.error("阿里云OSError异常: {}, requestId:{}", traceback.format_exc(), self.__requestId) + # 可能原因:本地文件不存在等 + raise AliyunVodException('OSError', repr(e), traceback.format_exc()) + except AliyunVodException as e: + logger.error("阿里云VodException异常: {}, requestId:{}", e, self.__requestId) + # 可能原因:参数错误 + raise e + except Exception as e: + logger.error("阿里云UnkownException异常: {}, requestId:{}", traceback.format_exc(), self.__requestId) + raise AliyunVodException('UnkownException', repr(e), traceback.format_exc()) + except: + logger.error("阿里云UnkownError异常: {}, requestId:{}", traceback.format_exc(), self.__requestId) + raise AliyunVodException('UnkownError', 'UnkownError', traceback.format_exc()) + return wrapper + + +class AliyunVodDownloader: + """ + VOD网络文件的下载类,上传网络文件时会先下载到本地临时目录,再上传到点播 + """ + + def __init__(self, localDir=None): + if localDir: + self.__localDir = localDir + else: + p = os.path.dirname(os.path.realpath(__file__)) + self.__localDir = os.path.dirname(p) + '/dlfiles' + + def setSaveLocalDir(self, localDir): + self.__localDir = localDir + + def getSaveLocalDir(self): + return self.__localDir + + def downloadFile(self, fileUrl, localFileName, fileSize=None): + localPath = self.__localDir + '/' + localFileName + logger.info("Download %s To %s" % (fileUrl, localPath)) + try: + lsize = self.getFileSize(localPath) + if fileSize and lsize == fileSize: + logger.info('Download OK, File Exists') + return 0, localPath + + AliyunVodUtils.mkDir(self.__localDir) + + err, webPage = self.__openWebFile(fileUrl, lsize) + if err == 0: + logger.info('Download OK, File Exists') + webPage.close() + return 0, localPath + + fileObj = open(localPath, 'ab+') + for chunk in webPage.iter_content(chunk_size=8 * 1024): + if chunk: + fileObj.write(chunk) + except Exception as e: + logger.error("Download fail: %s" % (e)) + return -1, None + + fileObj.close() + webPage.close() + logger.info('Download OK') + return 1, localPath + + def getFileSize(self, filePath): + try: + lsize = os.stat(filePath).st_size + except: + lsize = 0 + + return lsize + + def __openWebFile(self, fileUrl, offset): + webPage = None + try: + headers = {'Range': 'bytes=%d-' % offset} + webPage = requests.get(fileUrl, stream=True, headers=headers, timeout=120, verify=False) + status_code = webPage.status_code + err = -1 + if status_code in [200, 206]: + err = 1 + elif status_code == 416: + err = 0 + else: + logger.error("Download offset %s fail, invalid url, status: %s" % (offset, status_code)) + except Exception as e: + logger.error("Download offset %s fail: %s" % (offset, e)) + err = -2 + finally: + return err, webPage diff --git a/vodsdk/UploadAttachedMediaRequest.py b/vodsdk/UploadAttachedMediaRequest.py new file mode 100644 index 0000000..02ff996 --- /dev/null +++ b/vodsdk/UploadAttachedMediaRequest.py @@ -0,0 +1,87 @@ +# -*- coding: UTF-8 -*- +""" + # Class UploadAttachedMediaRequest + # + # Aliyun VoD's Upload Attached Media(such as watermark,subtitle files) Request class, which wraps parameters to upload an media file into VoD. + # Users could pass parameters to AliyunVodUploader, including File Path,Title,etc. via an UploadAttachedMediaRequest instance. + # For more details, please check out the VoD API document: https://help.aliyun.com/document_detail/98467.html +""" + +from vodsdk.AliyunVodUtils import * +class UploadAttachedMediaRequest: + def __init__(self, filePath, businessType, title=None, fileExt=None): + """ + constructor for UploadAttachedMediaRequest + :param filePath: string, 文件的绝对路径,或者网络文件的URL,必须含有扩展名 + :return + """ + self.businessType = businessType + self.filePath = None + self.fileName = None + self.mediaExt = None + self.title = None + self.setFilePath(filePath, title, fileExt) + + self.fileSize = None + self.cateId = None + self.tags = None + self.description = None + self.userData = None + self.storageLocation = None + self.appId = None + self.workflowId = None + + + def setFilePath(self, filePath, title=None, fileExt=None): + if fileExt is None: + fileExt = AliyunVodUtils.getFileExtension(filePath) + if not fileExt: + raise AliyunVodException('ParameterError', 'InvalidParameter', 'filePath has no Extension') + + fileExt = fileExt.lstrip('.') + self.mediaExt = fileExt + self.filePath = AliyunVodUtils.toUnicode(filePath) + + briefPath, briefName = AliyunVodUtils.getFileBriefPath(self.filePath) + self.fileName = briefPath + if fileExt and (not self.fileName.endswith('.' + fileExt)): + self.fileName = self.fileName + '.' + fileExt + + if title: + self.title = title + else: + if self.title is None: + self.title = briefName + + + def setBusinessType(self, businessType): + self.businessType = businessType + + def setTitle(self, title): + self.title = title + + def setFileSize(self, fileSize): + self.fileSize = fileSize + + def setCateId(self, cateId): + self.cateId = cateId + + def setTags(self, tags): + self.tags = tags + + def setDescription(self, description): + self.description = description + + def setStorageLocation(self, storageLocation): + self.storageLocation = storageLocation + + def setUserData(self, userData): + self.userData = userData + + def setAppId(self, appId): + self.appId = appId + + def setWorkflowId(self, workflowId): + self.workflowId = workflowId + + diff --git a/vodsdk/UploadImageRequest.py b/vodsdk/UploadImageRequest.py new file mode 100644 index 0000000..31bc317 --- /dev/null +++ b/vodsdk/UploadImageRequest.py @@ -0,0 +1,84 @@ +# -*- coding: UTF-8 -*- +""" + # Class UploadImageRequest + # + # Aliyun VoD's Upload Image Request class, which wraps parameters to upload an image into VoD. + # Users could pass parameters to AliyunVodUploader, including File Path,Title,etc. via an UploadImageRequest instance. + # For more details, please check out the VoD API document: https://help.aliyun.com/document_detail/55619.html +""" + +from vodsdk.AliyunVodUtils import * +class UploadImageRequest: + def __init__(self, filePath, title=None, fileExt=None): + """ + constructor for UploadVideoRequest + :param filePath: string, 文件的绝对路径,或者网络文件的URL,必须含有扩展名 + :param title: string, 图片标题 + :return + """ + self.filePath = None + self.fileName = None + self.imageExt = None + self.mediaExt = None + self.title = None + self.setFilePath(filePath, title, fileExt) + + self.imageType = 'default' + self.cateId = None + self.tags = None + self.description = None + self.userData = None + self.storageLocation = None + self.appId = None + self.workflowId = None + + def setFilePath(self, filePath, title=None, fileExt=None): + if fileExt is None: + fileExt = AliyunVodUtils.getFileExtension(filePath) + if not fileExt: + raise AliyunVodException('ParameterError', 'InvalidParameter', 'filePath has no Extension') + + fileExt = fileExt.lstrip('.') + self.imageExt = fileExt + self.mediaExt = fileExt + self.filePath = AliyunVodUtils.toUnicode(filePath) + + briefPath, briefName = AliyunVodUtils.getFileBriefPath(self.filePath) + self.fileName = briefPath + + if fileExt and (not self.fileName.endswith('.' + fileExt)): + self.fileName = self.fileName + '.' + fileExt + + if title: + self.title = title + else: + if self.title is None: + self.title = briefName + + + def setImageType(self, imageType): + self.imageType = imageType + + def setTitle(self, title): + self.title = title + + def setCateId(self, cateId): + self.cateId = cateId + + def setTags(self, tags): + self.tags = tags + + def setDescription(self, description): + self.description = description + + def setStorageLocation(self, storageLocation): + self.storageLocation = storageLocation + + def setUserData(self, userData): + self.userData = userData + + def setAppId(self, appId): + self.appId = appId + + def setWorkflowId(self, workflowId): + self.workflowId = workflowId diff --git a/vodsdk/UploadVideoRequest.py b/vodsdk/UploadVideoRequest.py new file mode 100644 index 0000000..665acd1 --- /dev/null +++ b/vodsdk/UploadVideoRequest.py @@ -0,0 +1,86 @@ +# -*- coding: UTF-8 -*- +""" + # Class UploadVideoRequest + # + # Aliyun VoD's Upload Video Request class, which wraps parameters to upload a video into VoD. + # Users could pass parameters to AliyunVodUploader, including File Path,Title,etc. via an UploadVideoRequest instance. + # For more details, please check out the VoD API document: https://help.aliyun.com/document_detail/55407.html +""" + +from vodsdk.AliyunVodUtils import * +class UploadVideoRequest: + def __init__(self, filePath, title=None, fileExt=None): + """ + constructor for UploadVideoRequest + :param filePath: string, 文件的绝对路径,或者网络文件的URL,必须含有扩展名 + :param title: string, 视频标题,最长128字节,不传则使用文件名为标题 + :return + """ + self.filePath = None + self.fileName = None + self.mediaExt = None + self.title = None + self.setFilePath(filePath, title, fileExt) + + self.cateId = None + self.tags = None + self.description = None + self.coverURL = None + self.templateGroupId = None + self.isShowWatermark = None + self.userData = None + self.storageLocation = None + self.uploadId = None + self.appId = None + self.workflowId = None + + def setFilePath(self, filePath, title=None, fileExt=None): + if fileExt is None: + fileExt = AliyunVodUtils.getFileExtension(filePath) + if not fileExt: + raise AliyunVodException('ParameterError', 'InvalidParameter', 'filePath has no Extension') + + fileExt = fileExt.lstrip('.') + self.mediaExt = fileExt + self.filePath = AliyunVodUtils.toUnicode(filePath) + + briefPath, briefName = AliyunVodUtils.getFileBriefPath(self.filePath) + self.fileName = briefPath + if fileExt and (not self.fileName.endswith('.' + fileExt)): + self.fileName = self.fileName + '.' + fileExt + + if title: + self.title = title + else: + if self.title is None: + self.title = briefName + + + def setCateId(self, cateId): + self.cateId = cateId + + def setTags(self, tags): + self.tags = tags + + def setDescription(self, description): + self.description = description + + def setCoverURL(self, coverURL): + self.coverURL = coverURL + + def setTemplateGroupId(self, templateGroupId): + self.templateGroupId = templateGroupId + + # 关闭水印,仅用于配置全局水印且转码模板开启水印后,单次上传时关闭水印 + def shutdownWatermark(self): + self.isShowWatermark = False + + # 设置上传ID,可用于关联导入视频 + def setUploadId(self, uploadId): + self.uploadId = uploadId + + def setAppId(self, appId): + self.appId = appId + + def setWorkflowId(self, workflowId): + self.workflowId = workflowId diff --git a/vodsdk/__init__.py b/vodsdk/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/__pycache__/AliyunVodUploader.cpython-38.pyc b/vodsdk/__pycache__/AliyunVodUploader.cpython-38.pyc new file mode 100644 index 0000000..167880d Binary files /dev/null and b/vodsdk/__pycache__/AliyunVodUploader.cpython-38.pyc differ diff --git a/vodsdk/__pycache__/AliyunVodUtils.cpython-38.pyc b/vodsdk/__pycache__/AliyunVodUtils.cpython-38.pyc new file mode 100644 index 0000000..b78b4d4 Binary files /dev/null and b/vodsdk/__pycache__/AliyunVodUtils.cpython-38.pyc differ diff --git a/vodsdk/__pycache__/UploadVideoRequest.cpython-38.pyc b/vodsdk/__pycache__/UploadVideoRequest.cpython-38.pyc new file mode 100644 index 0000000..2cdc099 Binary files /dev/null and b/vodsdk/__pycache__/UploadVideoRequest.cpython-38.pyc differ diff --git a/vodsdk/__pycache__/__init__.cpython-38.pyc b/vodsdk/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..c7b9f43 Binary files /dev/null and b/vodsdk/__pycache__/__init__.cpython-38.pyc differ diff --git a/vodsdk/__pycache__/dsp_master.cpython-38.pyc b/vodsdk/__pycache__/dsp_master.cpython-38.pyc new file mode 100644 index 0000000..ae39e3b Binary files /dev/null and b/vodsdk/__pycache__/dsp_master.cpython-38.pyc differ diff --git a/vodsdk/common/Constant.py b/vodsdk/common/Constant.py new file mode 100644 index 0000000..c147670 --- /dev/null +++ b/vodsdk/common/Constant.py @@ -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}$' + } + } +} diff --git a/vodsdk/common/YmlConstant.py b/vodsdk/common/YmlConstant.py new file mode 100644 index 0000000..eecc780 --- /dev/null +++ b/vodsdk/common/YmlConstant.py @@ -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' diff --git a/vodsdk/common/__init__.py b/vodsdk/common/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/common/__pycache__/Constant.cpython-310.pyc b/vodsdk/common/__pycache__/Constant.cpython-310.pyc new file mode 100644 index 0000000..d164c38 Binary files /dev/null and b/vodsdk/common/__pycache__/Constant.cpython-310.pyc differ diff --git a/vodsdk/common/__pycache__/Constant.cpython-38.pyc b/vodsdk/common/__pycache__/Constant.cpython-38.pyc new file mode 100644 index 0000000..73d6a84 Binary files /dev/null and b/vodsdk/common/__pycache__/Constant.cpython-38.pyc differ diff --git a/vodsdk/common/__pycache__/YmlConstant.cpython-38.pyc b/vodsdk/common/__pycache__/YmlConstant.cpython-38.pyc new file mode 100644 index 0000000..30975e0 Binary files /dev/null and b/vodsdk/common/__pycache__/YmlConstant.cpython-38.pyc differ diff --git a/vodsdk/common/__pycache__/__init__.cpython-310.pyc b/vodsdk/common/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..58366ca Binary files /dev/null and b/vodsdk/common/__pycache__/__init__.cpython-310.pyc differ diff --git a/vodsdk/common/__pycache__/__init__.cpython-38.pyc b/vodsdk/common/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..03bd997 Binary files /dev/null and b/vodsdk/common/__pycache__/__init__.cpython-38.pyc differ diff --git a/vodsdk/concurrency/CommonThread.py b/vodsdk/concurrency/CommonThread.py new file mode 100644 index 0000000..efcf548 --- /dev/null +++ b/vodsdk/concurrency/CommonThread.py @@ -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("线程停止完成!") diff --git a/vodsdk/concurrency/FeedbackThread.py b/vodsdk/concurrency/FeedbackThread.py new file mode 100644 index 0000000..bc5f1fe --- /dev/null +++ b/vodsdk/concurrency/FeedbackThread.py @@ -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("问题反馈线程执行完成") diff --git a/vodsdk/concurrency/FileUploadThread.py b/vodsdk/concurrency/FileUploadThread.py new file mode 100644 index 0000000..069f921 --- /dev/null +++ b/vodsdk/concurrency/FileUploadThread.py @@ -0,0 +1,385 @@ +# -*- 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 +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._algSwitch = self._context['service']['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: + 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: + 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) diff --git a/vodsdk/concurrency/FileUploadThread_20250106.py b/vodsdk/concurrency/FileUploadThread_20250106.py new file mode 100644 index 0000000..5531f9d --- /dev/null +++ b/vodsdk/concurrency/FileUploadThread_20250106.py @@ -0,0 +1,305 @@ +# -*- 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'])) + for tk in task: + tk.result() + 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) diff --git a/vodsdk/concurrency/FileUploadThread_withMiniSdk.py b/vodsdk/concurrency/FileUploadThread_withMiniSdk.py new file mode 100644 index 0000000..2275541 --- /dev/null +++ b/vodsdk/concurrency/FileUploadThread_withMiniSdk.py @@ -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) diff --git a/vodsdk/concurrency/HeartbeatThread.py b/vodsdk/concurrency/HeartbeatThread.py new file mode 100644 index 0000000..90ac707 --- /dev/null +++ b/vodsdk/concurrency/HeartbeatThread.py @@ -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) diff --git a/vodsdk/concurrency/IntelligentRecognitionProcess.py b/vodsdk/concurrency/IntelligentRecognitionProcess.py new file mode 100644 index 0000000..7c40632 --- /dev/null +++ b/vodsdk/concurrency/IntelligentRecognitionProcess.py @@ -0,0 +1,1482 @@ +# -*- coding: utf-8 -*- +import base64 +import os +from concurrent.futures import ThreadPoolExecutor +from os.path import join, exists, getsize +from time import time, sleep +from traceback import format_exc +import requests +import cv2 + +from multiprocessing import Process, Queue + +import numpy as np +from loguru import logger + +from common.Constant import init_progess, success_progess +from concurrency.FileUploadThread import ImageTypeImageFileUpload +from concurrency.HeartbeatThread import Heartbeat + +from concurrency.PullVideoStreamProcess import OnlinePullVideoStreamProcess, OfflinePullVideoStreamProcess +from concurrency.PushVideoStreamProcess import OnPushStreamProcess, OffPushStreamProcess + +from util.GPUtils import check_gpu_resource +from util.LogUtils import init_log +from concurrency.CommonThread import Common +from concurrency.PullStreamThread import RecordingPullStreamThread +from concurrency.RecordingHeartbeatThread import RecordingHeartbeat +from enums.AnalysisStatusEnum import AnalysisStatus +from enums.AnalysisTypeEnum import AnalysisType +from enums.ExceptionEnum import ExceptionType +from enums.ModelTypeEnum import ModelType +from enums.RecordingStatusEnum import RecordingStatus +from util.AliyunSdk import ThAliyunVodSdk +from util.MinioSdk import MinioSdk +from util.CpuUtils import check_cpu +from util.Cv2Utils import write_or_video, push_video_stream, close_all_p +from entity.FeedBack import message_feedback, recording_feedback +from exception.CustomerException import ServiceException +from util.ImageUtils import url2Array, add_water_pic +from util.ModelUtils import MODEL_CONFIG +from util.OcrBaiduSdk import OcrBaiduSdk + +from enums.BaiduSdkEnum import VehicleEnumVALUE +from enums.ModelTypeEnum import BaiduModelTarget +from util.PlotsUtils import xywh2xyxy2 +from util.QueUtil import put_queue, get_no_block_queue, clear_queue +from util.TimeUtils import now_date_to_str, YMDHMSF +from util.CpuUtils import print_cpu_status +import inspect +class IntelligentRecognitionProcess(Process): + __slots__ = ('_fb_queue', '_msg', '_analyse_type', '_context', 'event_queue', '_pull_queue', '_hb_queue', + "_image_queue", "_push_queue", '_push_ex_queue') + + def __init__(self, *args): + super().__init__() + # 入参 + self._fb_queue, self._msg, self._analyse_type, self._context = args + # 初始化参数 + self.event_queue, self._pull_queue, self._hb_queue, self._image_queue, self._push_queue, self._push_ex_queue = \ + Queue(), Queue(10), Queue(), Queue(), Queue(), Queue() + + # 发送waitting消息 + put_queue(self._fb_queue, message_feedback(self._msg["request_id"], AnalysisStatus.WAITING.value, + self._analyse_type, progress=init_progess), timeout=2, is_ex=True) + self._storage_source = self._context['service']['storage_source'] + self._algStatus = False + def sendEvent(self, eBody): + put_queue(self.event_queue, eBody, timeout=2, is_ex=True) + + def clear_queue(self): + clear_queue(self.event_queue) + clear_queue(self._pull_queue) + clear_queue(self._hb_queue) + clear_queue(self._image_queue) + clear_queue(self._push_queue) + clear_queue(self._push_ex_queue) + + @staticmethod + def build_video_path(context, msg, is_build_or=True): + random_time = now_date_to_str(YMDHMSF) + pre_path = '%s/%s%s' % (context["base_dir"], context["video"]["file_path"], random_time) + end_path = '%s%s' % (msg["request_id"], ".mp4") + if is_build_or: + context["orFilePath"] = '%s%s%s' % (pre_path, "_on_or_", end_path) + context["aiFilePath"] = '%s%s%s' % (pre_path, "_on_ai_", end_path) + + @staticmethod + def start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context): + hb_thread = Heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + hb_thread.setDaemon(True) + hb_thread.start() + return hb_thread + + + + + +class OnlineIntelligentRecognitionProcess(IntelligentRecognitionProcess): + __slots__ = () + + @staticmethod + def start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context): + pushProcess = OnPushStreamProcess(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + pushProcess.daemon = True + pushProcess.start() + return pushProcess + + @staticmethod + def start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, frame_num): + pullProcess = OnlinePullVideoStreamProcess(msg, context, fb_queue, pull_queue, image_queue, analyse_type, + frame_num) + pullProcess.daemon = True + pullProcess.start() + return pullProcess + + + def upload_video(self,base_dir, env, request_id, orFilePath, aiFilePath): + if self._storage_source==1: + minioSdk = MinioSdk(base_dir, env, request_id ) + upload_video_thread_or = Common(minioSdk.put_object, orFilePath, "or_online_%s.mp4" % request_id) + upload_video_thread_ai = Common(minioSdk.put_object, aiFilePath, "ai_online_%s.mp4" % request_id) + else: + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_or = Common(aliyunVodSdk.get_play_url, orFilePath, "or_online_%s" % request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + + + upload_video_thread_or.setDaemon(True) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_or.start() + upload_video_thread_ai.start() + or_url = upload_video_thread_or.get_result() + ai_url = upload_video_thread_ai.get_result() + return or_url, ai_url + ''' + @staticmethod + def upload_video(base_dir, env, request_id, orFilePath, aiFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_or = Common(aliyunVodSdk.get_play_url, orFilePath, "or_online_%s" % request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + upload_video_thread_or.setDaemon(True) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_or.start() + upload_video_thread_ai.start() + or_url = upload_video_thread_or.get_result() + ai_url = upload_video_thread_ai.get_result() + return or_url, ai_url + ''' + + @staticmethod + def ai_normal_dtection(model, frame, request_id): + model_conf, code = model + retResults = MODEL_CONFIG[code][3]([model_conf, frame, request_id])[0] + if type(retResults) is np.ndarray or len(retResults) == 0: + ret = retResults + if type(retResults) is np.ndarray: + ret = retResults.tolist() + else: + ret = retResults[2] + return code, ret + + @staticmethod + def obj_det(self, model_array, frame, task_status, cframe, tt, request_id): + push_obj = [] + if task_status[1] == 1: + dtection_result = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result.append(result) + for d in dtection_result: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) == 0: + task_status[1] = 0 + if task_status[1] == 0: + if cframe % 30 == 0: + dtection_result1 = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result1.append(result) + for d in dtection_result1: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) > 0: + task_status[1] = 1 + return push_obj + + @staticmethod + def checkPT(start_time, service_timeout, pull_process, push_process, hb_thread, push_ex_queue, pull_queue, + request_id): + 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 pull_process is not None and not pull_process.is_alive(): + while True: + if pull_queue.empty() or pull_queue.qsize() == 0: + break + pull_result = get_no_block_queue(pull_queue) + if pull_result is not None and pull_result[0] == 1: + raise ServiceException(pull_result[1], pull_result[2]) + logger.info("拉流进程异常停止, requestId: {}", request_id) + raise Exception("拉流进程异常停止!") + if hb_thread is not None and not hb_thread.is_alive(): + logger.info("心跳线程异常停止, requestId: {}", request_id) + raise Exception("心跳线程异常停止!") + if push_process is not None and not push_process.is_alive(): + while True: + if push_ex_queue.empty() or push_ex_queue.qsize() == 0: + break + push_result = get_no_block_queue(push_ex_queue) + if push_result is not None and push_result[0] == 1: + raise ServiceException(push_result[1], push_result[2]) + logger.info("推流进程异常停止, requestId: {}", request_id) + raise Exception("推流进程异常停止!") + + def run(self): + msg, context, analyse_type = self._msg, self._context, self._analyse_type + self.build_video_path(context, msg) + request_id = msg["request_id"] + base_dir, env = context["base_dir"], context["env"] + service_timeout = int(context["service"]["timeout"]) + ex = None + # 拉流进程、推流进程、心跳线程 + pull_process, push_process, hb_thread = None, None, None + + # 事件队列、拉流队列、心跳队列、反馈队列 + event_queue, pull_queue, hb_queue, fb_queue = self.event_queue, self._pull_queue, self._hb_queue, self._fb_queue + + # 推流队列、推流异常队列、图片队列 + push_queue, push_ex_queue, image_queue = self._push_queue, self._push_ex_queue, self._image_queue + try: + # 初始化日志 + init_log(base_dir, env) + # 打印启动日志 + logger.info("开始启动实时分析进程!requestId: {}", request_id) + + # 启动拉流进程(包含拉流线程, 图片上传线程,mqtt读取线程) + # 拉流进程初始化时间长, 先启动 + pull_process = self.start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, 25) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #7.0, + # 启动心跳线程 + hb_thread = self.start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + + + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #7.0, + # 加载算法模型 + model_array = get_model(msg, context, analyse_type) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #9.5 + # 启动推流进程 + push_process = self.start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + # 第一个参数: 模型是否初始化 0:未初始化 1:初始化 + # 第二个参数: 检测是否有问题 0: 没有问题, 1: 有问题 + task_status = [0, 0] + draw_config = {} + start_time = time() + # 识别2个线程性能最优 + with ThreadPoolExecutor(max_workers=2) as t: + # 可能使用模型组合, 模型组合最多3个模型, 1对3, 上面的2个线程对应6个线程 + with ThreadPoolExecutor(max_workers=6) as tt: + while True: + # 检查拉流进程是否正常, 心跳线程是否正常 + self.checkPT(start_time, service_timeout, pull_process, push_process, hb_thread, push_ex_queue, + pull_queue, request_id) + # 检查推流是否异常 + push_status = get_no_block_queue(push_ex_queue) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #9.5,11.2 + if push_status is not None and push_status[0] == 1: + raise ServiceException(push_status[1], push_status[2]) + # 获取停止指令 + event_result = get_no_block_queue(event_queue) + + if event_result: + cmdStr = event_result.get("command") + #接收到算法开启、或者关闭的命令 + if cmdStr in ['algStart' , 'algStop' ]: + logger.info("发送向推流进程发送算法命令, requestId: {}, {}", request_id,cmdStr ) + put_queue(push_queue, (2, cmdStr), timeout=1, is_ex=True) + pull_process.sendCommand({"command": cmdStr}) + + # 接收到停止指令 + if "stop" == cmdStr: + logger.info("实时任务开始停止, requestId: {}", request_id) + pull_process.sendCommand({"command": 'stop'}) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + pull_result = get_no_block_queue(pull_queue) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + if pull_result is None: + sleep(1) + continue + # (4, (frame_list, frame_index_list, all_frames)) + if pull_result[0] == 4: + frame_list, frame_index_list, all_frames = pull_result[1] + if len(frame_list) > 0: + # 判断是否已经初始化 + if task_status[0] == 0: + task_status[0] = 1 + for i, model in enumerate(model_array): + model_conf, code = model + model_param = model_conf[1] + # (modeType, model_param, allowedList, names, rainbows) + MODEL_CONFIG[code][2](frame_list[0].shape[1], frame_list[0].shape[0], + model_conf) + if draw_config.get("font_config") is None: + draw_config["font_config"] = model_param['font_config'] + if draw_config.get(code) is None: + draw_config[code] = {} + draw_config[code]["allowedList"] = model_conf[2] + draw_config[code]["rainbows"] = model_conf[4] + draw_config[code]["label_arrays"] = model_param['label_arraylist'] + if "label_dict" in model_param: + draw_config[code]["label_dict"] = model_param['label_dict'] + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + # 多线程并发处理, 经过测试两个线程最优 + det_array = [] + for i, frame in enumerate(frame_list): + det_result = t.submit(self.obj_det, self, model_array, frame, task_status, + frame_index_list[i], tt, request_id) + det_array.append(det_result) + push_objs = [det.result() for det in det_array] + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + put_queue(push_queue, + (1, (frame_list, frame_index_list, all_frames, draw_config, push_objs)), + timeout=2, is_ex=True) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + del det_array, push_objs + del frame_list, frame_index_list, all_frames + elif pull_result[0] == 1: + # 拉流发生异常 + put_queue(push_queue, (2, 'stop_ex'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + raise ServiceException(pull_result[1], pull_result[2]) + elif pull_result[0] == 2: + put_queue(push_queue, (2, 'stop'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + break + else: + raise Exception("未知拉流状态异常!") + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, 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: + orFilePath, aiFilePath = context["orFilePath"], context["aiFilePath"] + base_dir, env = context["base_dir"], context["env"] + or_url, ai_url, exc = "", "", None + try: + # 如果拉流进程存在, 关闭拉流进程(拉流线程、图片上传线程) + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + logger.info("关闭拉流进程, requestId:{}", request_id) + pull_process.join(timeout=120) + logger.info("关闭拉流进程1, requestId:{}", request_id) + if exists(orFilePath) and exists(aiFilePath) and getsize(orFilePath) > 100: + or_url, ai_url = self.upload_video(base_dir, env, request_id, orFilePath, aiFilePath) + if or_url is None or ai_url is None: + logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + # 停止心跳线程 + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=1) + hb_thread.join(timeout=120) + if exists(orFilePath): + logger.info("开始删除原视频, orFilePath: {}, requestId: {}", orFilePath, request_id) + os.remove(orFilePath) + logger.info("删除原视频成功, orFilePath: {}, requestId: {}", orFilePath, request_id) + if exists(aiFilePath): + logger.info("开始删除AI视频, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + os.remove(aiFilePath) + logger.info("删除AI视频成功, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + # 如果有异常, 检查是否有原视频和AI视频,有则上传,响应失败 + if ex: + code, msg = ex + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + video_url=or_url, + ai_video_url=ai_url), timeout=2, is_ex=False) + else: + if or_url is None or len(or_url) == 0 or ai_url is None or len(ai_url) == 0: + raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1]) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess, + video_url=or_url, + ai_video_url=ai_url), timeout=2, is_ex=False) + + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, request_id) + exc = s.code, s.msg + except Exception: + logger.error("服务异常: {}, requestId: {},", format_exc(), request_id) + exc = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + logger.info("关闭拉流进程, requestId:{}", request_id) + pull_process.join(timeout=120) + logger.info("关闭拉流进程1, requestId:{}", request_id) + if exc: + code, msg = exc + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + video_url=or_url, + ai_video_url=ai_url), timeout=2, is_ex=False) + logger.info("清理队列, requestId:{}", request_id) + self.clear_queue() + logger.info("清理队列完成, requestId:{}", request_id) + + +class OfflineIntelligentRecognitionProcess(IntelligentRecognitionProcess): + __slots__ = () + + def upload_video(self,base_dir, env, request_id, aiFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + if self._storage_source==1: + minioSdk = MinioSdk(base_dir, env, request_id ) + upload_video_thread_ai = Common(minioSdk.put_object, aiFilePath, "ai_online_%s.mp4" % request_id) + else: + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + ai_url = upload_video_thread_ai.get_result() + return ai_url + + ''' + @staticmethod + def upload_video(base_dir, env, request_id, aiFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + ai_url = upload_video_thread_ai.get_result() + return ai_url + ''' + @staticmethod + def ai_normal_dtection(model, frame, request_id): + model_conf, code = model + retResults = MODEL_CONFIG[code][3]([model_conf, frame, request_id])[0] + if type(retResults) is np.ndarray or len(retResults) == 0: + ret = retResults + if type(retResults) is np.ndarray: + ret = retResults.tolist() + else: + ret = retResults[2] + return code, ret + + @staticmethod + def obj_det(self, model_array, frame, task_status, cframe, tt, request_id): + push_obj = [] + if task_status[1] == 1: + dtection_result = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result.append(result) + for d in dtection_result: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) == 0: + task_status[1] = 0 + if task_status[1] == 0: + if cframe % 30 == 0: + dtection_result1 = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result1.append(result) + for d in dtection_result1: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) > 0: + task_status[1] = 1 + return push_obj + + @staticmethod + def start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context): + pushProcess = OffPushStreamProcess(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + pushProcess.daemon = True + pushProcess.start() + return pushProcess + + @staticmethod + def start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, frame_num): + pullProcess = OfflinePullVideoStreamProcess(msg, context, fb_queue, pull_queue, image_queue, analyse_type, + frame_num) + pullProcess.daemon = True + pullProcess.start() + return pullProcess + + @staticmethod + def checkPT(service_timeout, start_time, pull_process, push_process, hb_thread, push_ex_queue, pull_queue, + request_id): + 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 pull_process is not None and not pull_process.is_alive(): + while True: + if pull_queue.empty() or pull_queue.qsize() == 0: + break + pull_result = get_no_block_queue(pull_queue) + if pull_result is not None and pull_result[0] == 1: + raise ServiceException(pull_result[1], pull_result[2]) + logger.info("拉流进程异常停止, requestId: {}", request_id) + raise Exception("拉流进程异常停止!") + if hb_thread is not None and not hb_thread.is_alive(): + logger.info("心跳线程异常停止, requestId: {}", request_id) + raise Exception("心跳线程异常停止!") + if push_process is not None and not push_process.is_alive(): + while True: + if push_ex_queue.empty() or push_ex_queue.qsize() == 0: + break + push_result = get_no_block_queue(push_ex_queue) + if push_result is not None and push_result[0] == 1: + raise ServiceException(push_result[1], push_result[2]) + logger.info("推流进程异常停止, requestId: {}", request_id) + raise Exception("推流进程异常停止!") + + def run(self): + msg, context, analyse_type, ex = self._msg, self._context, self._analyse_type, None + self.build_video_path(context, msg, is_build_or=False) + request_id, base_dir, env = msg["request_id"], context["base_dir"], context["env"] + # 拉流进程、推流进程、心跳线程 + pull_process, push_process, hb_thread = None, None, None + service_timeout = int(context["service"]["timeout"]) + # 事件队列、拉流队列、心跳队列、反馈队列 + event_queue, pull_queue, hb_queue, fb_queue = self.event_queue, self._pull_queue, self._hb_queue, self._fb_queue + # 推流队列、推流异常队列、图片队列 + push_queue, push_ex_queue, image_queue = self._push_queue, self._push_ex_queue, self._image_queue + try: + # 初始化日志 + init_log(base_dir, env) + # 打印启动日志 + logger.info("开始启动离线分析进程!requestId: {}", request_id) + # 启动拉流进程(包含拉流线程, 图片上传线程) + # 拉流进程初始化时间长, 先启动 + pull_process = self.start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, 25) + # 启动心跳线程 + hb_thread = self.start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + # 加载算法模型 + model_array = get_model(msg, context, analyse_type) + # 启动推流进程 + push_process = self.start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + # 第一个参数: 模型是否初始化 0:未初始化 1:初始化 + # 第二个参数: 检测是否有问题 0: 没有问题, 1: 有问题 + task_status = [0, 0] + draw_config = {} + start_time = time() + # 识别2个线程性能最优 + with ThreadPoolExecutor(max_workers=2) as t: + # 可能使用模型组合, 模型组合最多3个模型, 1对3, 上面的2个线程对应6个线程 + with ThreadPoolExecutor(max_workers=6) as tt: + while True: + # 检查拉流进程是否正常, 心跳线程是否正常 + self.checkPT(service_timeout, start_time, pull_process, push_process, hb_thread, push_ex_queue, + pull_queue, request_id) + # 检查推流是否异常 + push_status = get_no_block_queue(push_ex_queue) + if push_status is not None and push_status[0] == 1: + raise ServiceException(push_status[1], push_status[2]) + # 获取停止指令 + event_result = get_no_block_queue(event_queue) + if event_result: + cmdStr = event_result.get("command") + # 接收到停止指令 + if "stop" == cmdStr: + logger.info("离线任务开始停止, requestId: {}", request_id) + pull_process.sendCommand({"command": 'stop'}) + if cmdStr in ['algStart' , 'algStop' ]: + logger.info("发送向推流进程发送算法命令, requestId: {}, {}", request_id,cmdStr ) + put_queue(push_queue, (2, cmdStr), timeout=1, is_ex=True) + pull_process.sendCommand({"command": cmdStr}) + + pull_result = get_no_block_queue(pull_queue) + if pull_result is None: + sleep(1) + continue + # (4, (frame_list, frame_index_list, all_frames)) + if pull_result[0] == 4: + frame_list, frame_index_list, all_frames = pull_result[1] + if len(frame_list) > 0: + # 判断是否已经初始化 + if task_status[0] == 0: + task_status[0] = 1 + for i, model in enumerate(model_array): + model_conf, code = model + model_param = model_conf[1] + # (modeType, model_param, allowedList, names, rainbows) + MODEL_CONFIG[code][2](frame_list[0].shape[1], frame_list[0].shape[0], + model_conf) + if draw_config.get("font_config") is None: + draw_config["font_config"] = model_param['font_config'] + if draw_config.get(code) is None: + draw_config[code] = {} + draw_config[code]["allowedList"] = model_conf[2] + draw_config[code]["rainbows"] = model_conf[4] + draw_config[code]["label_arrays"] = model_param['label_arraylist'] + if "label_dict" in model_param: + draw_config[code]["label_dict"] = model_param['label_dict'] + det_array = [] + for i, frame in enumerate(frame_list): + det_result = t.submit(self.obj_det, self, model_array, frame, task_status, + frame_index_list[i], tt, request_id) + det_array.append(det_result) + push_objs = [det.result() for det in det_array] + put_queue(push_queue, + (1, (frame_list, frame_index_list, all_frames, draw_config, push_objs)), + timeout=2, is_ex=True) + del det_array, push_objs + del frame_list, frame_index_list, all_frames + elif pull_result[0] == 1: + put_queue(push_queue, (2, 'stop_ex'), timeout=1, is_ex=True) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + raise ServiceException(pull_result[1], pull_result[2]) + elif pull_result[0] == 2: + logger.info("离线任务开始停止, requestId: {}", request_id) + put_queue(push_queue, (2, 'stop'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + break + else: + raise Exception("未知拉流状态异常!") + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, 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: + base_dir, env, aiFilePath = context["base_dir"], context["env"], context["aiFilePath"] + ai_url, exc = "", None + try: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + push_process.join(timeout=120) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(timeout=120) + if exists(aiFilePath) and getsize(aiFilePath) > 100: + ai_url = self.upload_video(base_dir, env, request_id, aiFilePath) + if ai_url is None: + logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + # 停止心跳线程 + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=1) + hb_thread.join(timeout=120) + if exists(aiFilePath): + logger.info("开始删除AI视频, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + os.remove(aiFilePath) + logger.info("删除AI视频成功, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + # 如果有异常, 检查是否有原视频和AI视频,有则上传,响应失败 + if ex: + code, msg = ex + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + ai_video_url=ai_url), timeout=2, is_ex=False) + else: + if ai_url is None or len(ai_url) == 0: + raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1]) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess, + ai_video_url=ai_url), timeout=2, is_ex=False) + + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, request_id) + exc = s.code, s.msg + except Exception: + logger.error("服务异常: {}, requestId: {},", format_exc(), request_id) + exc = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + push_process.join(timeout=120) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(timeout=120) + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=1) + hb_thread.join(timeout=120) + if exc: + code, msg = exc + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + ai_video_url=ai_url), timeout=2, is_ex=False) + self.clear_queue() + + +''' +图片识别 +''' + + +class PhotosIntelligentRecognitionProcess(Process): + __slots__ = ("_fb_queue", "_msg", "_analyse_type", "_context", "_image_queue") + + def __init__(self, *args): + super().__init__() + self._fb_queue, self._msg, self._analyse_type, self._context = args + self._image_queue = Queue() + put_queue(self._fb_queue, message_feedback(self._msg["request_id"], AnalysisStatus.WAITING.value, + self._analyse_type, progress=init_progess), timeout=2, is_ex=True) + self.build_logo(self._msg, self._context) + self._storage_source = self._context['service']['storage_source'] + + @staticmethod + def build_logo(msg, context): + logo = None + if context["video"]["video_add_water"]: + logo = msg.get("logo_url") + if logo is not None and len(logo) > 0: + logo = url2Array(logo, enable_ex=False) + if logo is None: + logo = cv2.imread(join(context['base_dir'], "image/logo.png"), -1) + context['logo'] = logo + + def epidemic_prevention(self, imageUrl, model, orc, request_id): + try: + # modeType, allowedList, new_device, model, par, img_type + model_conf, code = model + modeType, allowedList, new_device, model, par, img_type = model_conf + image = url2Array(imageUrl) + param = [image, new_device, model, par, img_type, request_id] + dataBack = MODEL_CONFIG[code][3](param) + if img_type == 'plate': + carCode = '' + if dataBack is None or dataBack.get("plateImage") is None or len(dataBack.get("plateImage")) == 0: + result = orc.license_plate_recognition(image, request_id) + score = '' + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + logger.error("车牌识别为空: {}", result) + carCode = '' + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + else: + result = orc.license_plate_recognition(dataBack.get("plateImage")[0], request_id) + score = dataBack.get("plateImage")[1] + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + result = orc.license_plate_recognition(image, request_id) + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + logger.error("车牌识别为空: {}", result) + carCode = '' + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + if len(carCode) > 0: + plate_result = {'type': str(3), 'modelCode': code, 'carUrl': imageUrl, + 'carCode': carCode, + 'score': score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(3), + plate_result), timeout=2, is_ex=True) + if img_type == 'code': + if dataBack is None or dataBack.get("type") is None: + return + # 行程码 + if dataBack.get("type") == 1 and 1 in allowedList: + # 手机号 + if dataBack.get("phoneNumberImage") is None or len(dataBack.get("phoneNumberImage")) == 0: + phoneNumberRecognition = '' + phone_score = '' + else: + phone = orc.universal_text_recognition(dataBack.get("phoneNumberImage")[0], request_id) + phone_score = dataBack.get("phoneNumberImage")[1] + if phone is None or phone.get("words_result") is None or len(phone.get("words_result")) == 0: + logger.error("手机号识别为空: {}", phone) + phoneNumberRecognition = '' + else: + phoneNumberRecognition = phone.get("words_result") + if dataBack.get("cityImage") is None or len(dataBack.get("cityImage")) == 0: + cityRecognition = '' + city_score = '' + else: + city = orc.universal_text_recognition(dataBack.get("cityImage")[0], request_id) + city_score = dataBack.get("cityImage")[1] + if city is None or city.get("words_result") is None or len(city.get("words_result")) == 0: + logger.error("城市识别为空: {}", city) + cityRecognition = '' + else: + cityRecognition = city.get("words_result") + if len(phoneNumberRecognition) > 0 or len(cityRecognition) > 0: + trip_result = {'type': str(1), + 'modelCode': code, + 'imageUrl': imageUrl, + 'phoneNumberRecognition': phoneNumberRecognition, + 'phone_sorce': phone_score, + 'cityRecognition': cityRecognition, + 'city_score': city_score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(1), + trip_result), timeout=2, is_ex=True) + if dataBack.get("type") == 2 and 2 in allowedList: + if dataBack.get("nameImage") is None or len(dataBack.get("nameImage")) == 0: + nameRecognition = '' + name_score = '' + else: + name = orc.universal_text_recognition(dataBack.get("nameImage")[0], request_id) + name_score = dataBack.get("nameImage")[1] + if name is None or name.get("words_result") is None or len(name.get("words_result")) == 0: + logger.error("名字识别为空: {}", name) + nameRecognition = '' + else: + nameRecognition = name.get("words_result") + + if dataBack.get("phoneNumberImage") is None or len(dataBack.get("phoneNumberImage")) == 0: + phoneNumberRecognition = '' + phone_score = '' + else: + phone = orc.universal_text_recognition(dataBack.get("phoneNumberImage")[0], request_id) + phone_score = dataBack.get("phoneNumberImage")[1] + if phone is None or phone.get("words_result") is None or len(phone.get("words_result")) == 0: + logger.error("手机号识别为空: {}", phone) + phoneNumberRecognition = '' + else: + phoneNumberRecognition = phone.get("words_result") + if dataBack.get("hsImage") is None or len(dataBack.get("hsImage")) == 0: + hsRecognition = '' + hs_score = '' + else: + hs = orc.universal_text_recognition(dataBack.get("hsImage")[0], request_id) + hs_score = dataBack.get("hsImage")[1] + if hs is None or hs.get("words_result") is None or len(hs.get("words_result")) == 0: + logger.error("核酸识别为空: {}", hs) + hsRecognition = '' + else: + hsRecognition = hs.get("words_result") + if len(nameRecognition) > 0 or len(phoneNumberRecognition) > 0 or len(hsRecognition) > 0: + healthy_result = {'type': str(2), + 'modelCode': code, + 'imageUrl': imageUrl, + 'color': dataBack.get("color"), + 'nameRecognition': nameRecognition, + 'name_score': name_score, + 'phoneNumberRecognition': phoneNumberRecognition, + 'phone_score': phone_score, + 'hsRecognition': hsRecognition, + 'hs_score': hs_score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(2), + healthy_result), timeout=2, is_ex=True) + except ServiceException as s: + raise s + except Exception as e: + logger.error("模型分析异常: {}, requestId: {}", format_exc(), request_id) + raise e + + ''' + # 防疫模型 + ''' + + def epidemicPrevention(self, imageUrls, model, base_dir, env, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + orc = OcrBaiduSdk(base_dir, env) + obj_list = [] + for imageUrl in imageUrls: + obj = t.submit(self.epidemic_prevention, imageUrl, model, orc, request_id) + obj_list.append(obj) + for r in obj_list: + r.result(60) + + def image_recognition(self, imageUrl, mod, image_queue, logo, request_id): + try: + model_conf, code = mod + model_param = model_conf[1] + image = url2Array(imageUrl) + MODEL_CONFIG[code][2](image.shape[1], image.shape[0], model_conf) + p_result = MODEL_CONFIG[code][3]([model_conf, image, request_id])[0] + #print(' line872:p_result[2]:',p_result[2] ) + if p_result is None or len(p_result) < 3 or p_result[2] is None or len(p_result[2]) == 0: + return + if logo: + image = add_water_pic(image, logo, request_id) + # (modeType, model_param, allowedList, names, rainbows) + allowedList = model_conf[2] + label_arraylist = model_param['label_arraylist'] + font_config = model_param['font_config'] + rainbows = model_conf[4] + det_xywh = {code: {}} + ai_result_list = p_result[2] + for ai_result in ai_result_list: + box, score, cls = xywh2xyxy2(ai_result) + # 如果检测目标在识别任务中,继续处理 + if cls in allowedList: + label_array = label_arraylist[cls] + color = rainbows[cls] + cd = det_xywh[code].get(cls) + 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]) + #print('ai_result_list:{},allowlist:{}'.format(ai_result_list,allowedList )) + if len(det_xywh) > 0: + put_queue(image_queue, (1, (det_xywh, imageUrl, image, font_config, "")), timeout=2, is_ex=False) + except ServiceException as s: + raise s + except Exception as e: + logger.error("模型分析异常: {}, requestId: {}", format_exc(), self._msg.get("request_id")) + raise e + + def publicIdentification(self, imageUrls, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + obj_list = [] + for imageUrl in imageUrls: + obj = t.submit(self.image_recognition, imageUrl, mod, image_queue, logo, request_id) + obj_list.append(obj) + for r in obj_list: + r.result(60) + + ''' + 1. imageUrls: 图片url数组,多张图片 + 2. mod: 模型对象 + 3. image_queue: 图片队列 + ''' + + def baiduRecognition(self, imageUrls, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + thread_result = [] + for imageUrl in imageUrls: + obj = t.submit(self.baidu_recognition, imageUrl, mod, image_queue, logo, request_id) + thread_result.append(obj) + for r in thread_result: + r.result(60) + + def baidu_recognition(self, imageUrl, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + try: + # modeType, aipImageClassifyClient, aipBodyAnalysisClient, allowedList, rainbows, + # vehicle_names, person_names, requestId + model_conf, code = mod + allowedList = model_conf[3] + rainbows = model_conf[4] + # 图片转数组 + img = url2Array(imageUrl) + vehicle_label_arrays, person_label_arrays, font_config = MODEL_CONFIG[code][2](img.shape[1], + img.shape[0], + model_conf) + obj_list = [] + for target in allowedList: + parm = [target, imageUrl, model_conf[1], model_conf[2], request_id] + reuslt = t.submit(self.baidu_method, code, parm, img, image_queue, vehicle_label_arrays, + person_label_arrays, font_config, rainbows, logo) + obj_list.append(reuslt) + for r in obj_list: + r.result(60) + except ServiceException as s: + raise s + except Exception as e: + logger.error("百度AI分析异常: {}, requestId: {}", format_exc(), request_id) + raise e + + @staticmethod + def baidu_method(code, parm, img, image_queue, vehicle_label_arrays, person_label_arrays, font_config, + rainbows, logo): + # [target, url, aipImageClassifyClient, aipBodyAnalysisClient, requestId] + request_id = parm[4] + target = parm[0] + image_url = parm[1] + result = MODEL_CONFIG[code][3](parm) + if target == BaiduModelTarget.VEHICLE_DETECTION.value[1] and result is not None: + vehicleInfo = result.get("vehicle_info") + if vehicleInfo is not None and len(vehicleInfo) > 0: + det_xywh = {code: {}} + copy_frame = img.copy() + for i, info in enumerate(vehicleInfo): + value = VehicleEnumVALUE.get(info.get("type")) + target_num = value.value[2] + label_array = vehicle_label_arrays[target_num] + color = rainbows[target_num] + if value is None: + logger.error("车辆识别出现未支持的目标类型!type:{}, requestId:{}", info.get("type"), request_id) + return + left_top = (int(info.get("location").get("left")), int(info.get("location").get("top"))) + right_top = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top"))) + right_bottom = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + left_bottom = (int(info.get("location").get("left")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + box = [left_top, right_top, right_bottom, left_bottom] + score = float("%.2f" % info.get("probability")) + if logo: + copy_frame = add_water_pic(copy_frame, logo, request_id) + if det_xywh[code].get(target) is None: + det_xywh[code][target] = [[target, box, score, label_array, color]] + else: + det_xywh[code][target].append([target, box, score, label_array, color]) + info["id"] = str(i) + if len(det_xywh[code]) > 0: + result["type"] = str(target) + result["modelCode"] = code + put_queue(image_queue, (1, (det_xywh, image_url, copy_frame, font_config, result)), timeout=2, + is_ex=True) + # 人体识别 + if target == BaiduModelTarget.HUMAN_DETECTION.value[1] and result is not None: + personInfo = result.get("person_info") + personNum = result.get("person_num") + if personNum is not None and personNum > 0 and personInfo is not None and len(personInfo) > 0: + det_xywh = {code: {}} + copy_frame = img.copy() + for i, info in enumerate(personInfo): + left_top = (int(info.get("location").get("left")), int(info.get("location").get("top"))) + right_top = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top"))) + right_bottom = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + left_bottom = (int(info.get("location").get("left")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + box = [left_top, right_top, right_bottom, left_bottom] + score = float("%.2f" % info.get("location").get("score")) + label_array = person_label_arrays[0] + color = rainbows[0] + if logo: + copy_frame = add_water_pic(copy_frame, logo, request_id) + if det_xywh[code].get(target) is None: + det_xywh[code][target] = [[target, box, score, label_array, color]] + else: + det_xywh[code][target].append([target, box, score, label_array, color]) + info["id"] = str(i) + if len(det_xywh[code]) > 0: + result["type"] = str(target) + result["modelCode"] = code + put_queue(image_queue, (1, (det_xywh, image_url, copy_frame, font_config, result)), timeout=2) + # 人流量 + if target == BaiduModelTarget.PEOPLE_COUNTING.value[1] and result is not None: + base64Image = result.get("image") + if base64Image is not None and len(base64Image) > 0: + baiduImage = base64.b64decode(base64Image) + result["type"] = str(target) + result["modelCode"] = code + del result["image"] + put_queue(image_queue, (1, (None, image_url, baiduImage, None, result)), timeout=2) + + @staticmethod + def start_File_upload(fb_queue, context, msg, image_queue, analyse_type): + image_thread = ImageTypeImageFileUpload(fb_queue, context, msg, image_queue, analyse_type) + image_thread.setDaemon(True) + image_thread.start() + return image_thread + def check_ImageUrl_Vaild(self,url,timeout=1): + try: + # 发送 HTTP 请求,尝试访问图片 + response = requests.get(url, timeout=timeout) # 设置超时时间为 10 秒 + if response.status_code == 200: + return True,url + else: + return False,f"图片地址无效,状态码:{response.status_code}" + except requests.exceptions.RequestException as e: + # 捕获请求过程中可能出现的异常(如网络问题、超时等) + return False,str(e) + + def run(self): + fb_queue, msg, analyse_type, context = self._fb_queue, self._msg, self._analyse_type, self._context + request_id, logo, image_queue = msg["request_id"], context['logo'], self._image_queue + base_dir, env = context["base_dir"], context["env"] + imageUrls = msg["image_urls"] + image_thread = None + init_log(base_dir, env) + valFlag=True + for url in imageUrls: + valFlag,ret = self.check_ImageUrl_Vaild(url,timeout=1) + + if not valFlag: + logger.error("图片分析异常: {}, requestId:{},url:{}",ret, request_id,url) + #print("AnalysisStatus.FAILED.value:{},ExceptionType.URL_ADDRESS_ACCESS_FAILED.value[0]:{},ExceptionType.URL_ADDRESS_ACCESS_FAILED.value[1]:{}".format(AnalysisStatus.FAILED.value,ExceptionType.URL_ADDRESS_ACCESS_FAILED.value[0],ExceptionType.URL_ADDRESS_ACCESS_FAILED.value[1] ) ) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + ExceptionType.URL_ADDRESS_ACCESS_FAILED.value[0], + ExceptionType.URL_ADDRESS_ACCESS_FAILED.value[1]), timeout=2) + + return + + + with ThreadPoolExecutor(max_workers=1) as t: + try: + #init_log(base_dir, env) + logger.info("开始启动图片识别进程, requestId: {}", request_id) + model_array = get_model(msg, context, analyse_type) + image_thread = self.start_File_upload(fb_queue, context, msg, image_queue, analyse_type) + task_list = [] + for model in model_array: + # 百度模型逻辑 + if model[1] == ModelType.BAIDU_MODEL.value[1]: + result = t.submit(self.baiduRecognition, imageUrls, model, image_queue, logo, request_id) + task_list.append(result) + # 防疫模型 + elif model[1] == ModelType.EPIDEMIC_PREVENTION_MODEL.value[1]: + result = t.submit(self.epidemicPrevention, imageUrls, model, base_dir, env, request_id) + task_list.append(result) + # 车牌模型 + elif model[1] == ModelType.PLATE_MODEL.value[1]: + result = t.submit(self.epidemicPrevention, imageUrls, model, base_dir, env, request_id) + task_list.append(result) + else: + result = t.submit(self.publicIdentification, imageUrls, model, image_queue, logo, request_id) + task_list.append(result) + for r in task_list: + r.result(60) + if image_thread and not image_thread.is_alive(): + raise Exception("图片识别图片上传线程异常停止!!!") + if image_thread and image_thread.is_alive(): + put_queue(image_queue, (2, 'stop'), timeout=2) + image_thread.join(120) + logger.info("图片进程任务完成,requestId:{}", request_id) + put_queue(fb_queue, message_feedback(request_id, + AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess), timeout=2, is_ex=True) + except ServiceException as s: + logger.error("图片分析异常,异常编号:{}, 异常描述:{}, requestId:{}", s.code, s.msg, request_id) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + s.code, + s.msg), timeout=2) + except Exception: + logger.error("图片分析异常: {}, requestId:{}", format_exc(), request_id) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]), timeout=2) + finally: + if image_thread and image_thread.is_alive(): + clear_queue(image_queue) + put_queue(image_queue, (2, 'stop'), timeout=2) + image_thread.join(120) + clear_queue(image_queue) + + +class ScreenRecordingProcess(Process): + __slots__ = ('_fb_queue', '_context', '_msg', '_analysisType', '_event_queue', '_hb_queue', '_analysisType') + + def __init__(self, *args): + super().__init__() + # 传参 + self._fb_queue, self._context, self._msg, self._analysisType = args + self._event_queue, self._hb_queue, self._pull_queue = Queue(), Queue(), Queue(10) + put_queue(self._fb_queue, + recording_feedback(self._msg["request_id"], RecordingStatus.RECORDING_WAITING.value[0]), + timeout=1, is_ex=True) + self._storage_source = self._context['service']['storage_source'] + def sendEvent(self, result): + put_queue(self._event_queue, result, timeout=2, is_ex=True) + + @staticmethod + def start_pull_stream_thread(msg, context, pull_queue, hb_queue, fb_queue, frame_num): + pullThread = RecordingPullStreamThread(msg, context, pull_queue, hb_queue, fb_queue, frame_num) + pullThread.setDaemon(True) + pullThread.start() + return pullThread + + @staticmethod + def start_hb_thread(fb_queue, hb_queue, request_id): + hb = RecordingHeartbeat(fb_queue, hb_queue, request_id) + hb.setDaemon(True) + hb.start() + return hb + + @staticmethod + def check(start_time, service_timeout, pull_thread, hb_thread, request_id): + 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 pull_thread and not pull_thread.is_alive(): + logger.info("录屏拉流线程停止异常, requestId: {}", request_id) + raise Exception("录屏拉流线程异常停止") + if hb_thread and not hb_thread.is_alive(): + logger.info("录屏心跳线程异常停止, requestId: {}", request_id) + raise Exception("录屏心跳线程异常停止") + + def run(self): + msg, context = self._msg, self._context + request_id, push_url = msg['request_id'], msg.get('push_url') + pull_queue, fb_queue, hb_queue, event_queue = self._pull_queue, self._fb_queue, self._hb_queue, \ + self._event_queue + base_dir, env, service_timeout = context['base_dir'], context['env'], int(context["service"]["timeout"]) + pre_path, end_path = '%s/%s%s' % (base_dir, context["video"]["file_path"], now_date_to_str(YMDHMSF)), \ + '%s%s' % (request_id, ".mp4") + orFilePath = '%s%s%s' % (pre_path, "_on_or_", end_path) + pull_thread, hb_thread = None, None + or_write_status, p_push_status = [0, 0], [0, 0] + or_video_file, push_p = None, None + ex = None + try: + # 初始化日志 + init_log(base_dir, env) + # 启动拉流线程 + pull_thread = self.start_pull_stream_thread(msg, context, pull_queue, hb_queue, fb_queue, 25) + hb_thread = self.start_hb_thread(fb_queue, hb_queue, request_id) + start_time = time() + with ThreadPoolExecutor(max_workers=2) as t: + while True: + # 检查拉流线程和心跳线程 + self.check(start_time, service_timeout, pull_thread, hb_thread, request_id) + # 判断是否需要停止录屏 + event_result = get_no_block_queue(event_queue) + if event_result is not None: + cmdStr = event_result.get("command") + # 接收到停止指令 + if 'stop' == cmdStr: + logger.info("录屏任务开始停止, requestId: {}", request_id) + pull_thread.sendEvent({"command": "stop"}) + pull_result = get_no_block_queue(pull_queue) + if pull_result is None: + sleep(1) + continue + if pull_result[0] == 1: + close_all_p(push_p, or_video_file, None, request_id) + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(180) + raise ServiceException(pull_result[1], pull_result[2]) + elif pull_result[0] == 2: + close_all_p(push_p, or_video_file, None, request_id) + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(180) + break + elif pull_result[0] == 4: + frame_list, frame_index_list, all_frames = pull_result[1] + if len(frame_list) > 0: + 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, {"progress": task_process}, timeout=1) + write_or_video_result = t.submit(write_or_video, frame, orFilePath, or_video_file, + or_write_status, request_id) + if push_url is not None and len(push_url) > 0: + push_p_result = t.submit(push_video_stream, frame, push_p, push_url, p_push_status, + request_id) + push_p = push_p_result.result() + or_video_file = write_or_video_result.result() + else: + raise Exception("未知拉流状态异常!") + logger.info("录屏线程任务完成,requestId:{}", self._msg.get("request_id")) + except ServiceException as s: + logger.error("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, self._msg.get("request_id")) + ex = s.code, s.msg + except Exception: + logger.error("服务异常: {}, requestId: {},", format_exc(), self._msg.get("request_id")) + ex = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + or_url = "" + exn = None + try: + # 关闭推流管道, 原视频写流客户端 + close_all_p(push_p, or_video_file, None, request_id) + # 关闭拉流线程 + if pull_thread and pull_thread.is_alive(): + pull_thread.sendEvent({"command": "stop_ex"}) + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(120) + # 判断是否需要上传视频 + if exists(orFilePath) and getsize(orFilePath) > 100: + or_url = self.upload_video(base_dir, env, request_id, orFilePath) + if or_url is None or len(or_url) == 0: + logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + # 停止心跳线程 + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=10, is_ex=False) + hb_thread.join(timeout=120) + if exists(orFilePath): + logger.info("开始删除原视频, orFilePath: {}, requestId: {}", orFilePath, request_id) + os.remove(orFilePath) + logger.info("删除原视频成功, orFilePath: {}, requestId: {}", orFilePath, request_id) + # 如果有异常, 检查是否有原视频和AI视频,有则上传,响应失败 + if ex: + code, msg = ex + put_queue(fb_queue, recording_feedback(request_id, RecordingStatus.RECORDING_FAILED.value[0], + error_code=code, + error_msg=msg, + video_url=or_url), timeout=10, is_ex=False) + else: + if or_url is None or len(or_url) == 0: + raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1]) + put_queue(fb_queue, recording_feedback(request_id, RecordingStatus.RECORDING_SUCCESS.value[0], + progress=success_progess, + video_url=or_url), timeout=10, is_ex=False) + except ServiceException as s: + exn = s.code, s.msg + except Exception: + logger.error("异常:{}, requestId: {}", format_exc(), request_id) + exn = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + if pull_thread and pull_thread.is_alive(): + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(120) + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=10, is_ex=False) + hb_thread.join(timeout=120) + self.clear_queue_end() + if exn: + code, msg = exn + put_queue(fb_queue, recording_feedback(request_id, RecordingStatus.RECORDING_FAILED.value[0], + error_code=code, + error_msg=msg, + video_url=or_url), timeout=10, is_ex=False) + + def clear_queue_end(self): + clear_queue(self._event_queue) + clear_queue(self._hb_queue) + clear_queue(self._pull_queue) + + + + + def upload_video(self,base_dir, env, request_id, orFilePath): + if self._storage_source==1: + minioSdk = MinioSdk(base_dir, env, request_id ) + upload_video_thread_ai = Common(minioSdk.put_object, aiFilePath, "%s/ai_online.mp4" % request_id) + else: + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + or_url = upload_video_thread_ai.get_result() + return or_url + ''' + @staticmethod + def upload_video(base_dir, env, request_id, orFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, orFilePath, "or_online_%s" % request_id) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + or_url = upload_video_thread_ai.get_result() + return or_url + ''' + +""" +"models": [{ + "code": "模型编号", + "categories":[{ + "id": "模型id", + "config": { + "k1": "v1", + "k2": "v2" + } + }] +}] +""" + + +def get_model(msg, context, analyse_type): + # 初始变量 + request_id, base_dir, gpu_name, env = msg["request_id"], context["base_dir"], context["gpu_name"], context["env"] + models, model_num_limit = msg["models"], context["service"]["model"]['limit'] + try: + # 实时、离线元组 + analyse_type_tuple = (AnalysisType.ONLINE.value, AnalysisType.OFFLINE.value) + # (实时、离线)检查模型组合, 目前只支持3个模型组合 + if analyse_type in analyse_type_tuple: + if len(models) > model_num_limit: + raise ServiceException(ExceptionType.MODEL_GROUP_LIMIT_EXCEPTION.value[0], + ExceptionType.MODEL_GROUP_LIMIT_EXCEPTION.value[1]) + modelArray, codeArray = [], set() + for model in models: + # 模型编码 + code = model["code"] + # 检验code是否重复 + if code in codeArray: + raise ServiceException(ExceptionType.MODEL_DUPLICATE_EXCEPTION.value[0], + ExceptionType.MODEL_DUPLICATE_EXCEPTION.value[1]) + codeArray.add(code) + # 检测目标数组 + needed_objectsIndex = list(set([int(category["id"]) for category in model["categories"]])) + logger.info("模型编号: {}, 检查目标: {}, requestId: {}", code, needed_objectsIndex, request_id) + model_method = MODEL_CONFIG.get(code) + if model_method is None: + logger.error("未匹配到对应的模型, requestId:{}", request_id) + raise ServiceException(ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[0], + ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[1]) + # 检查cpu资源、gpu资源 + check_cpu(base_dir, request_id) + gpu_ids = check_gpu_resource(request_id) + # 如果实时识别、离线识别 + if analyse_type in analyse_type_tuple: + if model["is_video"] == "1": + mod = model_method[0](gpu_ids[0], needed_objectsIndex, request_id, gpu_name, base_dir, env) + modelArray.append((mod.model_conf, code)) + else: + raise ServiceException(ExceptionType.MODEL_NOT_SUPPORT_VIDEO_EXCEPTION.value[0], + ExceptionType.MODEL_NOT_SUPPORT_VIDEO_EXCEPTION.value[1], + model_method[1].value[2]) + # 如果是图片识别 + if analyse_type == AnalysisType.IMAGE.value: + if model["is_image"] == "1": + mod = model_method[0](gpu_ids[0], needed_objectsIndex, request_id, gpu_name, base_dir, env) + modelArray.append((mod.model_conf, code)) + else: + raise ServiceException(ExceptionType.MODEL_NOT_SUPPORT_IMAGE_EXCEPTION.value[0], + ExceptionType.MODEL_NOT_SUPPORT_IMAGE_EXCEPTION.value[1], + model_method[1].value[2]) + if len(modelArray) == 0: + raise ServiceException(ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[0], + ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[1]) + return modelArray + except ServiceException as s: + raise s + except Exception: + logger.error("模型配置处理异常: {}, request_id: {}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) diff --git a/vodsdk/concurrency/IntelligentRecognitionProcess2.py b/vodsdk/concurrency/IntelligentRecognitionProcess2.py new file mode 100644 index 0000000..9afed2b --- /dev/null +++ b/vodsdk/concurrency/IntelligentRecognitionProcess2.py @@ -0,0 +1,1098 @@ +# -*- coding: utf-8 -*- +import base64 +import os +from concurrent.futures import ThreadPoolExecutor +from os.path import join, exists, getsize +from time import time, sleep +from traceback import format_exc + +import cv2 + +from multiprocessing import Process, Queue +from loguru import logger + +from common.Constant import init_progess, success_progess + +from concurrency.FileUploadThread import ImageTypeImageFileUpload +from concurrency.HeartbeatThread import Heartbeat +from concurrency.PullVideoStreamProcess2 import OnlinePullVideoStreamProcess2, OfflinePullVideoStreamProcess2 +from concurrency.PushVideoStreamProcess2 import OnPushStreamProcess2, OffPushStreamProcess2 + +from util.GPUtils import check_gpu_resource +from util.LogUtils import init_log +from concurrency.CommonThread import Common +from enums.AnalysisStatusEnum import AnalysisStatus +from enums.AnalysisTypeEnum import AnalysisType +from enums.ExceptionEnum import ExceptionType +from enums.ModelTypeEnum2 import ModelType2 +from util import TimeUtils +from util.AliyunSdk import ThAliyunVodSdk +from util.CpuUtils import check_cpu +from entity.FeedBack import message_feedback +from exception.CustomerException import ServiceException +from util.ImageUtils import url2Array, add_water_pic +from util.ModelUtils2 import MODEL_CONFIG2 +from util.OcrBaiduSdk import OcrBaiduSdk + +from enums.BaiduSdkEnum import VehicleEnumVALUE +from enums.ModelTypeEnum import BaiduModelTarget +from util.PlotsUtils import xywh2xyxy2 +from util.QueUtil import put_queue, get_no_block_queue, clear_queue +from util.TimeUtils import now_date_to_str, YMDHMSF + + +class IntelligentRecognitionProcess2(Process): + __slots__ = ('_fb_queue', '_msg', '_analyse_type', '_context', 'event_queue', '_pull_queue', '_hb_queue', + "_image_queue", "_push_queue", '_push_ex_queue') + + def __init__(self, *args): + super().__init__() + self._fb_queue, self._msg, self._analyse_type, self._context = args + self.event_queue, self._pull_queue, self._hb_queue, self._image_queue = Queue(), Queue(10), Queue(), Queue() + self._push_queue, self._push_ex_queue = Queue(), Queue() + put_queue(self._fb_queue, message_feedback(self._msg["request_id"], + AnalysisStatus.WAITING.value, + self._analyse_type, + progress=init_progess), timeout=2, is_ex=True) + + 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 clear_queue(self): + clear_queue(self.event_queue) + clear_queue(self._pull_queue) + clear_queue(self._hb_queue) + clear_queue(self._image_queue) + clear_queue(self._push_queue) + clear_queue(self._push_ex_queue) + + @staticmethod + def ai_dtection(model, frame_list, frame_index_list, request_id): + retResults = MODEL_CONFIG2[model[1]][3]([frame_list, frame_index_list, model[0][1], request_id])[0] + if len(frame_list) == 1: + return model[1], [retResults[2]] + return model[1], retResults[2] + + @staticmethod + def build_video_path(context, msg, is_build_or=True): + random_time = now_date_to_str(YMDHMSF) + pre_path = '%s/%s%s' % (context["base_dir"], context["video"]["file_path"], random_time) + end_path = '%s%s' % (msg["request_id"], ".mp4") + if is_build_or: + context["orFilePath"] = '%s%s%s' % (pre_path, "_on_or_", end_path) + context["aiFilePath"] = '%s%s%s' % (pre_path, "_on_ai_", end_path) + + @staticmethod + def start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context): + hb_thread = Heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + hb_thread.setDaemon(True) + hb_thread.start() + return hb_thread + + +class OnlineIntelligentRecognitionProcess2(IntelligentRecognitionProcess2): + __slots__ = () + + @staticmethod + def upload_video(base_dir, env, request_id, orFilePath, aiFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_or = Common(aliyunVodSdk.get_play_url, orFilePath, "or_online_%s" % request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + upload_video_thread_or.setDaemon(True) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_or.start() + upload_video_thread_ai.start() + or_url = upload_video_thread_or.get_result() + ai_url = upload_video_thread_ai.get_result() + return or_url, ai_url + + @staticmethod + def start_push_stream2(msg, push_queue, image_queue, push_ex_queue, hb_queue, context): + pushProcess = OnPushStreamProcess2(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + pushProcess.daemon = True + pushProcess.start() + return pushProcess + + @staticmethod + def start_pull_stream2(msg, context, fb_queue, pull_queue, image_queue, analyse_type, frame_num): + pullProcess = OnlinePullVideoStreamProcess2(msg, context, fb_queue, pull_queue, image_queue, analyse_type, + frame_num) + pullProcess.daemon = True + pullProcess.start() + return pullProcess + + @staticmethod + def checkPT(start_time, service_timeout, pull_process, push_process, hb_thread, push_ex_queue, pull_queue, + request_id): + 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 pull_process is not None and not pull_process.is_alive(): + while True: + if pull_queue.empty() or pull_queue.qsize() == 0: + break + pull_result = get_no_block_queue(pull_queue) + if pull_result is not None and pull_result[0] == 1: + raise ServiceException(pull_result[1], pull_result[2]) + logger.info("拉流进程异常停止, requestId: {}", request_id) + raise Exception("拉流进程异常停止!") + if hb_thread is not None and not hb_thread.is_alive(): + logger.info("心跳线程异常停止, requestId: {}", request_id) + raise Exception("心跳线程异常停止!") + if push_process is not None and not push_process.is_alive(): + while True: + if push_ex_queue.empty() or push_ex_queue.qsize() == 0: + break + push_result = get_no_block_queue(push_ex_queue) + if push_result is not None and push_result[0] == 1: + raise ServiceException(push_result[1], push_result[2]) + logger.info("推流进程异常停止, requestId: {}", request_id) + raise Exception("推流进程异常停止!") + + def run(self): + msg, context, analyse_type, ex = self._msg, self._context, self._analyse_type, None + self.build_video_path(context, msg) + request_id, base_dir, env = msg["request_id"], context["base_dir"], context["env"] + # 拉流进程、推流进程、心跳线程 + pull_process, push_process, hb_thread = None, None, None + # 事件队列、拉流队列、心跳队列、反馈队列 + event_queue, pull_queue, hb_queue, fb_queue = self.event_queue, self._pull_queue, self._hb_queue, self._fb_queue + # 推流队列、推流异常队列、图片队列 + push_queue, push_ex_queue, image_queue = self._push_queue, self._push_ex_queue, self._image_queue + service_timeout = int(context["service"]["timeout"]) + try: + # 初始化日志 + init_log(base_dir, env) + # 打印启动日志 + logger.info("开始启动实时分析进程!requestId: {}", request_id) + # 启动拉流进程(包含拉流线程, 图片上传线程) + # 拉流进程初始化时间长, 先启动 + pull_process = self.start_pull_stream2(msg, context, fb_queue, pull_queue, image_queue, analyse_type, 100) + # 启动心跳线程 + hb_thread = self.start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + # 加载算法模型 + model_array = get_model(msg, context, analyse_type) + # 启动推流进程 + push_process = self.start_push_stream2(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + # 第一个参数: 模型是否初始化 0:未初始化 1:初始化 + task_status = [0] + draw_config = {} + start_time = time() + with ThreadPoolExecutor(max_workers=3) as t: + while True: + # 检查拉流进程是否正常, 心跳线程是否正常 + self.checkPT(start_time, service_timeout, pull_process, push_process, hb_thread, push_ex_queue, + pull_queue, request_id) + # 检查推流是否异常 + push_status = get_no_block_queue(push_ex_queue) + if push_status is not None and push_status[0] == 1: + raise ServiceException(push_status[1], push_status[2]) + # 获取停止指令 + event_result = get_no_block_queue(event_queue) + if event_result: + cmdStr = event_result.get("command") + # 接收到停止指令 + if "stop" == cmdStr: + logger.info("实时任务开始停止, requestId: {}", request_id) + pull_process.sendCommand({"command": 'stop'}) + pull_result = get_no_block_queue(pull_queue) + if pull_result is None: + sleep(1) + continue + # (4, (frame_list, frame_index_list, all_frames)) + if pull_result[0] == 4: + frame_list, frame_index_list, all_frames = pull_result[1] + if len(frame_list) > 0: + # 判断是否已经初始化 + if task_status[0] == 0: + task_status[0] = 1 + for i, model in enumerate(model_array): + # (modeType, model_param, allowedList, names, rainbows) + model_conf, code = model + model_param = model_conf[1] + MODEL_CONFIG2[code][2](frame_list[0].shape[1], frame_list[0].shape[0], model_conf) + if draw_config.get("font_config") is None: + draw_config["font_config"] = model_param['font_config'] + if draw_config.get(code) is None: + draw_config[code] = {} + draw_config[code]["allowedList"] = model_conf[2] + draw_config[code]["rainbows"] = model_conf[4] + draw_config[code]["label_arrays"] = model_param['label_arraylist'] + det_array = [] + for model in model_array: + result = t.submit(self.ai_dtection, model, frame_list, frame_index_list, request_id) + det_array.append(result) + push_objs = [det.result() for det in det_array] + put_queue(push_queue, + (1, (frame_list, frame_index_list, all_frames, draw_config, push_objs)), + timeout=10) + del det_array, push_objs + del frame_list, frame_index_list, all_frames + elif pull_result[0] == 1: + put_queue(push_queue, (2, 'stop_ex'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + raise ServiceException(pull_result[1], pull_result[2]) + elif pull_result[0] == 2: + put_queue(push_queue, (2, 'stop'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + break + else: + raise Exception("未知拉流状态异常!") + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, 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: + orFilePath, aiFilePath = context["orFilePath"], context["aiFilePath"] + base_dir, env = context["base_dir"], context["env"] + or_url, ai_url, exc = "", "", None + try: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + logger.info("关闭拉流进程, requestId:{}", request_id) + pull_process.join(timeout=120) + logger.info("关闭拉流进程1, requestId:{}", request_id) + if exists(orFilePath) and exists(aiFilePath) and getsize(orFilePath) > 100: + or_url, ai_url = self.upload_video(base_dir, env, request_id, orFilePath, aiFilePath) + if or_url is None or ai_url is None: + logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + # 停止心跳线程 + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=10, is_ex=False) + hb_thread.join(timeout=120) + if exists(orFilePath): + logger.info("开始删除原视频, orFilePath: {}, requestId: {}", orFilePath, request_id) + os.remove(orFilePath) + logger.info("删除原视频成功, orFilePath: {}, requestId: {}", orFilePath, request_id) + if exists(aiFilePath): + logger.info("开始删除AI视频, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + os.remove(aiFilePath) + logger.info("删除AI视频成功, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + # 如果有异常, 检查是否有原视频和AI视频,有则上传,响应失败 + if ex: + code, msg = ex + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + video_url=or_url, + ai_video_url=ai_url), timeout=10, is_ex=False) + else: + if or_url is None or len(or_url) == 0 or ai_url is None or len(ai_url) == 0: + raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1]) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess, + video_url=or_url, + ai_video_url=ai_url), timeout=10, is_ex=False) + + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, request_id) + exc = s.code, s.msg + except Exception: + logger.error("服务异常: {}, requestId: {},", format_exc(), request_id) + exc = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + logger.info("关闭拉流进程, requestId:{}", request_id) + pull_process.join(timeout=120) + logger.info("关闭拉流进程1, requestId:{}", request_id) + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=10, is_ex=False) + hb_thread.join(timeout=120) + if exc: + code, msg = exc + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + video_url=or_url, + ai_video_url=ai_url), timeout=10, is_ex=False) + self.clear_queue() + + +class OfflineIntelligentRecognitionProcess2(IntelligentRecognitionProcess2): + __slots__ = () + + @staticmethod + def upload_video(base_dir, env, request_id, aiFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + ai_url = upload_video_thread_ai.get_result() + return ai_url + + @staticmethod + def start_push_stream2(msg, push_queue, image_queue, push_ex_queue, hb_queue, context): + pushProcess = OffPushStreamProcess2(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + pushProcess.daemon = True + pushProcess.start() + return pushProcess + + @staticmethod + def start_pull_stream2(msg, context, fb_queue, pull_queue, image_queue, analyse_type, frame_num): + pullProcess = OfflinePullVideoStreamProcess2(msg, context, fb_queue, pull_queue, image_queue, analyse_type, + frame_num) + pullProcess.daemon = True + pullProcess.start() + return pullProcess + + @staticmethod + def checkPT(start_time, service_timeout, pull_process, push_process, hb_thread, push_ex_queue, pull_queue, + request_id): + 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 pull_process is not None and not pull_process.is_alive(): + while True: + if pull_queue.empty() or pull_queue.qsize() == 0: + break + pull_result = get_no_block_queue(pull_queue) + if pull_result is not None and pull_result[0] == 1: + raise ServiceException(pull_result[1], pull_result[2]) + logger.info("拉流进程异常停止, requestId: {}", request_id) + raise Exception("拉流进程异常停止!") + if hb_thread is not None and not hb_thread.is_alive(): + logger.info("心跳线程异常停止, requestId: {}", request_id) + raise Exception("心跳线程异常停止!") + if push_process is not None and not push_process.is_alive(): + while True: + if push_ex_queue.empty() or push_ex_queue.qsize() == 0: + break + push_result = get_no_block_queue(push_ex_queue) + if push_result is not None and push_result[0] == 1: + raise ServiceException(push_result[1], push_result[2]) + logger.info("推流进程异常停止, requestId: {}", request_id) + raise Exception("推流进程异常停止!") + + def run(self): + msg, context, analyse_type, ex = self._msg, self._context, self._analyse_type, None + self.build_video_path(context, msg, is_build_or=False) + request_id, base_dir, env = msg["request_id"], context["base_dir"], context["env"] + # 拉流进程、推流进程 + pull_process, push_process = None, None + # 心跳线程 + hb_thread = None + # 事件队列、拉流队列、心跳队列、反馈队列 + event_queue, pull_queue, hb_queue, fb_queue = self.event_queue, self._pull_queue, self._hb_queue, self._fb_queue + # 推流队列、推流异常队列、图片队列 + push_queue, push_ex_queue, image_queue = self._push_queue, self._push_ex_queue, self._image_queue + try: + # 初始化日志 + init_log(base_dir, env) + # 打印启动日志 + logger.info("开始启动离线分析进程!requestId: {}", request_id) + # 启动拉流进程(包含拉流线程, 图片上传线程) + # 拉流进程初始化时间长, 先启动 + pull_process = self.start_pull_stream2(msg, context, fb_queue, pull_queue, image_queue, analyse_type, 100) + # 启动心跳线程 + hb_thread = self.start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + # 加载算法模型 + model_array = get_model(msg, context, analyse_type) + # 启动推流进程 + push_process = self.start_push_stream2(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + # 第一个参数: 模型是否初始化 0:未初始化 1:初始化 + # 第二个参数: 检测是否有问题 0: 没有问题, 1: 有问题 + task_status = [0, 0] + draw_config = {} + service_timeout = int(context["service"]["timeout"]) + start_time = time() + with ThreadPoolExecutor(max_workers=2) as t: + while True: + # 检查拉流进程是否正常, 心跳线程是否正常 + self.checkPT(start_time, service_timeout, pull_process, push_process, hb_thread, push_ex_queue, + pull_queue, request_id) + # 检查推流是否异常 + push_status = get_no_block_queue(push_ex_queue) + if push_status is not None and push_status[0] == 1: + raise ServiceException(push_status[1], push_status[2]) + # 获取停止指令 + event_result = get_no_block_queue(event_queue) + if event_result: + cmdStr = event_result.get("command") + # 接收到停止指令 + if "stop" == cmdStr: + logger.info("离线任务开始停止, requestId: {}", request_id) + pull_process.sendCommand({"command": 'stop'}) + pull_result = get_no_block_queue(pull_queue) + if pull_result is None: + sleep(1) + continue + # (4, (frame_list, frame_index_list, all_frames)) + if pull_result[0] == 4: + frame_list, frame_index_list, all_frames = pull_result[1] + if len(frame_list) > 0: + # 判断是否已经初始化 + if task_status[0] == 0: + task_status[0] = 1 + for i, model in enumerate(model_array): + model_conf, code = model + model_param = model_conf[1] + # (modeType, model_param, allowedList, names, rainbows) + MODEL_CONFIG2[code][2](frame_list[0].shape[1], frame_list[0].shape[0], + model_conf) + if draw_config.get("font_config") is None: + draw_config["font_config"] = model_param['font_config'] + if draw_config.get(code) is None: + draw_config[code] = {} + draw_config[code]["allowedList"] = model_conf[2] + draw_config[code]["rainbows"] = model_conf[4] + draw_config[code]["label_arrays"] = model_param['label_arraylist'] + # 多线程并发处理, 经过测试两个线程最优 + det_array = [] + for model in model_array: + result = t.submit(self.ai_dtection, model, frame_list, frame_index_list, request_id) + det_array.append(result) + push_objs = [det.result() for det in det_array] + put_queue(push_queue, + (1, (frame_list, frame_index_list, all_frames, draw_config, push_objs)), + timeout=10) + del det_array, push_objs + del frame_list, frame_index_list, all_frames + elif pull_result[0] == 1: + put_queue(push_queue, (2, 'stop_ex'), timeout=1, is_ex=True) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + raise ServiceException(pull_result[1], pull_result[2]) + elif pull_result[0] == 2: + logger.info("离线任务开始停止, requestId: {}", request_id) + put_queue(push_queue, (2, 'stop'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + break + else: + raise Exception("未知拉流状态异常!") + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, 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: + base_dir, env, aiFilePath = context["base_dir"], context["env"], context["aiFilePath"] + ai_url, exc = "", None + try: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + push_process.join(timeout=120) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(timeout=120) + if exists(aiFilePath) and getsize(aiFilePath) > 100: + ai_url = self.upload_video(base_dir, env, request_id, aiFilePath) + if ai_url is None: + logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + # 停止心跳线程 + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=2, is_ex=False) + hb_thread.join(timeout=120) + if exists(aiFilePath): + logger.info("开始删除AI视频, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + os.remove(aiFilePath) + logger.info("删除AI视频成功, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + # 如果有异常, 检查是否有原视频和AI视频,有则上传,响应失败 + if ex: + code, msg = ex + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + ai_video_url=ai_url), timeout=10, is_ex=False) + else: + if ai_url is None or len(ai_url) == 0: + raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1]) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess, + ai_video_url=ai_url), timeout=10, is_ex=False) + + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, request_id) + exc = s.code, s.msg + except Exception: + logger.error("服务异常: {}, requestId: {},", format_exc(), request_id) + exc = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + push_process.join(timeout=120) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(timeout=120) + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=10, is_ex=False) + hb_thread.join(timeout=120) + if exc: + code, msg = exc + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + ai_video_url=ai_url), timeout=10, is_ex=False) + self.clear_queue() + + +''' +图片识别 +''' + + +class PhotosIntelligentRecognitionProcess2(Process): + __slots__ = ("_fb_queue", "_msg", "_analyse_type", "_context", "_image_queue") + + def __init__(self, *args): + super().__init__() + self._fb_queue, self._msg, self._analyse_type, self._context = args + self._image_queue = Queue() + put_queue(self._fb_queue, message_feedback(self._msg["request_id"], + AnalysisStatus.WAITING.value, + self._analyse_type, + progress=init_progess), timeout=1, is_ex=True) + + self.build_logo(self._msg, self._context) + + @staticmethod + def build_logo(msg, context): + logo = None + if context["video"]["video_add_water"]: + logo = msg.get("logo_url") + if logo is not None and len(logo) > 0: + logo = url2Array(logo, enable_ex=False) + if logo is None: + logo = cv2.imread(join(context['base_dir'], "image/logo.png"), -1) + context['logo'] = logo + + def epidemic_prevention(self, imageUrl, model, orc, request_id): + try: + # modeType, allowedList, new_device, model, par, img_type + model_conf, code = model + modeType, model_param, allowedList = model_conf + img_type = model_param["img_type"] + image = url2Array(imageUrl) + param = [model_param, image, request_id] + dataBack = MODEL_CONFIG2[code][3](param) + if img_type == 'plate': + carCode = '' + if dataBack is None or dataBack.get("plateImage") is None or len(dataBack.get("plateImage")) == 0: + result = orc.license_plate_recognition(image, request_id) + score = '' + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + logger.error("车牌识别为空: {}", result) + carCode = '' + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + else: + result = orc.license_plate_recognition(dataBack.get("plateImage")[0], request_id) + score = dataBack.get("plateImage")[1] + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + result = orc.license_plate_recognition(image, request_id) + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + logger.error("车牌识别为空: {}", result) + carCode = '' + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + if len(carCode) > 0: + plate_result = {'type': str(3), 'modelCode': code, 'carUrl': imageUrl, + 'carCode': carCode, + 'score': score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(3), + plate_result), + timeout=1) + if img_type == 'code': + if dataBack is None or dataBack.get("type") is None: + return + # 行程码 + if dataBack.get("type") == 1 and 1 in allowedList: + # 手机号 + if dataBack.get("phoneNumberImage") is None or len(dataBack.get("phoneNumberImage")) == 0: + phoneNumberRecognition = '' + phone_score = '' + else: + phone = orc.universal_text_recognition(dataBack.get("phoneNumberImage")[0], request_id) + phone_score = dataBack.get("phoneNumberImage")[1] + if phone is None or phone.get("words_result") is None or len(phone.get("words_result")) == 0: + logger.error("手机号识别为空: {}", phone) + phoneNumberRecognition = '' + else: + phoneNumberRecognition = phone.get("words_result") + if dataBack.get("cityImage") is None or len(dataBack.get("cityImage")) == 0: + cityRecognition = '' + city_score = '' + else: + city = orc.universal_text_recognition(dataBack.get("cityImage")[0], request_id) + city_score = dataBack.get("cityImage")[1] + if city is None or city.get("words_result") is None or len(city.get("words_result")) == 0: + logger.error("城市识别为空: {}", city) + cityRecognition = '' + else: + cityRecognition = city.get("words_result") + if len(phoneNumberRecognition) > 0 or len(cityRecognition) > 0: + trip_result = {'type': str(1), + 'modelCode': code, + 'imageUrl': imageUrl, + 'phoneNumberRecognition': phoneNumberRecognition, + 'phone_sorce': phone_score, + 'cityRecognition': cityRecognition, + 'city_score': city_score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(1), + trip_result), + timeout=1) + if dataBack.get("type") == 2 and 2 in allowedList: + if dataBack.get("nameImage") is None or len(dataBack.get("nameImage")) == 0: + nameRecognition = '' + name_score = '' + else: + name = orc.universal_text_recognition(dataBack.get("nameImage")[0], request_id) + name_score = dataBack.get("nameImage")[1] + if name is None or name.get("words_result") is None or len(name.get("words_result")) == 0: + logger.error("名字识别为空: {}", name) + nameRecognition = '' + else: + nameRecognition = name.get("words_result") + + if dataBack.get("phoneNumberImage") is None or len(dataBack.get("phoneNumberImage")) == 0: + phoneNumberRecognition = '' + phone_score = '' + else: + phone = orc.universal_text_recognition(dataBack.get("phoneNumberImage")[0], request_id) + phone_score = dataBack.get("phoneNumberImage")[1] + if phone is None or phone.get("words_result") is None or len(phone.get("words_result")) == 0: + logger.error("手机号识别为空: {}", phone) + phoneNumberRecognition = '' + else: + phoneNumberRecognition = phone.get("words_result") + if dataBack.get("hsImage") is None or len(dataBack.get("hsImage")) == 0: + hsRecognition = '' + hs_score = '' + else: + hs = orc.universal_text_recognition(dataBack.get("hsImage")[0], request_id) + hs_score = dataBack.get("hsImage")[1] + if hs is None or hs.get("words_result") is None or len(hs.get("words_result")) == 0: + logger.error("核酸识别为空: {}", hs) + hsRecognition = '' + else: + hsRecognition = hs.get("words_result") + if len(nameRecognition) > 0 or len(phoneNumberRecognition) > 0 or len(hsRecognition) > 0: + healthy_result = {'type': str(2), + 'modelCode': code, + 'imageUrl': imageUrl, + 'color': dataBack.get("color"), + 'nameRecognition': nameRecognition, + 'name_score': name_score, + 'phoneNumberRecognition': phoneNumberRecognition, + 'phone_score': phone_score, + 'hsRecognition': hsRecognition, + 'hs_score': hs_score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(2), + healthy_result), + timeout=1) + except ServiceException as s: + raise s + except Exception as e: + logger.error("模型分析异常: {}, requestId: {}", format_exc(), request_id) + raise e + + ''' + # 防疫模型 + ''' + + def epidemicPrevention(self, imageUrls, model, base_dir, env, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + orc = OcrBaiduSdk(base_dir, env) + obj_list = [] + for imageUrl in imageUrls: + obj = t.submit(self.epidemic_prevention, imageUrl, model, orc, request_id) + obj_list.append(obj) + for r in obj_list: + r.result(60) + + def image_recognition(self, imageUrl, mod, image_queue, logo, request_id): + try: + model_conf, code = mod + model_param = model_conf[1] + image = url2Array(imageUrl) + MODEL_CONFIG2[code][2](image.shape[1], image.shape[0], model_conf) + p_result = MODEL_CONFIG2[code][3]([[image], [0], model_param, request_id])[0] + if p_result is None or len(p_result) < 3 or p_result[2] is None or len(p_result[2]) == 0: + return + if logo: + image = add_water_pic(image, logo, request_id) + # (modeType, model_param, allowedList, names, rainbows) + allowedList = model_conf[2] + label_arraylist = model_param['label_arraylist'] + font_config = model_param['font_config'] + rainbows = model_conf[4] + det_xywh = {code: {}} + ai_result_list = p_result[2] + for ai_result in ai_result_list: + box, score, cls = xywh2xyxy2(ai_result) + # 如果检测目标在识别任务中,继续处理 + if cls in allowedList: + label_array = label_arraylist[cls] + color = rainbows[cls] + cd = det_xywh[code].get(cls) + 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]) + logger.info(" line813 ai_result_list{}, det_xywh: {}, allowedList:{} ".format( ai_result_list, det_xywh,allowedList) ) + if len(det_xywh) > 0: + put_queue(image_queue, (1, (det_xywh, imageUrl, image, font_config, ""))) + except ServiceException as s: + raise s + except Exception as e: + logger.error("模型分析异常: {}, requestId: {}", format_exc(), self._msg.get("request_id")) + raise e + + def publicIdentification(self, imageUrls, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + obj_list = [] + logger.info(' publicIdentification line823') + for imageUrl in imageUrls: + obj = t.submit(self.image_recognition, imageUrl, mod, image_queue, logo, request_id) + obj_list.append(obj) + for r in obj_list: + r.result(60) + + ''' + 1. imageUrls: 图片url数组,多张图片 + 2. mod: 模型对象 + 3. image_queue: 图片队列 + ''' + + def baiduRecognition(self, imageUrls, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + thread_result = [] + for imageUrl in imageUrls: + obj = t.submit(self.baidu_recognition, imageUrl, mod, image_queue, logo, request_id) + thread_result.append(obj) + for r in thread_result: + r.result() + + def baidu_recognition(self, imageUrl, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + try: + # (modeType, model_param, allowedList, (vehicle_names, person_names), rainbows) + model_conf, code = mod + model_param = model_conf[1] + allowedList = model_conf[2] + rainbows = model_conf[4] + # 图片转数组 + img = url2Array(imageUrl) + MODEL_CONFIG2[code][2](img.shape[1], img.shape[0], model_conf) + vehicle_label_arrays = model_param["vehicle_label_arrays"] + person_label_arrays = model_param["person_label_arrays"] + font_config = model_param["font_config"] + obj_list = [] + for target in allowedList: + parm = [model_param, target, imageUrl, request_id] + reuslt = t.submit(self.baidu_method, code, parm, img, image_queue, vehicle_label_arrays, + person_label_arrays, font_config, rainbows, logo) + obj_list.append(reuslt) + for r in obj_list: + r.result() + except ServiceException as s: + raise s + except Exception as e: + logger.error("百度AI分析异常: {}, requestId: {}", format_exc(), request_id) + raise e + + @staticmethod + def baidu_method(code, parm, img, image_queue, vehicle_label_arrays, person_label_arrays, font_config, + rainbows, logo): + # [model_param, target, imageUrl, request_id]] + request_id = parm[3] + target = parm[1] + image_url = parm[2] + result = MODEL_CONFIG2[code][3](parm) + if target == BaiduModelTarget.VEHICLE_DETECTION.value[1] and result is not None: + vehicleInfo = result.get("vehicle_info") + if vehicleInfo is not None and len(vehicleInfo) > 0: + det_xywh = {code: {}} + copy_frame = img.copy() + for i, info in enumerate(vehicleInfo): + value = VehicleEnumVALUE.get(info.get("type")) + target_num = value.value[2] + label_array = vehicle_label_arrays[target_num] + color = rainbows[target_num] + if value is None: + logger.error("车辆识别出现未支持的目标类型!type:{}, requestId:{}", info.get("type"), request_id) + return + left_top = (int(info.get("location").get("left")), int(info.get("location").get("top"))) + right_top = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top"))) + right_bottom = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + left_bottom = (int(info.get("location").get("left")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + box = [left_top, right_top, right_bottom, left_bottom] + score = float("%.2f" % info.get("probability")) + if logo: + copy_frame = add_water_pic(copy_frame, logo, request_id) + if det_xywh[code].get(target) is None: + det_xywh[code][target] = [[target, box, score, label_array, color]] + else: + det_xywh[code][target].append([target, box, score, label_array, color]) + info["id"] = str(i) + if len(det_xywh[code]) > 0: + result["type"] = str(target) + result["modelCode"] = code + put_queue(image_queue, (1, (det_xywh, image_url, copy_frame, font_config, result))) + # 人体识别 + if target == BaiduModelTarget.HUMAN_DETECTION.value[1] and result is not None: + personInfo = result.get("person_info") + personNum = result.get("person_num") + if personNum is not None and personNum > 0 and personInfo is not None and len(personInfo) > 0: + det_xywh = {code: {}} + copy_frame = img.copy() + for i, info in enumerate(personInfo): + left_top = (int(info.get("location").get("left")), int(info.get("location").get("top"))) + right_top = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top"))) + right_bottom = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + left_bottom = (int(info.get("location").get("left")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + box = [left_top, right_top, right_bottom, left_bottom] + score = float("%.2f" % info.get("location").get("score")) + label_array = person_label_arrays[0] + color = rainbows[0] + if logo: + copy_frame = add_water_pic(copy_frame, logo, request_id) + if det_xywh[code].get(target) is None: + det_xywh[code][target] = [[target, box, score, label_array, color]] + else: + det_xywh[code][target].append([target, box, score, label_array, color]) + info["id"] = str(i) + if len(det_xywh[code]) > 0: + result["type"] = str(target) + result["modelCode"] = code + put_queue(image_queue, (1, (det_xywh, image_url, copy_frame, font_config, result))) + # 人流量 + if target == BaiduModelTarget.PEOPLE_COUNTING.value[1] and result is not None: + base64Image = result.get("image") + if base64Image is not None and len(base64Image) > 0: + baiduImage = base64.b64decode(base64Image) + result["type"] = str(target) + result["modelCode"] = code + del result["image"] + put_queue(image_queue, (1, (None, image_url, baiduImage, None, result))) + + @staticmethod + def start_File_upload(*args): + fb_queue, context, msg, image_queue, analyse_type = args + image_thread = ImageTypeImageFileUpload(fb_queue, context, msg, image_queue, analyse_type) + image_thread.setDaemon(True) + image_thread.start() + return image_thread + + def run(self): + fb_queue, msg, analyse_type, context = self._fb_queue, self._msg, self._analyse_type, self._context + request_id, logo, image_queue = msg["request_id"], context['logo'], self._image_queue + base_dir, env = context["base_dir"], context["env"] + imageUrls = msg["image_urls"] + image_thread = None + with ThreadPoolExecutor(max_workers=3) as t: + try: + init_log(base_dir, env) + logger.info("开始启动图片识别进程, requestId: {}", request_id) + model_array = get_model(msg, context, analyse_type) + image_thread = self.start_File_upload(fb_queue, context, msg, image_queue, analyse_type) + task_list = [] + for model in model_array: + # 百度模型逻辑 + if model[1] == ModelType2.BAIDU_MODEL.value[1]: + result = t.submit(self.baiduRecognition, imageUrls, model, image_queue, logo, request_id) + task_list.append(result) + # 防疫模型 + elif model[1] == ModelType2.EPIDEMIC_PREVENTION_MODEL.value[1]: + result = t.submit(self.epidemicPrevention, imageUrls, model, base_dir, env, request_id) + task_list.append(result) + # 车牌模型 + elif model[1] == ModelType2.PLATE_MODEL.value[1]: + result = t.submit(self.epidemicPrevention, imageUrls, model, base_dir, env, request_id) + task_list.append(result) + else: + result = t.submit(self.publicIdentification, imageUrls, model, image_queue, logo, request_id) + task_list.append(result) + for r in task_list: + r.result(timeout=60) + logger.info(' line993: result:-------- ' ) + if image_thread and not image_thread.is_alive(): + raise Exception("图片识别图片上传线程异常停止!!!") + if image_thread and image_thread.is_alive(): + put_queue(image_queue, (2, 'stop'), timeout=10, is_ex=True) + image_thread.join(120) + logger.info("图片进程任务完成,requestId:{}", request_id) + put_queue(fb_queue, message_feedback(request_id, + AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess), timeout=10, is_ex=True) + except ServiceException as s: + logger.error("图片分析异常,异常编号:{}, 异常描述:{}, requestId:{}", s.code, s.msg, request_id) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + s.code, + s.msg)) + except Exception: + logger.error("图片分析异常: {}, requestId:{}", format_exc(), request_id) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1])) + finally: + if image_thread and image_thread.is_alive(): + put_queue(image_queue, (2, 'stop'), timeout=10, is_ex=True) + image_thread.join(120) + clear_queue(image_queue) + + +""" +"models": [{ + "code": "模型编号", + "categories":[{ + "id": "模型id", + "config": { + "k1": "v1", + "k2": "v2" + } + }] +}] +""" + + +def get_model(msg, context, analyse_type): + # 初始变量 + request_id, base_dir, gpu_name, env = msg["request_id"], context["base_dir"], context["gpu_name"], context["env"] + models, model_num_limit = msg["models"], context["service"]["model"]['limit'] + try: + # 实时、离线元组 + analyse_type_tuple = (AnalysisType.ONLINE.value, AnalysisType.OFFLINE.value) + # (实时、离线)检查模型组合, 目前只支持3个模型组合 + if analyse_type in analyse_type_tuple: + if len(models) > model_num_limit: + raise ServiceException(ExceptionType.MODEL_GROUP_LIMIT_EXCEPTION.value[0], + ExceptionType.MODEL_GROUP_LIMIT_EXCEPTION.value[1]) + modelArray, codeArray = [], set() + for model in models: + # 模型编码 + code = model["code"] + # 检验code是否重复 + if code in codeArray: + raise ServiceException(ExceptionType.MODEL_DUPLICATE_EXCEPTION.value[0], + ExceptionType.MODEL_DUPLICATE_EXCEPTION.value[1]) + codeArray.add(code) + # 检测目标数组 + needed_objectsIndex = list(set([int(category["id"]) for category in model["categories"]])) + logger.info("模型编号: {}, 检查目标: {}, requestId: {}", code, needed_objectsIndex, request_id) + model_method = MODEL_CONFIG2.get(code) + if model_method is None: + logger.error("未匹配到对应的模型, requestId:{}", request_id) + raise ServiceException(ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[0], + ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[1]) + # 检查cpu资源、gpu资源 + check_cpu(base_dir, request_id) + gpu_ids = check_gpu_resource(request_id) + # 如果实时识别、离线识别 + if analyse_type in analyse_type_tuple: + if model["is_video"] == "1": + mod = model_method[0](gpu_ids[0], needed_objectsIndex, request_id, gpu_name, base_dir, env) + modelArray.append((mod.model_conf, code)) + else: + raise ServiceException(ExceptionType.MODEL_NOT_SUPPORT_VIDEO_EXCEPTION.value[0], + ExceptionType.MODEL_NOT_SUPPORT_VIDEO_EXCEPTION.value[1], + model_method[1].value[2]) + # 如果是图片识别 + if analyse_type == AnalysisType.IMAGE.value: + if model["is_image"] == "1": + mod = model_method[0](gpu_ids[0], needed_objectsIndex, request_id, gpu_name, base_dir, env) + modelArray.append((mod.model_conf, code)) + else: + raise ServiceException(ExceptionType.MODEL_NOT_SUPPORT_IMAGE_EXCEPTION.value[0], + ExceptionType.MODEL_NOT_SUPPORT_IMAGE_EXCEPTION.value[1], + model_method[1].value[2]) + if len(modelArray) == 0: + raise ServiceException(ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[0], + ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[1]) + return modelArray + except ServiceException as s: + raise s + except Exception: + logger.error("模型配置处理异常: {}, request_id: {}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) diff --git a/vodsdk/concurrency/IntelligentRecognitionProcess_20250106.py b/vodsdk/concurrency/IntelligentRecognitionProcess_20250106.py new file mode 100644 index 0000000..3e56ce0 --- /dev/null +++ b/vodsdk/concurrency/IntelligentRecognitionProcess_20250106.py @@ -0,0 +1,1444 @@ +# -*- coding: utf-8 -*- +import base64 +import os +from concurrent.futures import ThreadPoolExecutor +from os.path import join, exists, getsize +from time import time, sleep +from traceback import format_exc + +import cv2 + +from multiprocessing import Process, Queue + +import numpy as np +from loguru import logger + +from common.Constant import init_progess, success_progess +from concurrency.FileUploadThread import ImageTypeImageFileUpload +from concurrency.HeartbeatThread import Heartbeat + +from concurrency.PullVideoStreamProcess import OnlinePullVideoStreamProcess, OfflinePullVideoStreamProcess +from concurrency.PushVideoStreamProcess import OnPushStreamProcess, OffPushStreamProcess + +from util.GPUtils import check_gpu_resource +from util.LogUtils import init_log +from concurrency.CommonThread import Common +from concurrency.PullStreamThread import RecordingPullStreamThread +from concurrency.RecordingHeartbeatThread import RecordingHeartbeat +from enums.AnalysisStatusEnum import AnalysisStatus +from enums.AnalysisTypeEnum import AnalysisType +from enums.ExceptionEnum import ExceptionType +from enums.ModelTypeEnum import ModelType +from enums.RecordingStatusEnum import RecordingStatus +from util.AliyunSdk import ThAliyunVodSdk +from util.CpuUtils import check_cpu +from util.Cv2Utils import write_or_video, push_video_stream, close_all_p +from entity.FeedBack import message_feedback, recording_feedback +from exception.CustomerException import ServiceException +from util.ImageUtils import url2Array, add_water_pic +from util.ModelUtils import MODEL_CONFIG +from util.OcrBaiduSdk import OcrBaiduSdk + +from enums.BaiduSdkEnum import VehicleEnumVALUE +from enums.ModelTypeEnum import BaiduModelTarget +from util.PlotsUtils import xywh2xyxy2 +from util.QueUtil import put_queue, get_no_block_queue, clear_queue +from util.TimeUtils import now_date_to_str, YMDHMSF +from util.CpuUtils import print_cpu_status +import inspect +class IntelligentRecognitionProcess(Process): + __slots__ = ('_fb_queue', '_msg', '_analyse_type', '_context', 'event_queue', '_pull_queue', '_hb_queue', + "_image_queue", "_push_queue", '_push_ex_queue') + + def __init__(self, *args): + super().__init__() + # 入参 + self._fb_queue, self._msg, self._analyse_type, self._context = args + # 初始化参数 + self.event_queue, self._pull_queue, self._hb_queue, self._image_queue, self._push_queue, self._push_ex_queue = \ + Queue(), Queue(10), Queue(), Queue(), Queue(), Queue() + + # 发送waitting消息 + put_queue(self._fb_queue, message_feedback(self._msg["request_id"], AnalysisStatus.WAITING.value, + self._analyse_type, progress=init_progess), timeout=2, is_ex=True) + self._storage_source = self._context['service']['storage_source'] + + def sendEvent(self, eBody): + put_queue(self.event_queue, eBody, timeout=2, is_ex=True) + + def clear_queue(self): + clear_queue(self.event_queue) + clear_queue(self._pull_queue) + clear_queue(self._hb_queue) + clear_queue(self._image_queue) + clear_queue(self._push_queue) + clear_queue(self._push_ex_queue) + + @staticmethod + def build_video_path(context, msg, is_build_or=True): + random_time = now_date_to_str(YMDHMSF) + pre_path = '%s/%s%s' % (context["base_dir"], context["video"]["file_path"], random_time) + end_path = '%s%s' % (msg["request_id"], ".mp4") + if is_build_or: + context["orFilePath"] = '%s%s%s' % (pre_path, "_on_or_", end_path) + context["aiFilePath"] = '%s%s%s' % (pre_path, "_on_ai_", end_path) + + @staticmethod + def start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context): + hb_thread = Heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + hb_thread.setDaemon(True) + hb_thread.start() + return hb_thread + + + + + +class OnlineIntelligentRecognitionProcess(IntelligentRecognitionProcess): + __slots__ = () + + @staticmethod + def start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context): + pushProcess = OnPushStreamProcess(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + pushProcess.daemon = True + pushProcess.start() + return pushProcess + + @staticmethod + def start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, frame_num): + pullProcess = OnlinePullVideoStreamProcess(msg, context, fb_queue, pull_queue, image_queue, analyse_type, + frame_num) + pullProcess.daemon = True + pullProcess.start() + return pullProcess + + + def upload_video(self,base_dir, env, request_id, orFilePath, aiFilePath): + if self._storage_source==1: + minioSdk = MinioSdk(base_dir, env, request_id ) + upload_video_thread_or = Common(minioSdk.put_object, orFilePath, "%s/or_online.mp4" % request_id) + upload_video_thread_ai = Common(minioSdk.put_object, aiFilePath, "%s/ai_online.mp4" % request_id) + else: + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_or = Common(aliyunVodSdk.get_play_url, orFilePath, "or_online_%s" % request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + + + upload_video_thread_or.setDaemon(True) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_or.start() + upload_video_thread_ai.start() + or_url = upload_video_thread_or.get_result() + ai_url = upload_video_thread_ai.get_result() + return or_url, ai_url + ''' + @staticmethod + def upload_video(base_dir, env, request_id, orFilePath, aiFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_or = Common(aliyunVodSdk.get_play_url, orFilePath, "or_online_%s" % request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + upload_video_thread_or.setDaemon(True) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_or.start() + upload_video_thread_ai.start() + or_url = upload_video_thread_or.get_result() + ai_url = upload_video_thread_ai.get_result() + return or_url, ai_url + ''' + + @staticmethod + def ai_normal_dtection(model, frame, request_id): + model_conf, code = model + retResults = MODEL_CONFIG[code][3]([model_conf, frame, request_id])[0] + if type(retResults) is np.ndarray or len(retResults) == 0: + ret = retResults + if type(retResults) is np.ndarray: + ret = retResults.tolist() + else: + ret = retResults[2] + return code, ret + + @staticmethod + def obj_det(self, model_array, frame, task_status, cframe, tt, request_id): + push_obj = [] + if task_status[1] == 1: + dtection_result = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result.append(result) + for d in dtection_result: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) == 0: + task_status[1] = 0 + if task_status[1] == 0: + if cframe % 30 == 0: + dtection_result1 = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result1.append(result) + for d in dtection_result1: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) > 0: + task_status[1] = 1 + return push_obj + + @staticmethod + def checkPT(start_time, service_timeout, pull_process, push_process, hb_thread, push_ex_queue, pull_queue, + request_id): + 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 pull_process is not None and not pull_process.is_alive(): + while True: + if pull_queue.empty() or pull_queue.qsize() == 0: + break + pull_result = get_no_block_queue(pull_queue) + if pull_result is not None and pull_result[0] == 1: + raise ServiceException(pull_result[1], pull_result[2]) + logger.info("拉流进程异常停止, requestId: {}", request_id) + raise Exception("拉流进程异常停止!") + if hb_thread is not None and not hb_thread.is_alive(): + logger.info("心跳线程异常停止, requestId: {}", request_id) + raise Exception("心跳线程异常停止!") + if push_process is not None and not push_process.is_alive(): + while True: + if push_ex_queue.empty() or push_ex_queue.qsize() == 0: + break + push_result = get_no_block_queue(push_ex_queue) + if push_result is not None and push_result[0] == 1: + raise ServiceException(push_result[1], push_result[2]) + logger.info("推流进程异常停止, requestId: {}", request_id) + raise Exception("推流进程异常停止!") + + def run(self): + msg, context, analyse_type = self._msg, self._context, self._analyse_type + self.build_video_path(context, msg) + request_id = msg["request_id"] + base_dir, env = context["base_dir"], context["env"] + service_timeout = int(context["service"]["timeout"]) + ex = None + # 拉流进程、推流进程、心跳线程 + pull_process, push_process, hb_thread = None, None, None + + # 事件队列、拉流队列、心跳队列、反馈队列 + event_queue, pull_queue, hb_queue, fb_queue = self.event_queue, self._pull_queue, self._hb_queue, self._fb_queue + + # 推流队列、推流异常队列、图片队列 + push_queue, push_ex_queue, image_queue = self._push_queue, self._push_ex_queue, self._image_queue + try: + # 初始化日志 + init_log(base_dir, env) + # 打印启动日志 + logger.info("开始启动实时分析进程!requestId: {}", request_id) + + # 启动拉流进程(包含拉流线程, 图片上传线程,mqtt读取线程) + # 拉流进程初始化时间长, 先启动 + pull_process = self.start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, 25) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #7.0, + # 启动心跳线程 + hb_thread = self.start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + + + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #7.0, + # 加载算法模型 + model_array = get_model(msg, context, analyse_type) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #9.5 + # 启动推流进程 + push_process = self.start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + # 第一个参数: 模型是否初始化 0:未初始化 1:初始化 + # 第二个参数: 检测是否有问题 0: 没有问题, 1: 有问题 + task_status = [0, 0] + draw_config = {} + start_time = time() + # 识别2个线程性能最优 + with ThreadPoolExecutor(max_workers=2) as t: + # 可能使用模型组合, 模型组合最多3个模型, 1对3, 上面的2个线程对应6个线程 + with ThreadPoolExecutor(max_workers=6) as tt: + while True: + # 检查拉流进程是否正常, 心跳线程是否正常 + self.checkPT(start_time, service_timeout, pull_process, push_process, hb_thread, push_ex_queue, + pull_queue, request_id) + # 检查推流是否异常 + push_status = get_no_block_queue(push_ex_queue) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #9.5,11.2 + if push_status is not None and push_status[0] == 1: + raise ServiceException(push_status[1], push_status[2]) + # 获取停止指令 + event_result = get_no_block_queue(event_queue) + + if event_result: + cmdStr = event_result.get("command") + + # 接收到停止指令 + if "stop" == cmdStr: + logger.info("实时任务开始停止, requestId: {}", request_id) + pull_process.sendCommand({"command": 'stop'}) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + pull_result = get_no_block_queue(pull_queue) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + if pull_result is None: + sleep(1) + continue + # (4, (frame_list, frame_index_list, all_frames)) + if pull_result[0] == 4: + frame_list, frame_index_list, all_frames = pull_result[1] + if len(frame_list) > 0: + # 判断是否已经初始化 + if task_status[0] == 0: + task_status[0] = 1 + for i, model in enumerate(model_array): + model_conf, code = model + model_param = model_conf[1] + # (modeType, model_param, allowedList, names, rainbows) + MODEL_CONFIG[code][2](frame_list[0].shape[1], frame_list[0].shape[0], + model_conf) + if draw_config.get("font_config") is None: + draw_config["font_config"] = model_param['font_config'] + if draw_config.get(code) is None: + draw_config[code] = {} + draw_config[code]["allowedList"] = model_conf[2] + draw_config[code]["rainbows"] = model_conf[4] + draw_config[code]["label_arrays"] = model_param['label_arraylist'] + if "label_dict" in model_param: + draw_config[code]["label_dict"] = model_param['label_dict'] + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + # 多线程并发处理, 经过测试两个线程最优 + det_array = [] + for i, frame in enumerate(frame_list): + det_result = t.submit(self.obj_det, self, model_array, frame, task_status, + frame_index_list[i], tt, request_id) + det_array.append(det_result) + push_objs = [det.result() for det in det_array] + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + put_queue(push_queue, + (1, (frame_list, frame_index_list, all_frames, draw_config, push_objs)), + timeout=2, is_ex=True) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + del det_array, push_objs + del frame_list, frame_index_list, all_frames + elif pull_result[0] == 1: + # 拉流发生异常 + put_queue(push_queue, (2, 'stop_ex'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + raise ServiceException(pull_result[1], pull_result[2]) + elif pull_result[0] == 2: + put_queue(push_queue, (2, 'stop'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + break + else: + raise Exception("未知拉流状态异常!") + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, 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: + orFilePath, aiFilePath = context["orFilePath"], context["aiFilePath"] + base_dir, env = context["base_dir"], context["env"] + or_url, ai_url, exc = "", "", None + try: + # 如果拉流进程存在, 关闭拉流进程(拉流线程、图片上传线程) + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + logger.info("关闭拉流进程, requestId:{}", request_id) + pull_process.join(timeout=120) + logger.info("关闭拉流进程1, requestId:{}", request_id) + if exists(orFilePath) and exists(aiFilePath) and getsize(orFilePath) > 100: + or_url, ai_url = self.upload_video(base_dir, env, request_id, orFilePath, aiFilePath) + if or_url is None or ai_url is None: + logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + # 停止心跳线程 + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=1) + hb_thread.join(timeout=120) + if exists(orFilePath): + logger.info("开始删除原视频, orFilePath: {}, requestId: {}", orFilePath, request_id) + os.remove(orFilePath) + logger.info("删除原视频成功, orFilePath: {}, requestId: {}", orFilePath, request_id) + if exists(aiFilePath): + logger.info("开始删除AI视频, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + os.remove(aiFilePath) + logger.info("删除AI视频成功, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + # 如果有异常, 检查是否有原视频和AI视频,有则上传,响应失败 + if ex: + code, msg = ex + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + video_url=or_url, + ai_video_url=ai_url), timeout=2, is_ex=False) + else: + if or_url is None or len(or_url) == 0 or ai_url is None or len(ai_url) == 0: + raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1]) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess, + video_url=or_url, + ai_video_url=ai_url), timeout=2, is_ex=False) + + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, request_id) + exc = s.code, s.msg + except Exception: + logger.error("服务异常: {}, requestId: {},", format_exc(), request_id) + exc = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + logger.info("关闭拉流进程, requestId:{}", request_id) + pull_process.join(timeout=120) + logger.info("关闭拉流进程1, requestId:{}", request_id) + if exc: + code, msg = exc + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + video_url=or_url, + ai_video_url=ai_url), timeout=2, is_ex=False) + logger.info("清理队列, requestId:{}", request_id) + self.clear_queue() + logger.info("清理队列完成, requestId:{}", request_id) + + +class OfflineIntelligentRecognitionProcess(IntelligentRecognitionProcess): + __slots__ = () + + def upload_video(self,base_dir, env, request_id, aiFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + if self._storage_source==1: + minioSdk = MinioSdk(base_dir, env, request_id ) + upload_video_thread_ai = Common(minioSdk.put_object, aiFilePath, "%s/ai_online.mp4" % request_id) + else: + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + ai_url = upload_video_thread_ai.get_result() + return ai_url + + ''' + @staticmethod + def upload_video(base_dir, env, request_id, aiFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + ai_url = upload_video_thread_ai.get_result() + return ai_url + ''' + @staticmethod + def ai_normal_dtection(model, frame, request_id): + model_conf, code = model + retResults = MODEL_CONFIG[code][3]([model_conf, frame, request_id])[0] + if type(retResults) is np.ndarray or len(retResults) == 0: + ret = retResults + if type(retResults) is np.ndarray: + ret = retResults.tolist() + else: + ret = retResults[2] + return code, ret + + @staticmethod + def obj_det(self, model_array, frame, task_status, cframe, tt, request_id): + push_obj = [] + if task_status[1] == 1: + dtection_result = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result.append(result) + for d in dtection_result: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) == 0: + task_status[1] = 0 + if task_status[1] == 0: + if cframe % 30 == 0: + dtection_result1 = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result1.append(result) + for d in dtection_result1: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) > 0: + task_status[1] = 1 + return push_obj + + @staticmethod + def start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context): + pushProcess = OffPushStreamProcess(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + pushProcess.daemon = True + pushProcess.start() + return pushProcess + + @staticmethod + def start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, frame_num): + pullProcess = OfflinePullVideoStreamProcess(msg, context, fb_queue, pull_queue, image_queue, analyse_type, + frame_num) + pullProcess.daemon = True + pullProcess.start() + return pullProcess + + @staticmethod + def checkPT(service_timeout, start_time, pull_process, push_process, hb_thread, push_ex_queue, pull_queue, + request_id): + 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 pull_process is not None and not pull_process.is_alive(): + while True: + if pull_queue.empty() or pull_queue.qsize() == 0: + break + pull_result = get_no_block_queue(pull_queue) + if pull_result is not None and pull_result[0] == 1: + raise ServiceException(pull_result[1], pull_result[2]) + logger.info("拉流进程异常停止, requestId: {}", request_id) + raise Exception("拉流进程异常停止!") + if hb_thread is not None and not hb_thread.is_alive(): + logger.info("心跳线程异常停止, requestId: {}", request_id) + raise Exception("心跳线程异常停止!") + if push_process is not None and not push_process.is_alive(): + while True: + if push_ex_queue.empty() or push_ex_queue.qsize() == 0: + break + push_result = get_no_block_queue(push_ex_queue) + if push_result is not None and push_result[0] == 1: + raise ServiceException(push_result[1], push_result[2]) + logger.info("推流进程异常停止, requestId: {}", request_id) + raise Exception("推流进程异常停止!") + + def run(self): + msg, context, analyse_type, ex = self._msg, self._context, self._analyse_type, None + self.build_video_path(context, msg, is_build_or=False) + request_id, base_dir, env = msg["request_id"], context["base_dir"], context["env"] + # 拉流进程、推流进程、心跳线程 + pull_process, push_process, hb_thread = None, None, None + service_timeout = int(context["service"]["timeout"]) + # 事件队列、拉流队列、心跳队列、反馈队列 + event_queue, pull_queue, hb_queue, fb_queue = self.event_queue, self._pull_queue, self._hb_queue, self._fb_queue + # 推流队列、推流异常队列、图片队列 + push_queue, push_ex_queue, image_queue = self._push_queue, self._push_ex_queue, self._image_queue + try: + # 初始化日志 + init_log(base_dir, env) + # 打印启动日志 + logger.info("开始启动离线分析进程!requestId: {}", request_id) + # 启动拉流进程(包含拉流线程, 图片上传线程) + # 拉流进程初始化时间长, 先启动 + pull_process = self.start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, 25) + # 启动心跳线程 + hb_thread = self.start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + # 加载算法模型 + model_array = get_model(msg, context, analyse_type) + # 启动推流进程 + push_process = self.start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + # 第一个参数: 模型是否初始化 0:未初始化 1:初始化 + # 第二个参数: 检测是否有问题 0: 没有问题, 1: 有问题 + task_status = [0, 0] + draw_config = {} + start_time = time() + # 识别2个线程性能最优 + with ThreadPoolExecutor(max_workers=2) as t: + # 可能使用模型组合, 模型组合最多3个模型, 1对3, 上面的2个线程对应6个线程 + with ThreadPoolExecutor(max_workers=6) as tt: + while True: + # 检查拉流进程是否正常, 心跳线程是否正常 + self.checkPT(service_timeout, start_time, pull_process, push_process, hb_thread, push_ex_queue, + pull_queue, request_id) + # 检查推流是否异常 + push_status = get_no_block_queue(push_ex_queue) + if push_status is not None and push_status[0] == 1: + raise ServiceException(push_status[1], push_status[2]) + # 获取停止指令 + event_result = get_no_block_queue(event_queue) + if event_result: + cmdStr = event_result.get("command") + # 接收到停止指令 + if "stop" == cmdStr: + logger.info("离线任务开始停止, requestId: {}", request_id) + pull_process.sendCommand({"command": 'stop'}) + pull_result = get_no_block_queue(pull_queue) + if pull_result is None: + sleep(1) + continue + # (4, (frame_list, frame_index_list, all_frames)) + if pull_result[0] == 4: + frame_list, frame_index_list, all_frames = pull_result[1] + if len(frame_list) > 0: + # 判断是否已经初始化 + if task_status[0] == 0: + task_status[0] = 1 + for i, model in enumerate(model_array): + model_conf, code = model + model_param = model_conf[1] + # (modeType, model_param, allowedList, names, rainbows) + MODEL_CONFIG[code][2](frame_list[0].shape[1], frame_list[0].shape[0], + model_conf) + if draw_config.get("font_config") is None: + draw_config["font_config"] = model_param['font_config'] + if draw_config.get(code) is None: + draw_config[code] = {} + draw_config[code]["allowedList"] = model_conf[2] + draw_config[code]["rainbows"] = model_conf[4] + draw_config[code]["label_arrays"] = model_param['label_arraylist'] + if "label_dict" in model_param: + draw_config[code]["label_dict"] = model_param['label_dict'] + det_array = [] + for i, frame in enumerate(frame_list): + det_result = t.submit(self.obj_det, self, model_array, frame, task_status, + frame_index_list[i], tt, request_id) + det_array.append(det_result) + push_objs = [det.result() for det in det_array] + put_queue(push_queue, + (1, (frame_list, frame_index_list, all_frames, draw_config, push_objs)), + timeout=2, is_ex=True) + del det_array, push_objs + del frame_list, frame_index_list, all_frames + elif pull_result[0] == 1: + put_queue(push_queue, (2, 'stop_ex'), timeout=1, is_ex=True) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + raise ServiceException(pull_result[1], pull_result[2]) + elif pull_result[0] == 2: + logger.info("离线任务开始停止, requestId: {}", request_id) + put_queue(push_queue, (2, 'stop'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + break + else: + raise Exception("未知拉流状态异常!") + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, 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: + base_dir, env, aiFilePath = context["base_dir"], context["env"], context["aiFilePath"] + ai_url, exc = "", None + try: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + push_process.join(timeout=120) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(timeout=120) + if exists(aiFilePath) and getsize(aiFilePath) > 100: + ai_url = self.upload_video(base_dir, env, request_id, aiFilePath) + if ai_url is None: + logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + # 停止心跳线程 + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=1) + hb_thread.join(timeout=120) + if exists(aiFilePath): + logger.info("开始删除AI视频, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + os.remove(aiFilePath) + logger.info("删除AI视频成功, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + # 如果有异常, 检查是否有原视频和AI视频,有则上传,响应失败 + if ex: + code, msg = ex + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + ai_video_url=ai_url), timeout=2, is_ex=False) + else: + if ai_url is None or len(ai_url) == 0: + raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1]) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess, + ai_video_url=ai_url), timeout=2, is_ex=False) + + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, request_id) + exc = s.code, s.msg + except Exception: + logger.error("服务异常: {}, requestId: {},", format_exc(), request_id) + exc = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + push_process.join(timeout=120) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(timeout=120) + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=1) + hb_thread.join(timeout=120) + if exc: + code, msg = exc + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + ai_video_url=ai_url), timeout=2, is_ex=False) + self.clear_queue() + + +''' +图片识别 +''' + + +class PhotosIntelligentRecognitionProcess(Process): + __slots__ = ("_fb_queue", "_msg", "_analyse_type", "_context", "_image_queue") + + def __init__(self, *args): + super().__init__() + self._fb_queue, self._msg, self._analyse_type, self._context = args + self._image_queue = Queue() + put_queue(self._fb_queue, message_feedback(self._msg["request_id"], AnalysisStatus.WAITING.value, + self._analyse_type, progress=init_progess), timeout=2, is_ex=True) + self.build_logo(self._msg, self._context) + self._storage_source = self._context['service']['storage_source'] + + @staticmethod + def build_logo(msg, context): + logo = None + if context["video"]["video_add_water"]: + logo = msg.get("logo_url") + if logo is not None and len(logo) > 0: + logo = url2Array(logo, enable_ex=False) + if logo is None: + logo = cv2.imread(join(context['base_dir'], "image/logo.png"), -1) + context['logo'] = logo + + def epidemic_prevention(self, imageUrl, model, orc, request_id): + try: + # modeType, allowedList, new_device, model, par, img_type + model_conf, code = model + modeType, allowedList, new_device, model, par, img_type = model_conf + image = url2Array(imageUrl) + param = [image, new_device, model, par, img_type, request_id] + dataBack = MODEL_CONFIG[code][3](param) + if img_type == 'plate': + carCode = '' + if dataBack is None or dataBack.get("plateImage") is None or len(dataBack.get("plateImage")) == 0: + result = orc.license_plate_recognition(image, request_id) + score = '' + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + logger.error("车牌识别为空: {}", result) + carCode = '' + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + else: + result = orc.license_plate_recognition(dataBack.get("plateImage")[0], request_id) + score = dataBack.get("plateImage")[1] + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + result = orc.license_plate_recognition(image, request_id) + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + logger.error("车牌识别为空: {}", result) + carCode = '' + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + if len(carCode) > 0: + plate_result = {'type': str(3), 'modelCode': code, 'carUrl': imageUrl, + 'carCode': carCode, + 'score': score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(3), + plate_result), timeout=2, is_ex=True) + if img_type == 'code': + if dataBack is None or dataBack.get("type") is None: + return + # 行程码 + if dataBack.get("type") == 1 and 1 in allowedList: + # 手机号 + if dataBack.get("phoneNumberImage") is None or len(dataBack.get("phoneNumberImage")) == 0: + phoneNumberRecognition = '' + phone_score = '' + else: + phone = orc.universal_text_recognition(dataBack.get("phoneNumberImage")[0], request_id) + phone_score = dataBack.get("phoneNumberImage")[1] + if phone is None or phone.get("words_result") is None or len(phone.get("words_result")) == 0: + logger.error("手机号识别为空: {}", phone) + phoneNumberRecognition = '' + else: + phoneNumberRecognition = phone.get("words_result") + if dataBack.get("cityImage") is None or len(dataBack.get("cityImage")) == 0: + cityRecognition = '' + city_score = '' + else: + city = orc.universal_text_recognition(dataBack.get("cityImage")[0], request_id) + city_score = dataBack.get("cityImage")[1] + if city is None or city.get("words_result") is None or len(city.get("words_result")) == 0: + logger.error("城市识别为空: {}", city) + cityRecognition = '' + else: + cityRecognition = city.get("words_result") + if len(phoneNumberRecognition) > 0 or len(cityRecognition) > 0: + trip_result = {'type': str(1), + 'modelCode': code, + 'imageUrl': imageUrl, + 'phoneNumberRecognition': phoneNumberRecognition, + 'phone_sorce': phone_score, + 'cityRecognition': cityRecognition, + 'city_score': city_score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(1), + trip_result), timeout=2, is_ex=True) + if dataBack.get("type") == 2 and 2 in allowedList: + if dataBack.get("nameImage") is None or len(dataBack.get("nameImage")) == 0: + nameRecognition = '' + name_score = '' + else: + name = orc.universal_text_recognition(dataBack.get("nameImage")[0], request_id) + name_score = dataBack.get("nameImage")[1] + if name is None or name.get("words_result") is None or len(name.get("words_result")) == 0: + logger.error("名字识别为空: {}", name) + nameRecognition = '' + else: + nameRecognition = name.get("words_result") + + if dataBack.get("phoneNumberImage") is None or len(dataBack.get("phoneNumberImage")) == 0: + phoneNumberRecognition = '' + phone_score = '' + else: + phone = orc.universal_text_recognition(dataBack.get("phoneNumberImage")[0], request_id) + phone_score = dataBack.get("phoneNumberImage")[1] + if phone is None or phone.get("words_result") is None or len(phone.get("words_result")) == 0: + logger.error("手机号识别为空: {}", phone) + phoneNumberRecognition = '' + else: + phoneNumberRecognition = phone.get("words_result") + if dataBack.get("hsImage") is None or len(dataBack.get("hsImage")) == 0: + hsRecognition = '' + hs_score = '' + else: + hs = orc.universal_text_recognition(dataBack.get("hsImage")[0], request_id) + hs_score = dataBack.get("hsImage")[1] + if hs is None or hs.get("words_result") is None or len(hs.get("words_result")) == 0: + logger.error("核酸识别为空: {}", hs) + hsRecognition = '' + else: + hsRecognition = hs.get("words_result") + if len(nameRecognition) > 0 or len(phoneNumberRecognition) > 0 or len(hsRecognition) > 0: + healthy_result = {'type': str(2), + 'modelCode': code, + 'imageUrl': imageUrl, + 'color': dataBack.get("color"), + 'nameRecognition': nameRecognition, + 'name_score': name_score, + 'phoneNumberRecognition': phoneNumberRecognition, + 'phone_score': phone_score, + 'hsRecognition': hsRecognition, + 'hs_score': hs_score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(2), + healthy_result), timeout=2, is_ex=True) + except ServiceException as s: + raise s + except Exception as e: + logger.error("模型分析异常: {}, requestId: {}", format_exc(), request_id) + raise e + + ''' + # 防疫模型 + ''' + + def epidemicPrevention(self, imageUrls, model, base_dir, env, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + orc = OcrBaiduSdk(base_dir, env) + obj_list = [] + for imageUrl in imageUrls: + obj = t.submit(self.epidemic_prevention, imageUrl, model, orc, request_id) + obj_list.append(obj) + for r in obj_list: + r.result(60) + + def image_recognition(self, imageUrl, mod, image_queue, logo, request_id): + try: + model_conf, code = mod + model_param = model_conf[1] + image = url2Array(imageUrl) + MODEL_CONFIG[code][2](image.shape[1], image.shape[0], model_conf) + p_result = MODEL_CONFIG[code][3]([model_conf, image, request_id])[0] + #print(' line872:p_result[2]:',p_result[2] ) + if p_result is None or len(p_result) < 3 or p_result[2] is None or len(p_result[2]) == 0: + return + if logo: + image = add_water_pic(image, logo, request_id) + # (modeType, model_param, allowedList, names, rainbows) + allowedList = model_conf[2] + label_arraylist = model_param['label_arraylist'] + font_config = model_param['font_config'] + rainbows = model_conf[4] + det_xywh = {code: {}} + ai_result_list = p_result[2] + for ai_result in ai_result_list: + box, score, cls = xywh2xyxy2(ai_result) + # 如果检测目标在识别任务中,继续处理 + if cls in allowedList: + label_array = label_arraylist[cls] + color = rainbows[cls] + cd = det_xywh[code].get(cls) + 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]) + #print('ai_result_list:{},allowlist:{}'.format(ai_result_list,allowedList )) + if len(det_xywh) > 0: + put_queue(image_queue, (1, (det_xywh, imageUrl, image, font_config, "")), timeout=2, is_ex=False) + except ServiceException as s: + raise s + except Exception as e: + logger.error("模型分析异常: {}, requestId: {}", format_exc(), self._msg.get("request_id")) + raise e + + def publicIdentification(self, imageUrls, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + obj_list = [] + for imageUrl in imageUrls: + obj = t.submit(self.image_recognition, imageUrl, mod, image_queue, logo, request_id) + obj_list.append(obj) + for r in obj_list: + r.result(60) + + ''' + 1. imageUrls: 图片url数组,多张图片 + 2. mod: 模型对象 + 3. image_queue: 图片队列 + ''' + + def baiduRecognition(self, imageUrls, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + thread_result = [] + for imageUrl in imageUrls: + obj = t.submit(self.baidu_recognition, imageUrl, mod, image_queue, logo, request_id) + thread_result.append(obj) + for r in thread_result: + r.result(60) + + def baidu_recognition(self, imageUrl, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + try: + # modeType, aipImageClassifyClient, aipBodyAnalysisClient, allowedList, rainbows, + # vehicle_names, person_names, requestId + model_conf, code = mod + allowedList = model_conf[3] + rainbows = model_conf[4] + # 图片转数组 + img = url2Array(imageUrl) + vehicle_label_arrays, person_label_arrays, font_config = MODEL_CONFIG[code][2](img.shape[1], + img.shape[0], + model_conf) + obj_list = [] + for target in allowedList: + parm = [target, imageUrl, model_conf[1], model_conf[2], request_id] + reuslt = t.submit(self.baidu_method, code, parm, img, image_queue, vehicle_label_arrays, + person_label_arrays, font_config, rainbows, logo) + obj_list.append(reuslt) + for r in obj_list: + r.result(60) + except ServiceException as s: + raise s + except Exception as e: + logger.error("百度AI分析异常: {}, requestId: {}", format_exc(), request_id) + raise e + + @staticmethod + def baidu_method(code, parm, img, image_queue, vehicle_label_arrays, person_label_arrays, font_config, + rainbows, logo): + # [target, url, aipImageClassifyClient, aipBodyAnalysisClient, requestId] + request_id = parm[4] + target = parm[0] + image_url = parm[1] + result = MODEL_CONFIG[code][3](parm) + if target == BaiduModelTarget.VEHICLE_DETECTION.value[1] and result is not None: + vehicleInfo = result.get("vehicle_info") + if vehicleInfo is not None and len(vehicleInfo) > 0: + det_xywh = {code: {}} + copy_frame = img.copy() + for i, info in enumerate(vehicleInfo): + value = VehicleEnumVALUE.get(info.get("type")) + target_num = value.value[2] + label_array = vehicle_label_arrays[target_num] + color = rainbows[target_num] + if value is None: + logger.error("车辆识别出现未支持的目标类型!type:{}, requestId:{}", info.get("type"), request_id) + return + left_top = (int(info.get("location").get("left")), int(info.get("location").get("top"))) + right_top = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top"))) + right_bottom = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + left_bottom = (int(info.get("location").get("left")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + box = [left_top, right_top, right_bottom, left_bottom] + score = float("%.2f" % info.get("probability")) + if logo: + copy_frame = add_water_pic(copy_frame, logo, request_id) + if det_xywh[code].get(target) is None: + det_xywh[code][target] = [[target, box, score, label_array, color]] + else: + det_xywh[code][target].append([target, box, score, label_array, color]) + info["id"] = str(i) + if len(det_xywh[code]) > 0: + result["type"] = str(target) + result["modelCode"] = code + put_queue(image_queue, (1, (det_xywh, image_url, copy_frame, font_config, result)), timeout=2, + is_ex=True) + # 人体识别 + if target == BaiduModelTarget.HUMAN_DETECTION.value[1] and result is not None: + personInfo = result.get("person_info") + personNum = result.get("person_num") + if personNum is not None and personNum > 0 and personInfo is not None and len(personInfo) > 0: + det_xywh = {code: {}} + copy_frame = img.copy() + for i, info in enumerate(personInfo): + left_top = (int(info.get("location").get("left")), int(info.get("location").get("top"))) + right_top = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top"))) + right_bottom = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + left_bottom = (int(info.get("location").get("left")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + box = [left_top, right_top, right_bottom, left_bottom] + score = float("%.2f" % info.get("location").get("score")) + label_array = person_label_arrays[0] + color = rainbows[0] + if logo: + copy_frame = add_water_pic(copy_frame, logo, request_id) + if det_xywh[code].get(target) is None: + det_xywh[code][target] = [[target, box, score, label_array, color]] + else: + det_xywh[code][target].append([target, box, score, label_array, color]) + info["id"] = str(i) + if len(det_xywh[code]) > 0: + result["type"] = str(target) + result["modelCode"] = code + put_queue(image_queue, (1, (det_xywh, image_url, copy_frame, font_config, result)), timeout=2) + # 人流量 + if target == BaiduModelTarget.PEOPLE_COUNTING.value[1] and result is not None: + base64Image = result.get("image") + if base64Image is not None and len(base64Image) > 0: + baiduImage = base64.b64decode(base64Image) + result["type"] = str(target) + result["modelCode"] = code + del result["image"] + put_queue(image_queue, (1, (None, image_url, baiduImage, None, result)), timeout=2) + + @staticmethod + def start_File_upload(fb_queue, context, msg, image_queue, analyse_type): + image_thread = ImageTypeImageFileUpload(fb_queue, context, msg, image_queue, analyse_type) + image_thread.setDaemon(True) + image_thread.start() + return image_thread + + def run(self): + fb_queue, msg, analyse_type, context = self._fb_queue, self._msg, self._analyse_type, self._context + request_id, logo, image_queue = msg["request_id"], context['logo'], self._image_queue + base_dir, env = context["base_dir"], context["env"] + imageUrls = msg["image_urls"] + image_thread = None + with ThreadPoolExecutor(max_workers=2) as t: + try: + init_log(base_dir, env) + logger.info("开始启动图片识别进程, requestId: {}", request_id) + model_array = get_model(msg, context, analyse_type) + image_thread = self.start_File_upload(fb_queue, context, msg, image_queue, analyse_type) + task_list = [] + for model in model_array: + # 百度模型逻辑 + if model[1] == ModelType.BAIDU_MODEL.value[1]: + result = t.submit(self.baiduRecognition, imageUrls, model, image_queue, logo, request_id) + task_list.append(result) + # 防疫模型 + elif model[1] == ModelType.EPIDEMIC_PREVENTION_MODEL.value[1]: + result = t.submit(self.epidemicPrevention, imageUrls, model, base_dir, env, request_id) + task_list.append(result) + # 车牌模型 + elif model[1] == ModelType.PLATE_MODEL.value[1]: + result = t.submit(self.epidemicPrevention, imageUrls, model, base_dir, env, request_id) + task_list.append(result) + else: + result = t.submit(self.publicIdentification, imageUrls, model, image_queue, logo, request_id) + task_list.append(result) + for r in task_list: + r.result(60) + if image_thread and not image_thread.is_alive(): + raise Exception("图片识别图片上传线程异常停止!!!") + if image_thread and image_thread.is_alive(): + put_queue(image_queue, (2, 'stop'), timeout=2) + image_thread.join(120) + logger.info("图片进程任务完成,requestId:{}", request_id) + put_queue(fb_queue, message_feedback(request_id, + AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess), timeout=2, is_ex=True) + except ServiceException as s: + logger.error("图片分析异常,异常编号:{}, 异常描述:{}, requestId:{}", s.code, s.msg, request_id) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + s.code, + s.msg), timeout=2) + except Exception: + logger.error("图片分析异常: {}, requestId:{}", format_exc(), request_id) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]), timeout=2) + finally: + if image_thread and image_thread.is_alive(): + clear_queue(image_queue) + put_queue(image_queue, (2, 'stop'), timeout=2) + image_thread.join(120) + clear_queue(image_queue) + + +class ScreenRecordingProcess(Process): + __slots__ = ('_fb_queue', '_context', '_msg', '_analysisType', '_event_queue', '_hb_queue', '_analysisType') + + def __init__(self, *args): + super().__init__() + # 传参 + self._fb_queue, self._context, self._msg, self._analysisType = args + self._event_queue, self._hb_queue, self._pull_queue = Queue(), Queue(), Queue(10) + put_queue(self._fb_queue, + recording_feedback(self._msg["request_id"], RecordingStatus.RECORDING_WAITING.value[0]), + timeout=1, is_ex=True) + self._storage_source = self._context['service']['storage_source'] + def sendEvent(self, result): + put_queue(self._event_queue, result, timeout=2, is_ex=True) + + @staticmethod + def start_pull_stream_thread(msg, context, pull_queue, hb_queue, fb_queue, frame_num): + pullThread = RecordingPullStreamThread(msg, context, pull_queue, hb_queue, fb_queue, frame_num) + pullThread.setDaemon(True) + pullThread.start() + return pullThread + + @staticmethod + def start_hb_thread(fb_queue, hb_queue, request_id): + hb = RecordingHeartbeat(fb_queue, hb_queue, request_id) + hb.setDaemon(True) + hb.start() + return hb + + @staticmethod + def check(start_time, service_timeout, pull_thread, hb_thread, request_id): + 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 pull_thread and not pull_thread.is_alive(): + logger.info("录屏拉流线程停止异常, requestId: {}", request_id) + raise Exception("录屏拉流线程异常停止") + if hb_thread and not hb_thread.is_alive(): + logger.info("录屏心跳线程异常停止, requestId: {}", request_id) + raise Exception("录屏心跳线程异常停止") + + def run(self): + msg, context = self._msg, self._context + request_id, push_url = msg['request_id'], msg.get('push_url') + pull_queue, fb_queue, hb_queue, event_queue = self._pull_queue, self._fb_queue, self._hb_queue, \ + self._event_queue + base_dir, env, service_timeout = context['base_dir'], context['env'], int(context["service"]["timeout"]) + pre_path, end_path = '%s/%s%s' % (base_dir, context["video"]["file_path"], now_date_to_str(YMDHMSF)), \ + '%s%s' % (request_id, ".mp4") + orFilePath = '%s%s%s' % (pre_path, "_on_or_", end_path) + pull_thread, hb_thread = None, None + or_write_status, p_push_status = [0, 0], [0, 0] + or_video_file, push_p = None, None + ex = None + try: + # 初始化日志 + init_log(base_dir, env) + # 启动拉流线程 + pull_thread = self.start_pull_stream_thread(msg, context, pull_queue, hb_queue, fb_queue, 25) + hb_thread = self.start_hb_thread(fb_queue, hb_queue, request_id) + start_time = time() + with ThreadPoolExecutor(max_workers=2) as t: + while True: + # 检查拉流线程和心跳线程 + self.check(start_time, service_timeout, pull_thread, hb_thread, request_id) + # 判断是否需要停止录屏 + event_result = get_no_block_queue(event_queue) + if event_result is not None: + cmdStr = event_result.get("command") + # 接收到停止指令 + if 'stop' == cmdStr: + logger.info("录屏任务开始停止, requestId: {}", request_id) + pull_thread.sendEvent({"command": "stop"}) + pull_result = get_no_block_queue(pull_queue) + if pull_result is None: + sleep(1) + continue + if pull_result[0] == 1: + close_all_p(push_p, or_video_file, None, request_id) + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(180) + raise ServiceException(pull_result[1], pull_result[2]) + elif pull_result[0] == 2: + close_all_p(push_p, or_video_file, None, request_id) + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(180) + break + elif pull_result[0] == 4: + frame_list, frame_index_list, all_frames = pull_result[1] + if len(frame_list) > 0: + 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, {"progress": task_process}, timeout=1) + write_or_video_result = t.submit(write_or_video, frame, orFilePath, or_video_file, + or_write_status, request_id) + if push_url is not None and len(push_url) > 0: + push_p_result = t.submit(push_video_stream, frame, push_p, push_url, p_push_status, + request_id) + push_p = push_p_result.result() + or_video_file = write_or_video_result.result() + else: + raise Exception("未知拉流状态异常!") + logger.info("录屏线程任务完成,requestId:{}", self._msg.get("request_id")) + except ServiceException as s: + logger.error("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, self._msg.get("request_id")) + ex = s.code, s.msg + except Exception: + logger.error("服务异常: {}, requestId: {},", format_exc(), self._msg.get("request_id")) + ex = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + or_url = "" + exn = None + try: + # 关闭推流管道, 原视频写流客户端 + close_all_p(push_p, or_video_file, None, request_id) + # 关闭拉流线程 + if pull_thread and pull_thread.is_alive(): + pull_thread.sendEvent({"command": "stop_ex"}) + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(120) + # 判断是否需要上传视频 + if exists(orFilePath) and getsize(orFilePath) > 100: + or_url = self.upload_video(base_dir, env, request_id, orFilePath) + if or_url is None or len(or_url) == 0: + logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + # 停止心跳线程 + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=10, is_ex=False) + hb_thread.join(timeout=120) + if exists(orFilePath): + logger.info("开始删除原视频, orFilePath: {}, requestId: {}", orFilePath, request_id) + os.remove(orFilePath) + logger.info("删除原视频成功, orFilePath: {}, requestId: {}", orFilePath, request_id) + # 如果有异常, 检查是否有原视频和AI视频,有则上传,响应失败 + if ex: + code, msg = ex + put_queue(fb_queue, recording_feedback(request_id, RecordingStatus.RECORDING_FAILED.value[0], + error_code=code, + error_msg=msg, + video_url=or_url), timeout=10, is_ex=False) + else: + if or_url is None or len(or_url) == 0: + raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1]) + put_queue(fb_queue, recording_feedback(request_id, RecordingStatus.RECORDING_SUCCESS.value[0], + progress=success_progess, + video_url=or_url), timeout=10, is_ex=False) + except ServiceException as s: + exn = s.code, s.msg + except Exception: + logger.error("异常:{}, requestId: {}", format_exc(), request_id) + exn = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + if pull_thread and pull_thread.is_alive(): + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(120) + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=10, is_ex=False) + hb_thread.join(timeout=120) + self.clear_queue_end() + if exn: + code, msg = exn + put_queue(fb_queue, recording_feedback(request_id, RecordingStatus.RECORDING_FAILED.value[0], + error_code=code, + error_msg=msg, + video_url=or_url), timeout=10, is_ex=False) + + def clear_queue_end(self): + clear_queue(self._event_queue) + clear_queue(self._hb_queue) + clear_queue(self._pull_queue) + + + + + def upload_video(self,base_dir, env, request_id, orFilePath): + if self._storage_source==1: + minioSdk = MinioSdk(base_dir, env, request_id ) + upload_video_thread_ai = Common(minioSdk.put_object, aiFilePath, "%s/ai_online.mp4" % request_id) + else: + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + or_url = upload_video_thread_ai.get_result() + return or_url + ''' + @staticmethod + def upload_video(base_dir, env, request_id, orFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, orFilePath, "or_online_%s" % request_id) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + or_url = upload_video_thread_ai.get_result() + return or_url + ''' + +""" +"models": [{ + "code": "模型编号", + "categories":[{ + "id": "模型id", + "config": { + "k1": "v1", + "k2": "v2" + } + }] +}] +""" + + +def get_model(msg, context, analyse_type): + # 初始变量 + request_id, base_dir, gpu_name, env = msg["request_id"], context["base_dir"], context["gpu_name"], context["env"] + models, model_num_limit = msg["models"], context["service"]["model"]['limit'] + try: + # 实时、离线元组 + analyse_type_tuple = (AnalysisType.ONLINE.value, AnalysisType.OFFLINE.value) + # (实时、离线)检查模型组合, 目前只支持3个模型组合 + if analyse_type in analyse_type_tuple: + if len(models) > model_num_limit: + raise ServiceException(ExceptionType.MODEL_GROUP_LIMIT_EXCEPTION.value[0], + ExceptionType.MODEL_GROUP_LIMIT_EXCEPTION.value[1]) + modelArray, codeArray = [], set() + for model in models: + # 模型编码 + code = model["code"] + # 检验code是否重复 + if code in codeArray: + raise ServiceException(ExceptionType.MODEL_DUPLICATE_EXCEPTION.value[0], + ExceptionType.MODEL_DUPLICATE_EXCEPTION.value[1]) + codeArray.add(code) + # 检测目标数组 + needed_objectsIndex = list(set([int(category["id"]) for category in model["categories"]])) + logger.info("模型编号: {}, 检查目标: {}, requestId: {}", code, needed_objectsIndex, request_id) + model_method = MODEL_CONFIG.get(code) + if model_method is None: + logger.error("未匹配到对应的模型, requestId:{}", request_id) + raise ServiceException(ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[0], + ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[1]) + # 检查cpu资源、gpu资源 + check_cpu(base_dir, request_id) + gpu_ids = check_gpu_resource(request_id) + # 如果实时识别、离线识别 + if analyse_type in analyse_type_tuple: + if model["is_video"] == "1": + mod = model_method[0](gpu_ids[0], needed_objectsIndex, request_id, gpu_name, base_dir, env) + modelArray.append((mod.model_conf, code)) + else: + raise ServiceException(ExceptionType.MODEL_NOT_SUPPORT_VIDEO_EXCEPTION.value[0], + ExceptionType.MODEL_NOT_SUPPORT_VIDEO_EXCEPTION.value[1], + model_method[1].value[2]) + # 如果是图片识别 + if analyse_type == AnalysisType.IMAGE.value: + if model["is_image"] == "1": + mod = model_method[0](gpu_ids[0], needed_objectsIndex, request_id, gpu_name, base_dir, env) + modelArray.append((mod.model_conf, code)) + else: + raise ServiceException(ExceptionType.MODEL_NOT_SUPPORT_IMAGE_EXCEPTION.value[0], + ExceptionType.MODEL_NOT_SUPPORT_IMAGE_EXCEPTION.value[1], + model_method[1].value[2]) + if len(modelArray) == 0: + raise ServiceException(ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[0], + ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[1]) + return modelArray + except ServiceException as s: + raise s + except Exception: + logger.error("模型配置处理异常: {}, request_id: {}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) diff --git a/vodsdk/concurrency/IntelligentRecognitionProcess_withMiniSdk.py b/vodsdk/concurrency/IntelligentRecognitionProcess_withMiniSdk.py new file mode 100644 index 0000000..3e56ce0 --- /dev/null +++ b/vodsdk/concurrency/IntelligentRecognitionProcess_withMiniSdk.py @@ -0,0 +1,1444 @@ +# -*- coding: utf-8 -*- +import base64 +import os +from concurrent.futures import ThreadPoolExecutor +from os.path import join, exists, getsize +from time import time, sleep +from traceback import format_exc + +import cv2 + +from multiprocessing import Process, Queue + +import numpy as np +from loguru import logger + +from common.Constant import init_progess, success_progess +from concurrency.FileUploadThread import ImageTypeImageFileUpload +from concurrency.HeartbeatThread import Heartbeat + +from concurrency.PullVideoStreamProcess import OnlinePullVideoStreamProcess, OfflinePullVideoStreamProcess +from concurrency.PushVideoStreamProcess import OnPushStreamProcess, OffPushStreamProcess + +from util.GPUtils import check_gpu_resource +from util.LogUtils import init_log +from concurrency.CommonThread import Common +from concurrency.PullStreamThread import RecordingPullStreamThread +from concurrency.RecordingHeartbeatThread import RecordingHeartbeat +from enums.AnalysisStatusEnum import AnalysisStatus +from enums.AnalysisTypeEnum import AnalysisType +from enums.ExceptionEnum import ExceptionType +from enums.ModelTypeEnum import ModelType +from enums.RecordingStatusEnum import RecordingStatus +from util.AliyunSdk import ThAliyunVodSdk +from util.CpuUtils import check_cpu +from util.Cv2Utils import write_or_video, push_video_stream, close_all_p +from entity.FeedBack import message_feedback, recording_feedback +from exception.CustomerException import ServiceException +from util.ImageUtils import url2Array, add_water_pic +from util.ModelUtils import MODEL_CONFIG +from util.OcrBaiduSdk import OcrBaiduSdk + +from enums.BaiduSdkEnum import VehicleEnumVALUE +from enums.ModelTypeEnum import BaiduModelTarget +from util.PlotsUtils import xywh2xyxy2 +from util.QueUtil import put_queue, get_no_block_queue, clear_queue +from util.TimeUtils import now_date_to_str, YMDHMSF +from util.CpuUtils import print_cpu_status +import inspect +class IntelligentRecognitionProcess(Process): + __slots__ = ('_fb_queue', '_msg', '_analyse_type', '_context', 'event_queue', '_pull_queue', '_hb_queue', + "_image_queue", "_push_queue", '_push_ex_queue') + + def __init__(self, *args): + super().__init__() + # 入参 + self._fb_queue, self._msg, self._analyse_type, self._context = args + # 初始化参数 + self.event_queue, self._pull_queue, self._hb_queue, self._image_queue, self._push_queue, self._push_ex_queue = \ + Queue(), Queue(10), Queue(), Queue(), Queue(), Queue() + + # 发送waitting消息 + put_queue(self._fb_queue, message_feedback(self._msg["request_id"], AnalysisStatus.WAITING.value, + self._analyse_type, progress=init_progess), timeout=2, is_ex=True) + self._storage_source = self._context['service']['storage_source'] + + def sendEvent(self, eBody): + put_queue(self.event_queue, eBody, timeout=2, is_ex=True) + + def clear_queue(self): + clear_queue(self.event_queue) + clear_queue(self._pull_queue) + clear_queue(self._hb_queue) + clear_queue(self._image_queue) + clear_queue(self._push_queue) + clear_queue(self._push_ex_queue) + + @staticmethod + def build_video_path(context, msg, is_build_or=True): + random_time = now_date_to_str(YMDHMSF) + pre_path = '%s/%s%s' % (context["base_dir"], context["video"]["file_path"], random_time) + end_path = '%s%s' % (msg["request_id"], ".mp4") + if is_build_or: + context["orFilePath"] = '%s%s%s' % (pre_path, "_on_or_", end_path) + context["aiFilePath"] = '%s%s%s' % (pre_path, "_on_ai_", end_path) + + @staticmethod + def start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context): + hb_thread = Heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + hb_thread.setDaemon(True) + hb_thread.start() + return hb_thread + + + + + +class OnlineIntelligentRecognitionProcess(IntelligentRecognitionProcess): + __slots__ = () + + @staticmethod + def start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context): + pushProcess = OnPushStreamProcess(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + pushProcess.daemon = True + pushProcess.start() + return pushProcess + + @staticmethod + def start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, frame_num): + pullProcess = OnlinePullVideoStreamProcess(msg, context, fb_queue, pull_queue, image_queue, analyse_type, + frame_num) + pullProcess.daemon = True + pullProcess.start() + return pullProcess + + + def upload_video(self,base_dir, env, request_id, orFilePath, aiFilePath): + if self._storage_source==1: + minioSdk = MinioSdk(base_dir, env, request_id ) + upload_video_thread_or = Common(minioSdk.put_object, orFilePath, "%s/or_online.mp4" % request_id) + upload_video_thread_ai = Common(minioSdk.put_object, aiFilePath, "%s/ai_online.mp4" % request_id) + else: + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_or = Common(aliyunVodSdk.get_play_url, orFilePath, "or_online_%s" % request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + + + upload_video_thread_or.setDaemon(True) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_or.start() + upload_video_thread_ai.start() + or_url = upload_video_thread_or.get_result() + ai_url = upload_video_thread_ai.get_result() + return or_url, ai_url + ''' + @staticmethod + def upload_video(base_dir, env, request_id, orFilePath, aiFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_or = Common(aliyunVodSdk.get_play_url, orFilePath, "or_online_%s" % request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + upload_video_thread_or.setDaemon(True) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_or.start() + upload_video_thread_ai.start() + or_url = upload_video_thread_or.get_result() + ai_url = upload_video_thread_ai.get_result() + return or_url, ai_url + ''' + + @staticmethod + def ai_normal_dtection(model, frame, request_id): + model_conf, code = model + retResults = MODEL_CONFIG[code][3]([model_conf, frame, request_id])[0] + if type(retResults) is np.ndarray or len(retResults) == 0: + ret = retResults + if type(retResults) is np.ndarray: + ret = retResults.tolist() + else: + ret = retResults[2] + return code, ret + + @staticmethod + def obj_det(self, model_array, frame, task_status, cframe, tt, request_id): + push_obj = [] + if task_status[1] == 1: + dtection_result = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result.append(result) + for d in dtection_result: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) == 0: + task_status[1] = 0 + if task_status[1] == 0: + if cframe % 30 == 0: + dtection_result1 = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result1.append(result) + for d in dtection_result1: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) > 0: + task_status[1] = 1 + return push_obj + + @staticmethod + def checkPT(start_time, service_timeout, pull_process, push_process, hb_thread, push_ex_queue, pull_queue, + request_id): + 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 pull_process is not None and not pull_process.is_alive(): + while True: + if pull_queue.empty() or pull_queue.qsize() == 0: + break + pull_result = get_no_block_queue(pull_queue) + if pull_result is not None and pull_result[0] == 1: + raise ServiceException(pull_result[1], pull_result[2]) + logger.info("拉流进程异常停止, requestId: {}", request_id) + raise Exception("拉流进程异常停止!") + if hb_thread is not None and not hb_thread.is_alive(): + logger.info("心跳线程异常停止, requestId: {}", request_id) + raise Exception("心跳线程异常停止!") + if push_process is not None and not push_process.is_alive(): + while True: + if push_ex_queue.empty() or push_ex_queue.qsize() == 0: + break + push_result = get_no_block_queue(push_ex_queue) + if push_result is not None and push_result[0] == 1: + raise ServiceException(push_result[1], push_result[2]) + logger.info("推流进程异常停止, requestId: {}", request_id) + raise Exception("推流进程异常停止!") + + def run(self): + msg, context, analyse_type = self._msg, self._context, self._analyse_type + self.build_video_path(context, msg) + request_id = msg["request_id"] + base_dir, env = context["base_dir"], context["env"] + service_timeout = int(context["service"]["timeout"]) + ex = None + # 拉流进程、推流进程、心跳线程 + pull_process, push_process, hb_thread = None, None, None + + # 事件队列、拉流队列、心跳队列、反馈队列 + event_queue, pull_queue, hb_queue, fb_queue = self.event_queue, self._pull_queue, self._hb_queue, self._fb_queue + + # 推流队列、推流异常队列、图片队列 + push_queue, push_ex_queue, image_queue = self._push_queue, self._push_ex_queue, self._image_queue + try: + # 初始化日志 + init_log(base_dir, env) + # 打印启动日志 + logger.info("开始启动实时分析进程!requestId: {}", request_id) + + # 启动拉流进程(包含拉流线程, 图片上传线程,mqtt读取线程) + # 拉流进程初始化时间长, 先启动 + pull_process = self.start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, 25) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #7.0, + # 启动心跳线程 + hb_thread = self.start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + + + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #7.0, + # 加载算法模型 + model_array = get_model(msg, context, analyse_type) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #9.5 + # 启动推流进程 + push_process = self.start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + # 第一个参数: 模型是否初始化 0:未初始化 1:初始化 + # 第二个参数: 检测是否有问题 0: 没有问题, 1: 有问题 + task_status = [0, 0] + draw_config = {} + start_time = time() + # 识别2个线程性能最优 + with ThreadPoolExecutor(max_workers=2) as t: + # 可能使用模型组合, 模型组合最多3个模型, 1对3, 上面的2个线程对应6个线程 + with ThreadPoolExecutor(max_workers=6) as tt: + while True: + # 检查拉流进程是否正常, 心跳线程是否正常 + self.checkPT(start_time, service_timeout, pull_process, push_process, hb_thread, push_ex_queue, + pull_queue, request_id) + # 检查推流是否异常 + push_status = get_no_block_queue(push_ex_queue) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) #9.5,11.2 + if push_status is not None and push_status[0] == 1: + raise ServiceException(push_status[1], push_status[2]) + # 获取停止指令 + event_result = get_no_block_queue(event_queue) + + if event_result: + cmdStr = event_result.get("command") + + # 接收到停止指令 + if "stop" == cmdStr: + logger.info("实时任务开始停止, requestId: {}", request_id) + pull_process.sendCommand({"command": 'stop'}) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + pull_result = get_no_block_queue(pull_queue) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + if pull_result is None: + sleep(1) + continue + # (4, (frame_list, frame_index_list, all_frames)) + if pull_result[0] == 4: + frame_list, frame_index_list, all_frames = pull_result[1] + if len(frame_list) > 0: + # 判断是否已经初始化 + if task_status[0] == 0: + task_status[0] = 1 + for i, model in enumerate(model_array): + model_conf, code = model + model_param = model_conf[1] + # (modeType, model_param, allowedList, names, rainbows) + MODEL_CONFIG[code][2](frame_list[0].shape[1], frame_list[0].shape[0], + model_conf) + if draw_config.get("font_config") is None: + draw_config["font_config"] = model_param['font_config'] + if draw_config.get(code) is None: + draw_config[code] = {} + draw_config[code]["allowedList"] = model_conf[2] + draw_config[code]["rainbows"] = model_conf[4] + draw_config[code]["label_arrays"] = model_param['label_arraylist'] + if "label_dict" in model_param: + draw_config[code]["label_dict"] = model_param['label_dict'] + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + # 多线程并发处理, 经过测试两个线程最优 + det_array = [] + for i, frame in enumerate(frame_list): + det_result = t.submit(self.obj_det, self, model_array, frame, task_status, + frame_index_list[i], tt, request_id) + det_array.append(det_result) + push_objs = [det.result() for det in det_array] + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + put_queue(push_queue, + (1, (frame_list, frame_index_list, all_frames, draw_config, push_objs)), + timeout=2, is_ex=True) + #print_cpu_status(requestId=request_id,lineNum=inspect.currentframe().f_lineno) + del det_array, push_objs + del frame_list, frame_index_list, all_frames + elif pull_result[0] == 1: + # 拉流发生异常 + put_queue(push_queue, (2, 'stop_ex'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + raise ServiceException(pull_result[1], pull_result[2]) + elif pull_result[0] == 2: + put_queue(push_queue, (2, 'stop'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + break + else: + raise Exception("未知拉流状态异常!") + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, 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: + orFilePath, aiFilePath = context["orFilePath"], context["aiFilePath"] + base_dir, env = context["base_dir"], context["env"] + or_url, ai_url, exc = "", "", None + try: + # 如果拉流进程存在, 关闭拉流进程(拉流线程、图片上传线程) + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + logger.info("关闭拉流进程, requestId:{}", request_id) + pull_process.join(timeout=120) + logger.info("关闭拉流进程1, requestId:{}", request_id) + if exists(orFilePath) and exists(aiFilePath) and getsize(orFilePath) > 100: + or_url, ai_url = self.upload_video(base_dir, env, request_id, orFilePath, aiFilePath) + if or_url is None or ai_url is None: + logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + # 停止心跳线程 + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=1) + hb_thread.join(timeout=120) + if exists(orFilePath): + logger.info("开始删除原视频, orFilePath: {}, requestId: {}", orFilePath, request_id) + os.remove(orFilePath) + logger.info("删除原视频成功, orFilePath: {}, requestId: {}", orFilePath, request_id) + if exists(aiFilePath): + logger.info("开始删除AI视频, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + os.remove(aiFilePath) + logger.info("删除AI视频成功, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + # 如果有异常, 检查是否有原视频和AI视频,有则上传,响应失败 + if ex: + code, msg = ex + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + video_url=or_url, + ai_video_url=ai_url), timeout=2, is_ex=False) + else: + if or_url is None or len(or_url) == 0 or ai_url is None or len(ai_url) == 0: + raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1]) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess, + video_url=or_url, + ai_video_url=ai_url), timeout=2, is_ex=False) + + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, request_id) + exc = s.code, s.msg + except Exception: + logger.error("服务异常: {}, requestId: {},", format_exc(), request_id) + exc = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + logger.info("关闭拉流进程, requestId:{}", request_id) + pull_process.join(timeout=120) + logger.info("关闭拉流进程1, requestId:{}", request_id) + if exc: + code, msg = exc + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + video_url=or_url, + ai_video_url=ai_url), timeout=2, is_ex=False) + logger.info("清理队列, requestId:{}", request_id) + self.clear_queue() + logger.info("清理队列完成, requestId:{}", request_id) + + +class OfflineIntelligentRecognitionProcess(IntelligentRecognitionProcess): + __slots__ = () + + def upload_video(self,base_dir, env, request_id, aiFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + if self._storage_source==1: + minioSdk = MinioSdk(base_dir, env, request_id ) + upload_video_thread_ai = Common(minioSdk.put_object, aiFilePath, "%s/ai_online.mp4" % request_id) + else: + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + ai_url = upload_video_thread_ai.get_result() + return ai_url + + ''' + @staticmethod + def upload_video(base_dir, env, request_id, aiFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + ai_url = upload_video_thread_ai.get_result() + return ai_url + ''' + @staticmethod + def ai_normal_dtection(model, frame, request_id): + model_conf, code = model + retResults = MODEL_CONFIG[code][3]([model_conf, frame, request_id])[0] + if type(retResults) is np.ndarray or len(retResults) == 0: + ret = retResults + if type(retResults) is np.ndarray: + ret = retResults.tolist() + else: + ret = retResults[2] + return code, ret + + @staticmethod + def obj_det(self, model_array, frame, task_status, cframe, tt, request_id): + push_obj = [] + if task_status[1] == 1: + dtection_result = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result.append(result) + for d in dtection_result: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) == 0: + task_status[1] = 0 + if task_status[1] == 0: + if cframe % 30 == 0: + dtection_result1 = [] + for model in model_array: + result = tt.submit(self.ai_normal_dtection, model, frame, request_id) + dtection_result1.append(result) + for d in dtection_result1: + code, det_r = d.result() + if len(det_r) > 0: + push_obj.append((code, det_r)) + if len(push_obj) > 0: + task_status[1] = 1 + return push_obj + + @staticmethod + def start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context): + pushProcess = OffPushStreamProcess(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + pushProcess.daemon = True + pushProcess.start() + return pushProcess + + @staticmethod + def start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, frame_num): + pullProcess = OfflinePullVideoStreamProcess(msg, context, fb_queue, pull_queue, image_queue, analyse_type, + frame_num) + pullProcess.daemon = True + pullProcess.start() + return pullProcess + + @staticmethod + def checkPT(service_timeout, start_time, pull_process, push_process, hb_thread, push_ex_queue, pull_queue, + request_id): + 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 pull_process is not None and not pull_process.is_alive(): + while True: + if pull_queue.empty() or pull_queue.qsize() == 0: + break + pull_result = get_no_block_queue(pull_queue) + if pull_result is not None and pull_result[0] == 1: + raise ServiceException(pull_result[1], pull_result[2]) + logger.info("拉流进程异常停止, requestId: {}", request_id) + raise Exception("拉流进程异常停止!") + if hb_thread is not None and not hb_thread.is_alive(): + logger.info("心跳线程异常停止, requestId: {}", request_id) + raise Exception("心跳线程异常停止!") + if push_process is not None and not push_process.is_alive(): + while True: + if push_ex_queue.empty() or push_ex_queue.qsize() == 0: + break + push_result = get_no_block_queue(push_ex_queue) + if push_result is not None and push_result[0] == 1: + raise ServiceException(push_result[1], push_result[2]) + logger.info("推流进程异常停止, requestId: {}", request_id) + raise Exception("推流进程异常停止!") + + def run(self): + msg, context, analyse_type, ex = self._msg, self._context, self._analyse_type, None + self.build_video_path(context, msg, is_build_or=False) + request_id, base_dir, env = msg["request_id"], context["base_dir"], context["env"] + # 拉流进程、推流进程、心跳线程 + pull_process, push_process, hb_thread = None, None, None + service_timeout = int(context["service"]["timeout"]) + # 事件队列、拉流队列、心跳队列、反馈队列 + event_queue, pull_queue, hb_queue, fb_queue = self.event_queue, self._pull_queue, self._hb_queue, self._fb_queue + # 推流队列、推流异常队列、图片队列 + push_queue, push_ex_queue, image_queue = self._push_queue, self._push_ex_queue, self._image_queue + try: + # 初始化日志 + init_log(base_dir, env) + # 打印启动日志 + logger.info("开始启动离线分析进程!requestId: {}", request_id) + # 启动拉流进程(包含拉流线程, 图片上传线程) + # 拉流进程初始化时间长, 先启动 + pull_process = self.start_pull_stream(msg, context, fb_queue, pull_queue, image_queue, analyse_type, 25) + # 启动心跳线程 + hb_thread = self.start_heartbeat(fb_queue, hb_queue, request_id, analyse_type, context) + # 加载算法模型 + model_array = get_model(msg, context, analyse_type) + # 启动推流进程 + push_process = self.start_push_stream(msg, push_queue, image_queue, push_ex_queue, hb_queue, context) + # 第一个参数: 模型是否初始化 0:未初始化 1:初始化 + # 第二个参数: 检测是否有问题 0: 没有问题, 1: 有问题 + task_status = [0, 0] + draw_config = {} + start_time = time() + # 识别2个线程性能最优 + with ThreadPoolExecutor(max_workers=2) as t: + # 可能使用模型组合, 模型组合最多3个模型, 1对3, 上面的2个线程对应6个线程 + with ThreadPoolExecutor(max_workers=6) as tt: + while True: + # 检查拉流进程是否正常, 心跳线程是否正常 + self.checkPT(service_timeout, start_time, pull_process, push_process, hb_thread, push_ex_queue, + pull_queue, request_id) + # 检查推流是否异常 + push_status = get_no_block_queue(push_ex_queue) + if push_status is not None and push_status[0] == 1: + raise ServiceException(push_status[1], push_status[2]) + # 获取停止指令 + event_result = get_no_block_queue(event_queue) + if event_result: + cmdStr = event_result.get("command") + # 接收到停止指令 + if "stop" == cmdStr: + logger.info("离线任务开始停止, requestId: {}", request_id) + pull_process.sendCommand({"command": 'stop'}) + pull_result = get_no_block_queue(pull_queue) + if pull_result is None: + sleep(1) + continue + # (4, (frame_list, frame_index_list, all_frames)) + if pull_result[0] == 4: + frame_list, frame_index_list, all_frames = pull_result[1] + if len(frame_list) > 0: + # 判断是否已经初始化 + if task_status[0] == 0: + task_status[0] = 1 + for i, model in enumerate(model_array): + model_conf, code = model + model_param = model_conf[1] + # (modeType, model_param, allowedList, names, rainbows) + MODEL_CONFIG[code][2](frame_list[0].shape[1], frame_list[0].shape[0], + model_conf) + if draw_config.get("font_config") is None: + draw_config["font_config"] = model_param['font_config'] + if draw_config.get(code) is None: + draw_config[code] = {} + draw_config[code]["allowedList"] = model_conf[2] + draw_config[code]["rainbows"] = model_conf[4] + draw_config[code]["label_arrays"] = model_param['label_arraylist'] + if "label_dict" in model_param: + draw_config[code]["label_dict"] = model_param['label_dict'] + det_array = [] + for i, frame in enumerate(frame_list): + det_result = t.submit(self.obj_det, self, model_array, frame, task_status, + frame_index_list[i], tt, request_id) + det_array.append(det_result) + push_objs = [det.result() for det in det_array] + put_queue(push_queue, + (1, (frame_list, frame_index_list, all_frames, draw_config, push_objs)), + timeout=2, is_ex=True) + del det_array, push_objs + del frame_list, frame_index_list, all_frames + elif pull_result[0] == 1: + put_queue(push_queue, (2, 'stop_ex'), timeout=1, is_ex=True) + logger.info("关闭推流进程, requestId:{}", request_id) + push_process.join(timeout=120) + logger.info("关闭推流进程1, requestId:{}", request_id) + raise ServiceException(pull_result[1], pull_result[2]) + elif pull_result[0] == 2: + logger.info("离线任务开始停止, requestId: {}", request_id) + put_queue(push_queue, (2, 'stop'), timeout=1, is_ex=True) + push_process.join(120) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(120) + break + else: + raise Exception("未知拉流状态异常!") + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, 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: + base_dir, env, aiFilePath = context["base_dir"], context["env"], context["aiFilePath"] + ai_url, exc = "", None + try: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + push_process.join(timeout=120) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(timeout=120) + if exists(aiFilePath) and getsize(aiFilePath) > 100: + ai_url = self.upload_video(base_dir, env, request_id, aiFilePath) + if ai_url is None: + logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + # 停止心跳线程 + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=1) + hb_thread.join(timeout=120) + if exists(aiFilePath): + logger.info("开始删除AI视频, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + os.remove(aiFilePath) + logger.info("删除AI视频成功, aiFilePath: {}, requestId: {}", aiFilePath, request_id) + # 如果有异常, 检查是否有原视频和AI视频,有则上传,响应失败 + if ex: + code, msg = ex + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + ai_video_url=ai_url), timeout=2, is_ex=False) + else: + if ai_url is None or len(ai_url) == 0: + raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1]) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess, + ai_video_url=ai_url), timeout=2, is_ex=False) + + except ServiceException as s: + logger.exception("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, request_id) + exc = s.code, s.msg + except Exception: + logger.error("服务异常: {}, requestId: {},", format_exc(), request_id) + exc = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + if push_process and push_process.is_alive(): + put_queue(push_queue, (2, 'stop_ex'), timeout=1) + push_process.join(timeout=120) + if pull_process and pull_process.is_alive(): + pull_process.sendCommand({"command": 'stop_ex'}) + pull_process.sendCommand({"command": 'stop'}) + pull_process.join(timeout=120) + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=1) + hb_thread.join(timeout=120) + if exc: + code, msg = exc + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + error_code=code, + error_msg=msg, + ai_video_url=ai_url), timeout=2, is_ex=False) + self.clear_queue() + + +''' +图片识别 +''' + + +class PhotosIntelligentRecognitionProcess(Process): + __slots__ = ("_fb_queue", "_msg", "_analyse_type", "_context", "_image_queue") + + def __init__(self, *args): + super().__init__() + self._fb_queue, self._msg, self._analyse_type, self._context = args + self._image_queue = Queue() + put_queue(self._fb_queue, message_feedback(self._msg["request_id"], AnalysisStatus.WAITING.value, + self._analyse_type, progress=init_progess), timeout=2, is_ex=True) + self.build_logo(self._msg, self._context) + self._storage_source = self._context['service']['storage_source'] + + @staticmethod + def build_logo(msg, context): + logo = None + if context["video"]["video_add_water"]: + logo = msg.get("logo_url") + if logo is not None and len(logo) > 0: + logo = url2Array(logo, enable_ex=False) + if logo is None: + logo = cv2.imread(join(context['base_dir'], "image/logo.png"), -1) + context['logo'] = logo + + def epidemic_prevention(self, imageUrl, model, orc, request_id): + try: + # modeType, allowedList, new_device, model, par, img_type + model_conf, code = model + modeType, allowedList, new_device, model, par, img_type = model_conf + image = url2Array(imageUrl) + param = [image, new_device, model, par, img_type, request_id] + dataBack = MODEL_CONFIG[code][3](param) + if img_type == 'plate': + carCode = '' + if dataBack is None or dataBack.get("plateImage") is None or len(dataBack.get("plateImage")) == 0: + result = orc.license_plate_recognition(image, request_id) + score = '' + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + logger.error("车牌识别为空: {}", result) + carCode = '' + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + else: + result = orc.license_plate_recognition(dataBack.get("plateImage")[0], request_id) + score = dataBack.get("plateImage")[1] + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + result = orc.license_plate_recognition(image, request_id) + if result is None or result.get("words_result") is None or len(result.get("words_result")) == 0: + logger.error("车牌识别为空: {}", result) + carCode = '' + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + else: + for word in result.get("words_result"): + if word is not None and word.get("number") is not None: + if len(carCode) == 0: + carCode = word.get("number") + else: + carCode = carCode + "," + word.get("number") + if len(carCode) > 0: + plate_result = {'type': str(3), 'modelCode': code, 'carUrl': imageUrl, + 'carCode': carCode, + 'score': score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(3), + plate_result), timeout=2, is_ex=True) + if img_type == 'code': + if dataBack is None or dataBack.get("type") is None: + return + # 行程码 + if dataBack.get("type") == 1 and 1 in allowedList: + # 手机号 + if dataBack.get("phoneNumberImage") is None or len(dataBack.get("phoneNumberImage")) == 0: + phoneNumberRecognition = '' + phone_score = '' + else: + phone = orc.universal_text_recognition(dataBack.get("phoneNumberImage")[0], request_id) + phone_score = dataBack.get("phoneNumberImage")[1] + if phone is None or phone.get("words_result") is None or len(phone.get("words_result")) == 0: + logger.error("手机号识别为空: {}", phone) + phoneNumberRecognition = '' + else: + phoneNumberRecognition = phone.get("words_result") + if dataBack.get("cityImage") is None or len(dataBack.get("cityImage")) == 0: + cityRecognition = '' + city_score = '' + else: + city = orc.universal_text_recognition(dataBack.get("cityImage")[0], request_id) + city_score = dataBack.get("cityImage")[1] + if city is None or city.get("words_result") is None or len(city.get("words_result")) == 0: + logger.error("城市识别为空: {}", city) + cityRecognition = '' + else: + cityRecognition = city.get("words_result") + if len(phoneNumberRecognition) > 0 or len(cityRecognition) > 0: + trip_result = {'type': str(1), + 'modelCode': code, + 'imageUrl': imageUrl, + 'phoneNumberRecognition': phoneNumberRecognition, + 'phone_sorce': phone_score, + 'cityRecognition': cityRecognition, + 'city_score': city_score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(1), + trip_result), timeout=2, is_ex=True) + if dataBack.get("type") == 2 and 2 in allowedList: + if dataBack.get("nameImage") is None or len(dataBack.get("nameImage")) == 0: + nameRecognition = '' + name_score = '' + else: + name = orc.universal_text_recognition(dataBack.get("nameImage")[0], request_id) + name_score = dataBack.get("nameImage")[1] + if name is None or name.get("words_result") is None or len(name.get("words_result")) == 0: + logger.error("名字识别为空: {}", name) + nameRecognition = '' + else: + nameRecognition = name.get("words_result") + + if dataBack.get("phoneNumberImage") is None or len(dataBack.get("phoneNumberImage")) == 0: + phoneNumberRecognition = '' + phone_score = '' + else: + phone = orc.universal_text_recognition(dataBack.get("phoneNumberImage")[0], request_id) + phone_score = dataBack.get("phoneNumberImage")[1] + if phone is None or phone.get("words_result") is None or len(phone.get("words_result")) == 0: + logger.error("手机号识别为空: {}", phone) + phoneNumberRecognition = '' + else: + phoneNumberRecognition = phone.get("words_result") + if dataBack.get("hsImage") is None or len(dataBack.get("hsImage")) == 0: + hsRecognition = '' + hs_score = '' + else: + hs = orc.universal_text_recognition(dataBack.get("hsImage")[0], request_id) + hs_score = dataBack.get("hsImage")[1] + if hs is None or hs.get("words_result") is None or len(hs.get("words_result")) == 0: + logger.error("核酸识别为空: {}", hs) + hsRecognition = '' + else: + hsRecognition = hs.get("words_result") + if len(nameRecognition) > 0 or len(phoneNumberRecognition) > 0 or len(hsRecognition) > 0: + healthy_result = {'type': str(2), + 'modelCode': code, + 'imageUrl': imageUrl, + 'color': dataBack.get("color"), + 'nameRecognition': nameRecognition, + 'name_score': name_score, + 'phoneNumberRecognition': phoneNumberRecognition, + 'phone_score': phone_score, + 'hsRecognition': hsRecognition, + 'hs_score': hs_score} + put_queue(self._fb_queue, message_feedback(request_id, + AnalysisStatus.RUNNING.value, + AnalysisType.IMAGE.value, "", "", + '', + imageUrl, + imageUrl, + str(code), + str(2), + healthy_result), timeout=2, is_ex=True) + except ServiceException as s: + raise s + except Exception as e: + logger.error("模型分析异常: {}, requestId: {}", format_exc(), request_id) + raise e + + ''' + # 防疫模型 + ''' + + def epidemicPrevention(self, imageUrls, model, base_dir, env, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + orc = OcrBaiduSdk(base_dir, env) + obj_list = [] + for imageUrl in imageUrls: + obj = t.submit(self.epidemic_prevention, imageUrl, model, orc, request_id) + obj_list.append(obj) + for r in obj_list: + r.result(60) + + def image_recognition(self, imageUrl, mod, image_queue, logo, request_id): + try: + model_conf, code = mod + model_param = model_conf[1] + image = url2Array(imageUrl) + MODEL_CONFIG[code][2](image.shape[1], image.shape[0], model_conf) + p_result = MODEL_CONFIG[code][3]([model_conf, image, request_id])[0] + #print(' line872:p_result[2]:',p_result[2] ) + if p_result is None or len(p_result) < 3 or p_result[2] is None or len(p_result[2]) == 0: + return + if logo: + image = add_water_pic(image, logo, request_id) + # (modeType, model_param, allowedList, names, rainbows) + allowedList = model_conf[2] + label_arraylist = model_param['label_arraylist'] + font_config = model_param['font_config'] + rainbows = model_conf[4] + det_xywh = {code: {}} + ai_result_list = p_result[2] + for ai_result in ai_result_list: + box, score, cls = xywh2xyxy2(ai_result) + # 如果检测目标在识别任务中,继续处理 + if cls in allowedList: + label_array = label_arraylist[cls] + color = rainbows[cls] + cd = det_xywh[code].get(cls) + 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]) + #print('ai_result_list:{},allowlist:{}'.format(ai_result_list,allowedList )) + if len(det_xywh) > 0: + put_queue(image_queue, (1, (det_xywh, imageUrl, image, font_config, "")), timeout=2, is_ex=False) + except ServiceException as s: + raise s + except Exception as e: + logger.error("模型分析异常: {}, requestId: {}", format_exc(), self._msg.get("request_id")) + raise e + + def publicIdentification(self, imageUrls, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + obj_list = [] + for imageUrl in imageUrls: + obj = t.submit(self.image_recognition, imageUrl, mod, image_queue, logo, request_id) + obj_list.append(obj) + for r in obj_list: + r.result(60) + + ''' + 1. imageUrls: 图片url数组,多张图片 + 2. mod: 模型对象 + 3. image_queue: 图片队列 + ''' + + def baiduRecognition(self, imageUrls, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + thread_result = [] + for imageUrl in imageUrls: + obj = t.submit(self.baidu_recognition, imageUrl, mod, image_queue, logo, request_id) + thread_result.append(obj) + for r in thread_result: + r.result(60) + + def baidu_recognition(self, imageUrl, mod, image_queue, logo, request_id): + with ThreadPoolExecutor(max_workers=2) as t: + try: + # modeType, aipImageClassifyClient, aipBodyAnalysisClient, allowedList, rainbows, + # vehicle_names, person_names, requestId + model_conf, code = mod + allowedList = model_conf[3] + rainbows = model_conf[4] + # 图片转数组 + img = url2Array(imageUrl) + vehicle_label_arrays, person_label_arrays, font_config = MODEL_CONFIG[code][2](img.shape[1], + img.shape[0], + model_conf) + obj_list = [] + for target in allowedList: + parm = [target, imageUrl, model_conf[1], model_conf[2], request_id] + reuslt = t.submit(self.baidu_method, code, parm, img, image_queue, vehicle_label_arrays, + person_label_arrays, font_config, rainbows, logo) + obj_list.append(reuslt) + for r in obj_list: + r.result(60) + except ServiceException as s: + raise s + except Exception as e: + logger.error("百度AI分析异常: {}, requestId: {}", format_exc(), request_id) + raise e + + @staticmethod + def baidu_method(code, parm, img, image_queue, vehicle_label_arrays, person_label_arrays, font_config, + rainbows, logo): + # [target, url, aipImageClassifyClient, aipBodyAnalysisClient, requestId] + request_id = parm[4] + target = parm[0] + image_url = parm[1] + result = MODEL_CONFIG[code][3](parm) + if target == BaiduModelTarget.VEHICLE_DETECTION.value[1] and result is not None: + vehicleInfo = result.get("vehicle_info") + if vehicleInfo is not None and len(vehicleInfo) > 0: + det_xywh = {code: {}} + copy_frame = img.copy() + for i, info in enumerate(vehicleInfo): + value = VehicleEnumVALUE.get(info.get("type")) + target_num = value.value[2] + label_array = vehicle_label_arrays[target_num] + color = rainbows[target_num] + if value is None: + logger.error("车辆识别出现未支持的目标类型!type:{}, requestId:{}", info.get("type"), request_id) + return + left_top = (int(info.get("location").get("left")), int(info.get("location").get("top"))) + right_top = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top"))) + right_bottom = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + left_bottom = (int(info.get("location").get("left")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + box = [left_top, right_top, right_bottom, left_bottom] + score = float("%.2f" % info.get("probability")) + if logo: + copy_frame = add_water_pic(copy_frame, logo, request_id) + if det_xywh[code].get(target) is None: + det_xywh[code][target] = [[target, box, score, label_array, color]] + else: + det_xywh[code][target].append([target, box, score, label_array, color]) + info["id"] = str(i) + if len(det_xywh[code]) > 0: + result["type"] = str(target) + result["modelCode"] = code + put_queue(image_queue, (1, (det_xywh, image_url, copy_frame, font_config, result)), timeout=2, + is_ex=True) + # 人体识别 + if target == BaiduModelTarget.HUMAN_DETECTION.value[1] and result is not None: + personInfo = result.get("person_info") + personNum = result.get("person_num") + if personNum is not None and personNum > 0 and personInfo is not None and len(personInfo) > 0: + det_xywh = {code: {}} + copy_frame = img.copy() + for i, info in enumerate(personInfo): + left_top = (int(info.get("location").get("left")), int(info.get("location").get("top"))) + right_top = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top"))) + right_bottom = (int(info.get("location").get("left")) + int(info.get("location").get("width")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + left_bottom = (int(info.get("location").get("left")), + int(info.get("location").get("top")) + int(info.get("location").get("height"))) + box = [left_top, right_top, right_bottom, left_bottom] + score = float("%.2f" % info.get("location").get("score")) + label_array = person_label_arrays[0] + color = rainbows[0] + if logo: + copy_frame = add_water_pic(copy_frame, logo, request_id) + if det_xywh[code].get(target) is None: + det_xywh[code][target] = [[target, box, score, label_array, color]] + else: + det_xywh[code][target].append([target, box, score, label_array, color]) + info["id"] = str(i) + if len(det_xywh[code]) > 0: + result["type"] = str(target) + result["modelCode"] = code + put_queue(image_queue, (1, (det_xywh, image_url, copy_frame, font_config, result)), timeout=2) + # 人流量 + if target == BaiduModelTarget.PEOPLE_COUNTING.value[1] and result is not None: + base64Image = result.get("image") + if base64Image is not None and len(base64Image) > 0: + baiduImage = base64.b64decode(base64Image) + result["type"] = str(target) + result["modelCode"] = code + del result["image"] + put_queue(image_queue, (1, (None, image_url, baiduImage, None, result)), timeout=2) + + @staticmethod + def start_File_upload(fb_queue, context, msg, image_queue, analyse_type): + image_thread = ImageTypeImageFileUpload(fb_queue, context, msg, image_queue, analyse_type) + image_thread.setDaemon(True) + image_thread.start() + return image_thread + + def run(self): + fb_queue, msg, analyse_type, context = self._fb_queue, self._msg, self._analyse_type, self._context + request_id, logo, image_queue = msg["request_id"], context['logo'], self._image_queue + base_dir, env = context["base_dir"], context["env"] + imageUrls = msg["image_urls"] + image_thread = None + with ThreadPoolExecutor(max_workers=2) as t: + try: + init_log(base_dir, env) + logger.info("开始启动图片识别进程, requestId: {}", request_id) + model_array = get_model(msg, context, analyse_type) + image_thread = self.start_File_upload(fb_queue, context, msg, image_queue, analyse_type) + task_list = [] + for model in model_array: + # 百度模型逻辑 + if model[1] == ModelType.BAIDU_MODEL.value[1]: + result = t.submit(self.baiduRecognition, imageUrls, model, image_queue, logo, request_id) + task_list.append(result) + # 防疫模型 + elif model[1] == ModelType.EPIDEMIC_PREVENTION_MODEL.value[1]: + result = t.submit(self.epidemicPrevention, imageUrls, model, base_dir, env, request_id) + task_list.append(result) + # 车牌模型 + elif model[1] == ModelType.PLATE_MODEL.value[1]: + result = t.submit(self.epidemicPrevention, imageUrls, model, base_dir, env, request_id) + task_list.append(result) + else: + result = t.submit(self.publicIdentification, imageUrls, model, image_queue, logo, request_id) + task_list.append(result) + for r in task_list: + r.result(60) + if image_thread and not image_thread.is_alive(): + raise Exception("图片识别图片上传线程异常停止!!!") + if image_thread and image_thread.is_alive(): + put_queue(image_queue, (2, 'stop'), timeout=2) + image_thread.join(120) + logger.info("图片进程任务完成,requestId:{}", request_id) + put_queue(fb_queue, message_feedback(request_id, + AnalysisStatus.SUCCESS.value, + analyse_type, + progress=success_progess), timeout=2, is_ex=True) + except ServiceException as s: + logger.error("图片分析异常,异常编号:{}, 异常描述:{}, requestId:{}", s.code, s.msg, request_id) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + s.code, + s.msg), timeout=2) + except Exception: + logger.error("图片分析异常: {}, requestId:{}", format_exc(), request_id) + put_queue(fb_queue, message_feedback(request_id, AnalysisStatus.FAILED.value, + analyse_type, + ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]), timeout=2) + finally: + if image_thread and image_thread.is_alive(): + clear_queue(image_queue) + put_queue(image_queue, (2, 'stop'), timeout=2) + image_thread.join(120) + clear_queue(image_queue) + + +class ScreenRecordingProcess(Process): + __slots__ = ('_fb_queue', '_context', '_msg', '_analysisType', '_event_queue', '_hb_queue', '_analysisType') + + def __init__(self, *args): + super().__init__() + # 传参 + self._fb_queue, self._context, self._msg, self._analysisType = args + self._event_queue, self._hb_queue, self._pull_queue = Queue(), Queue(), Queue(10) + put_queue(self._fb_queue, + recording_feedback(self._msg["request_id"], RecordingStatus.RECORDING_WAITING.value[0]), + timeout=1, is_ex=True) + self._storage_source = self._context['service']['storage_source'] + def sendEvent(self, result): + put_queue(self._event_queue, result, timeout=2, is_ex=True) + + @staticmethod + def start_pull_stream_thread(msg, context, pull_queue, hb_queue, fb_queue, frame_num): + pullThread = RecordingPullStreamThread(msg, context, pull_queue, hb_queue, fb_queue, frame_num) + pullThread.setDaemon(True) + pullThread.start() + return pullThread + + @staticmethod + def start_hb_thread(fb_queue, hb_queue, request_id): + hb = RecordingHeartbeat(fb_queue, hb_queue, request_id) + hb.setDaemon(True) + hb.start() + return hb + + @staticmethod + def check(start_time, service_timeout, pull_thread, hb_thread, request_id): + 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 pull_thread and not pull_thread.is_alive(): + logger.info("录屏拉流线程停止异常, requestId: {}", request_id) + raise Exception("录屏拉流线程异常停止") + if hb_thread and not hb_thread.is_alive(): + logger.info("录屏心跳线程异常停止, requestId: {}", request_id) + raise Exception("录屏心跳线程异常停止") + + def run(self): + msg, context = self._msg, self._context + request_id, push_url = msg['request_id'], msg.get('push_url') + pull_queue, fb_queue, hb_queue, event_queue = self._pull_queue, self._fb_queue, self._hb_queue, \ + self._event_queue + base_dir, env, service_timeout = context['base_dir'], context['env'], int(context["service"]["timeout"]) + pre_path, end_path = '%s/%s%s' % (base_dir, context["video"]["file_path"], now_date_to_str(YMDHMSF)), \ + '%s%s' % (request_id, ".mp4") + orFilePath = '%s%s%s' % (pre_path, "_on_or_", end_path) + pull_thread, hb_thread = None, None + or_write_status, p_push_status = [0, 0], [0, 0] + or_video_file, push_p = None, None + ex = None + try: + # 初始化日志 + init_log(base_dir, env) + # 启动拉流线程 + pull_thread = self.start_pull_stream_thread(msg, context, pull_queue, hb_queue, fb_queue, 25) + hb_thread = self.start_hb_thread(fb_queue, hb_queue, request_id) + start_time = time() + with ThreadPoolExecutor(max_workers=2) as t: + while True: + # 检查拉流线程和心跳线程 + self.check(start_time, service_timeout, pull_thread, hb_thread, request_id) + # 判断是否需要停止录屏 + event_result = get_no_block_queue(event_queue) + if event_result is not None: + cmdStr = event_result.get("command") + # 接收到停止指令 + if 'stop' == cmdStr: + logger.info("录屏任务开始停止, requestId: {}", request_id) + pull_thread.sendEvent({"command": "stop"}) + pull_result = get_no_block_queue(pull_queue) + if pull_result is None: + sleep(1) + continue + if pull_result[0] == 1: + close_all_p(push_p, or_video_file, None, request_id) + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(180) + raise ServiceException(pull_result[1], pull_result[2]) + elif pull_result[0] == 2: + close_all_p(push_p, or_video_file, None, request_id) + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(180) + break + elif pull_result[0] == 4: + frame_list, frame_index_list, all_frames = pull_result[1] + if len(frame_list) > 0: + 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, {"progress": task_process}, timeout=1) + write_or_video_result = t.submit(write_or_video, frame, orFilePath, or_video_file, + or_write_status, request_id) + if push_url is not None and len(push_url) > 0: + push_p_result = t.submit(push_video_stream, frame, push_p, push_url, p_push_status, + request_id) + push_p = push_p_result.result() + or_video_file = write_or_video_result.result() + else: + raise Exception("未知拉流状态异常!") + logger.info("录屏线程任务完成,requestId:{}", self._msg.get("request_id")) + except ServiceException as s: + logger.error("服务异常,异常编号:{}, 异常描述:{}, requestId: {}", s.code, s.msg, self._msg.get("request_id")) + ex = s.code, s.msg + except Exception: + logger.error("服务异常: {}, requestId: {},", format_exc(), self._msg.get("request_id")) + ex = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + or_url = "" + exn = None + try: + # 关闭推流管道, 原视频写流客户端 + close_all_p(push_p, or_video_file, None, request_id) + # 关闭拉流线程 + if pull_thread and pull_thread.is_alive(): + pull_thread.sendEvent({"command": "stop_ex"}) + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(120) + # 判断是否需要上传视频 + if exists(orFilePath) and getsize(orFilePath) > 100: + or_url = self.upload_video(base_dir, env, request_id, orFilePath) + if or_url is None or len(or_url) == 0: + logger.error("原视频或AI视频播放上传VOD失败!, requestId: {}", request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + # 停止心跳线程 + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=10, is_ex=False) + hb_thread.join(timeout=120) + if exists(orFilePath): + logger.info("开始删除原视频, orFilePath: {}, requestId: {}", orFilePath, request_id) + os.remove(orFilePath) + logger.info("删除原视频成功, orFilePath: {}, requestId: {}", orFilePath, request_id) + # 如果有异常, 检查是否有原视频和AI视频,有则上传,响应失败 + if ex: + code, msg = ex + put_queue(fb_queue, recording_feedback(request_id, RecordingStatus.RECORDING_FAILED.value[0], + error_code=code, + error_msg=msg, + video_url=or_url), timeout=10, is_ex=False) + else: + if or_url is None or len(or_url) == 0: + raise ServiceException(ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_TIME_EXCEPTION.value[1]) + put_queue(fb_queue, recording_feedback(request_id, RecordingStatus.RECORDING_SUCCESS.value[0], + progress=success_progess, + video_url=or_url), timeout=10, is_ex=False) + except ServiceException as s: + exn = s.code, s.msg + except Exception: + logger.error("异常:{}, requestId: {}", format_exc(), request_id) + exn = ExceptionType.SERVICE_INNER_EXCEPTION.value[0], ExceptionType.SERVICE_INNER_EXCEPTION.value[1] + finally: + if pull_thread and pull_thread.is_alive(): + pull_thread.sendEvent({"command": "stop"}) + pull_thread.join(120) + if hb_thread and hb_thread.is_alive(): + put_queue(hb_queue, {"command": "stop"}, timeout=10, is_ex=False) + hb_thread.join(timeout=120) + self.clear_queue_end() + if exn: + code, msg = exn + put_queue(fb_queue, recording_feedback(request_id, RecordingStatus.RECORDING_FAILED.value[0], + error_code=code, + error_msg=msg, + video_url=or_url), timeout=10, is_ex=False) + + def clear_queue_end(self): + clear_queue(self._event_queue) + clear_queue(self._hb_queue) + clear_queue(self._pull_queue) + + + + + def upload_video(self,base_dir, env, request_id, orFilePath): + if self._storage_source==1: + minioSdk = MinioSdk(base_dir, env, request_id ) + upload_video_thread_ai = Common(minioSdk.put_object, aiFilePath, "%s/ai_online.mp4" % request_id) + else: + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, aiFilePath, "ai_online_%s" % request_id) + + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + or_url = upload_video_thread_ai.get_result() + return or_url + ''' + @staticmethod + def upload_video(base_dir, env, request_id, orFilePath): + aliyunVodSdk = ThAliyunVodSdk(base_dir, env, request_id) + upload_video_thread_ai = Common(aliyunVodSdk.get_play_url, orFilePath, "or_online_%s" % request_id) + upload_video_thread_ai.setDaemon(True) + upload_video_thread_ai.start() + or_url = upload_video_thread_ai.get_result() + return or_url + ''' + +""" +"models": [{ + "code": "模型编号", + "categories":[{ + "id": "模型id", + "config": { + "k1": "v1", + "k2": "v2" + } + }] +}] +""" + + +def get_model(msg, context, analyse_type): + # 初始变量 + request_id, base_dir, gpu_name, env = msg["request_id"], context["base_dir"], context["gpu_name"], context["env"] + models, model_num_limit = msg["models"], context["service"]["model"]['limit'] + try: + # 实时、离线元组 + analyse_type_tuple = (AnalysisType.ONLINE.value, AnalysisType.OFFLINE.value) + # (实时、离线)检查模型组合, 目前只支持3个模型组合 + if analyse_type in analyse_type_tuple: + if len(models) > model_num_limit: + raise ServiceException(ExceptionType.MODEL_GROUP_LIMIT_EXCEPTION.value[0], + ExceptionType.MODEL_GROUP_LIMIT_EXCEPTION.value[1]) + modelArray, codeArray = [], set() + for model in models: + # 模型编码 + code = model["code"] + # 检验code是否重复 + if code in codeArray: + raise ServiceException(ExceptionType.MODEL_DUPLICATE_EXCEPTION.value[0], + ExceptionType.MODEL_DUPLICATE_EXCEPTION.value[1]) + codeArray.add(code) + # 检测目标数组 + needed_objectsIndex = list(set([int(category["id"]) for category in model["categories"]])) + logger.info("模型编号: {}, 检查目标: {}, requestId: {}", code, needed_objectsIndex, request_id) + model_method = MODEL_CONFIG.get(code) + if model_method is None: + logger.error("未匹配到对应的模型, requestId:{}", request_id) + raise ServiceException(ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[0], + ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[1]) + # 检查cpu资源、gpu资源 + check_cpu(base_dir, request_id) + gpu_ids = check_gpu_resource(request_id) + # 如果实时识别、离线识别 + if analyse_type in analyse_type_tuple: + if model["is_video"] == "1": + mod = model_method[0](gpu_ids[0], needed_objectsIndex, request_id, gpu_name, base_dir, env) + modelArray.append((mod.model_conf, code)) + else: + raise ServiceException(ExceptionType.MODEL_NOT_SUPPORT_VIDEO_EXCEPTION.value[0], + ExceptionType.MODEL_NOT_SUPPORT_VIDEO_EXCEPTION.value[1], + model_method[1].value[2]) + # 如果是图片识别 + if analyse_type == AnalysisType.IMAGE.value: + if model["is_image"] == "1": + mod = model_method[0](gpu_ids[0], needed_objectsIndex, request_id, gpu_name, base_dir, env) + modelArray.append((mod.model_conf, code)) + else: + raise ServiceException(ExceptionType.MODEL_NOT_SUPPORT_IMAGE_EXCEPTION.value[0], + ExceptionType.MODEL_NOT_SUPPORT_IMAGE_EXCEPTION.value[1], + model_method[1].value[2]) + if len(modelArray) == 0: + raise ServiceException(ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[0], + ExceptionType.AI_MODEL_MATCH_EXCEPTION.value[1]) + return modelArray + except ServiceException as s: + raise s + except Exception: + logger.error("模型配置处理异常: {}, request_id: {}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) diff --git a/vodsdk/concurrency/Pull2PushStreamProcess.py b/vodsdk/concurrency/Pull2PushStreamProcess.py new file mode 100644 index 0000000..dd410d0 --- /dev/null +++ b/vodsdk/concurrency/Pull2PushStreamProcess.py @@ -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) diff --git a/vodsdk/concurrency/Pull2PushStreamThread.py b/vodsdk/concurrency/Pull2PushStreamThread.py new file mode 100644 index 0000000..2ccffed --- /dev/null +++ b/vodsdk/concurrency/Pull2PushStreamThread.py @@ -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) diff --git a/vodsdk/concurrency/PullMqttThread.py b/vodsdk/concurrency/PullMqttThread.py new file mode 100644 index 0000000..fe208fb --- /dev/null +++ b/vodsdk/concurrency/PullMqttThread.py @@ -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() + \ No newline at end of file diff --git a/vodsdk/concurrency/PullStreamThread.py b/vodsdk/concurrency/PullStreamThread.py new file mode 100644 index 0000000..29a8570 --- /dev/null +++ b/vodsdk/concurrency/PullStreamThread.py @@ -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) diff --git a/vodsdk/concurrency/PullVideoStreamProcess.py b/vodsdk/concurrency/PullVideoStreamProcess.py new file mode 100644 index 0000000..54fe030 --- /dev/null +++ b/vodsdk/concurrency/PullVideoStreamProcess.py @@ -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) diff --git a/vodsdk/concurrency/PullVideoStreamProcess2.py b/vodsdk/concurrency/PullVideoStreamProcess2.py new file mode 100644 index 0000000..39690b1 --- /dev/null +++ b/vodsdk/concurrency/PullVideoStreamProcess2.py @@ -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) diff --git a/vodsdk/concurrency/PushStreamThread.py b/vodsdk/concurrency/PushStreamThread.py new file mode 100644 index 0000000..1e395d9 --- /dev/null +++ b/vodsdk/concurrency/PushStreamThread.py @@ -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) \ No newline at end of file diff --git a/vodsdk/concurrency/PushStreamThread2.py b/vodsdk/concurrency/PushStreamThread2.py new file mode 100644 index 0000000..9b84882 --- /dev/null +++ b/vodsdk/concurrency/PushStreamThread2.py @@ -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) \ No newline at end of file diff --git a/vodsdk/concurrency/PushVideoStreamProcess.py b/vodsdk/concurrency/PushVideoStreamProcess.py new file mode 100644 index 0000000..2004da7 --- /dev/null +++ b/vodsdk/concurrency/PushVideoStreamProcess.py @@ -0,0 +1,486 @@ +#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, draw_name_joint + +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'] + + 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: + 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 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: + 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 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) diff --git a/vodsdk/concurrency/PushVideoStreamProcess2.py b/vodsdk/concurrency/PushVideoStreamProcess2.py new file mode 100644 index 0000000..8aac80b --- /dev/null +++ b/vodsdk/concurrency/PushVideoStreamProcess2.py @@ -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) diff --git a/vodsdk/concurrency/RecordingHeartbeatThread.py b/vodsdk/concurrency/RecordingHeartbeatThread.py new file mode 100644 index 0000000..614589c --- /dev/null +++ b/vodsdk/concurrency/RecordingHeartbeatThread.py @@ -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) diff --git a/vodsdk/concurrency/__init__.py b/vodsdk/concurrency/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/concurrency/__pycache__/CommonThread.cpython-38.pyc b/vodsdk/concurrency/__pycache__/CommonThread.cpython-38.pyc new file mode 100644 index 0000000..1a1ff99 Binary files /dev/null and b/vodsdk/concurrency/__pycache__/CommonThread.cpython-38.pyc differ diff --git a/vodsdk/concurrency/__pycache__/FeedbackThread.cpython-38.pyc b/vodsdk/concurrency/__pycache__/FeedbackThread.cpython-38.pyc new file mode 100644 index 0000000..ea9bb03 Binary files /dev/null and b/vodsdk/concurrency/__pycache__/FeedbackThread.cpython-38.pyc differ diff --git a/vodsdk/concurrency/__pycache__/FileUploadThread.cpython-38.pyc b/vodsdk/concurrency/__pycache__/FileUploadThread.cpython-38.pyc new file mode 100644 index 0000000..e00f621 Binary files /dev/null and b/vodsdk/concurrency/__pycache__/FileUploadThread.cpython-38.pyc differ diff --git a/vodsdk/concurrency/__pycache__/HeartbeatThread.cpython-38.pyc b/vodsdk/concurrency/__pycache__/HeartbeatThread.cpython-38.pyc new file mode 100644 index 0000000..0f848db Binary files /dev/null and b/vodsdk/concurrency/__pycache__/HeartbeatThread.cpython-38.pyc differ diff --git a/vodsdk/concurrency/__pycache__/IntelligentRecognitionProcess.cpython-38.pyc b/vodsdk/concurrency/__pycache__/IntelligentRecognitionProcess.cpython-38.pyc new file mode 100644 index 0000000..013cd6c Binary files /dev/null and b/vodsdk/concurrency/__pycache__/IntelligentRecognitionProcess.cpython-38.pyc differ diff --git a/vodsdk/concurrency/__pycache__/IntelligentRecognitionProcess2.cpython-38.pyc b/vodsdk/concurrency/__pycache__/IntelligentRecognitionProcess2.cpython-38.pyc new file mode 100644 index 0000000..ba056c0 Binary files /dev/null and b/vodsdk/concurrency/__pycache__/IntelligentRecognitionProcess2.cpython-38.pyc differ diff --git a/vodsdk/concurrency/__pycache__/Pull2PushStreamProcess.cpython-38.pyc b/vodsdk/concurrency/__pycache__/Pull2PushStreamProcess.cpython-38.pyc new file mode 100644 index 0000000..c312d3d Binary files /dev/null and b/vodsdk/concurrency/__pycache__/Pull2PushStreamProcess.cpython-38.pyc differ diff --git a/vodsdk/concurrency/__pycache__/Pull2PushStreamThread.cpython-38.pyc b/vodsdk/concurrency/__pycache__/Pull2PushStreamThread.cpython-38.pyc new file mode 100644 index 0000000..eb13c99 Binary files /dev/null and b/vodsdk/concurrency/__pycache__/Pull2PushStreamThread.cpython-38.pyc differ diff --git a/vodsdk/concurrency/__pycache__/PullMqttThread.cpython-38.pyc b/vodsdk/concurrency/__pycache__/PullMqttThread.cpython-38.pyc new file mode 100644 index 0000000..46040b3 Binary files /dev/null and b/vodsdk/concurrency/__pycache__/PullMqttThread.cpython-38.pyc differ diff --git a/vodsdk/concurrency/__pycache__/PullStreamThread.cpython-38.pyc b/vodsdk/concurrency/__pycache__/PullStreamThread.cpython-38.pyc new file mode 100644 index 0000000..f92df66 Binary files /dev/null and b/vodsdk/concurrency/__pycache__/PullStreamThread.cpython-38.pyc differ diff --git a/vodsdk/concurrency/__pycache__/PullVideoStreamProcess.cpython-38.pyc b/vodsdk/concurrency/__pycache__/PullVideoStreamProcess.cpython-38.pyc new file mode 100644 index 0000000..51d27cb Binary files /dev/null and b/vodsdk/concurrency/__pycache__/PullVideoStreamProcess.cpython-38.pyc differ diff --git a/vodsdk/concurrency/__pycache__/PullVideoStreamProcess2.cpython-38.pyc b/vodsdk/concurrency/__pycache__/PullVideoStreamProcess2.cpython-38.pyc new file mode 100644 index 0000000..bf5c126 Binary files /dev/null and b/vodsdk/concurrency/__pycache__/PullVideoStreamProcess2.cpython-38.pyc differ diff --git a/vodsdk/concurrency/__pycache__/PushStreamThread.cpython-38.pyc b/vodsdk/concurrency/__pycache__/PushStreamThread.cpython-38.pyc new file mode 100644 index 0000000..338c44f Binary files /dev/null and b/vodsdk/concurrency/__pycache__/PushStreamThread.cpython-38.pyc differ diff --git a/vodsdk/concurrency/__pycache__/PushStreamThread2.cpython-38.pyc b/vodsdk/concurrency/__pycache__/PushStreamThread2.cpython-38.pyc new file mode 100644 index 0000000..be48993 Binary files /dev/null and b/vodsdk/concurrency/__pycache__/PushStreamThread2.cpython-38.pyc differ diff --git a/vodsdk/concurrency/__pycache__/PushVideoStreamProcess.cpython-38.pyc b/vodsdk/concurrency/__pycache__/PushVideoStreamProcess.cpython-38.pyc new file mode 100644 index 0000000..27cbd8c Binary files /dev/null and b/vodsdk/concurrency/__pycache__/PushVideoStreamProcess.cpython-38.pyc differ diff --git a/vodsdk/concurrency/__pycache__/PushVideoStreamProcess2.cpython-38.pyc b/vodsdk/concurrency/__pycache__/PushVideoStreamProcess2.cpython-38.pyc new file mode 100644 index 0000000..dfc1775 Binary files /dev/null and b/vodsdk/concurrency/__pycache__/PushVideoStreamProcess2.cpython-38.pyc differ diff --git a/vodsdk/concurrency/__pycache__/RecordingHeartbeatThread.cpython-38.pyc b/vodsdk/concurrency/__pycache__/RecordingHeartbeatThread.cpython-38.pyc new file mode 100644 index 0000000..3c2c11f Binary files /dev/null and b/vodsdk/concurrency/__pycache__/RecordingHeartbeatThread.cpython-38.pyc differ diff --git a/vodsdk/concurrency/__pycache__/__init__.cpython-38.pyc b/vodsdk/concurrency/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..b963a8b Binary files /dev/null and b/vodsdk/concurrency/__pycache__/__init__.cpython-38.pyc differ diff --git a/vodsdk/concurrency/__pycache__/uploadGPU.cpython-38.pyc b/vodsdk/concurrency/__pycache__/uploadGPU.cpython-38.pyc new file mode 100644 index 0000000..0928cb6 Binary files /dev/null and b/vodsdk/concurrency/__pycache__/uploadGPU.cpython-38.pyc differ diff --git a/vodsdk/concurrency/uploadGPU.py b/vodsdk/concurrency/uploadGPU.py new file mode 100644 index 0000000..a85c0a7 --- /dev/null +++ b/vodsdk/concurrency/uploadGPU.py @@ -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("主线程退出") + + + + \ No newline at end of file diff --git a/vodsdk/config/aliyun/dsp_dev_aliyun.yml b/vodsdk/config/aliyun/dsp_dev_aliyun.yml new file mode 100644 index 0000000..680cbbf --- /dev/null +++ b/vodsdk/config/aliyun/dsp_dev_aliyun.yml @@ -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 diff --git a/vodsdk/config/aliyun/dsp_prod_aliyun.yml b/vodsdk/config/aliyun/dsp_prod_aliyun.yml new file mode 100644 index 0000000..a573884 --- /dev/null +++ b/vodsdk/config/aliyun/dsp_prod_aliyun.yml @@ -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 diff --git a/vodsdk/config/aliyun/dsp_test_aliyun.yml b/vodsdk/config/aliyun/dsp_test_aliyun.yml new file mode 100644 index 0000000..67d0aa5 --- /dev/null +++ b/vodsdk/config/aliyun/dsp_test_aliyun.yml @@ -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 + diff --git a/vodsdk/config/aliyun/dsp_test_aliyun.yml.bak b/vodsdk/config/aliyun/dsp_test_aliyun.yml.bak new file mode 100644 index 0000000..67d0aa5 --- /dev/null +++ b/vodsdk/config/aliyun/dsp_test_aliyun.yml.bak @@ -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 + diff --git a/vodsdk/config/baidu/dsp_dev_baidu.yml b/vodsdk/config/baidu/dsp_dev_baidu.yml new file mode 100644 index 0000000..249b70c --- /dev/null +++ b/vodsdk/config/baidu/dsp_dev_baidu.yml @@ -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" diff --git a/vodsdk/config/baidu/dsp_prod_baidu.yml b/vodsdk/config/baidu/dsp_prod_baidu.yml new file mode 100644 index 0000000..249b70c --- /dev/null +++ b/vodsdk/config/baidu/dsp_prod_baidu.yml @@ -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" diff --git a/vodsdk/config/baidu/dsp_test_baidu.yml b/vodsdk/config/baidu/dsp_test_baidu.yml new file mode 100644 index 0000000..249b70c --- /dev/null +++ b/vodsdk/config/baidu/dsp_test_baidu.yml @@ -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" diff --git a/vodsdk/config/kafka/dsp_dev_kafka.yml b/vodsdk/config/kafka/dsp_dev_kafka.yml new file mode 100644 index 0000000..2f9572d --- /dev/null +++ b/vodsdk/config/kafka/dsp_dev_kafka.yml @@ -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 + + + diff --git a/vodsdk/config/kafka/dsp_prod_kafka.yml b/vodsdk/config/kafka/dsp_prod_kafka.yml new file mode 100644 index 0000000..193048f --- /dev/null +++ b/vodsdk/config/kafka/dsp_prod_kafka.yml @@ -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 diff --git a/vodsdk/config/kafka/dsp_test_kafka.yml b/vodsdk/config/kafka/dsp_test_kafka.yml new file mode 100644 index 0000000..3ba39d8 --- /dev/null +++ b/vodsdk/config/kafka/dsp_test_kafka.yml @@ -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 + + diff --git a/vodsdk/config/logger/dsp_dev_logger.yml b/vodsdk/config/logger/dsp_dev_logger.yml new file mode 100644 index 0000000..697581d --- /dev/null +++ b/vodsdk/config/logger/dsp_dev_logger.yml @@ -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" + diff --git a/vodsdk/config/logger/dsp_prod_logger.yml b/vodsdk/config/logger/dsp_prod_logger.yml new file mode 100644 index 0000000..1e8baed --- /dev/null +++ b/vodsdk/config/logger/dsp_prod_logger.yml @@ -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" + diff --git a/vodsdk/config/logger/dsp_test_logger.yml b/vodsdk/config/logger/dsp_test_logger.yml new file mode 100644 index 0000000..2a2e706 --- /dev/null +++ b/vodsdk/config/logger/dsp_test_logger.yml @@ -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: "3 days" +encoding: "utf8" + diff --git a/vodsdk/config/minio/dsp_test_minio.yml b/vodsdk/config/minio/dsp_test_minio.yml new file mode 100644 index 0000000..d066ba4 --- /dev/null +++ b/vodsdk/config/minio/dsp_test_minio.yml @@ -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' diff --git a/vodsdk/config/minio/dsp_test_minio_OnDSJ.yml b/vodsdk/config/minio/dsp_test_minio_OnDSJ.yml new file mode 100644 index 0000000..d2f8aa3 --- /dev/null +++ b/vodsdk/config/minio/dsp_test_minio_OnDSJ.yml @@ -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' + diff --git a/vodsdk/config/mqtt/dsp_test_mqtt.yml b/vodsdk/config/mqtt/dsp_test_mqtt.yml new file mode 100644 index 0000000..a8e2310 --- /dev/null +++ b/vodsdk/config/mqtt/dsp_test_mqtt.yml @@ -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 + diff --git a/vodsdk/config/service/dsp_dev_service.yml b/vodsdk/config/service/dsp_dev_service.yml new file mode 100644 index 0000000..4c4150c --- /dev/null +++ b/vodsdk/config/service/dsp_dev_service.yml @@ -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 + + diff --git a/vodsdk/config/service/dsp_prod_service.yml b/vodsdk/config/service/dsp_prod_service.yml new file mode 100644 index 0000000..006c393 --- /dev/null +++ b/vodsdk/config/service/dsp_prod_service.yml @@ -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 + diff --git a/vodsdk/config/service/dsp_test_service.yml b/vodsdk/config/service/dsp_test_service.yml new file mode 100644 index 0000000..e00daac --- /dev/null +++ b/vodsdk/config/service/dsp_test_service.yml @@ -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 + #是否启用mqtt,0--不用,1--启用 + mqtt_flag: 0 + #是否启用alg控制功能 + algSwitch: false + diff --git a/vodsdk/dsp_master.py b/vodsdk/dsp_master.py new file mode 100644 index 0000000..b83977f --- /dev/null +++ b/vodsdk/dsp_master.py @@ -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) diff --git a/vodsdk/entity/FeedBack.py b/vodsdk/entity/FeedBack.py new file mode 100644 index 0000000..0ce6cf8 --- /dev/null +++ b/vodsdk/entity/FeedBack.py @@ -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() + }} diff --git a/vodsdk/entity/PullStreamDto.py b/vodsdk/entity/PullStreamDto.py new file mode 100644 index 0000000..b3b3533 --- /dev/null +++ b/vodsdk/entity/PullStreamDto.py @@ -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 + diff --git a/vodsdk/entity/__init__.py b/vodsdk/entity/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/entity/__pycache__/FeedBack.cpython-38.pyc b/vodsdk/entity/__pycache__/FeedBack.cpython-38.pyc new file mode 100644 index 0000000..0785694 Binary files /dev/null and b/vodsdk/entity/__pycache__/FeedBack.cpython-38.pyc differ diff --git a/vodsdk/entity/__pycache__/__init__.cpython-38.pyc b/vodsdk/entity/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..40746d9 Binary files /dev/null and b/vodsdk/entity/__pycache__/__init__.cpython-38.pyc differ diff --git a/vodsdk/enums/AnalysisStatusEnum.py b/vodsdk/enums/AnalysisStatusEnum.py new file mode 100644 index 0000000..ac30040 --- /dev/null +++ b/vodsdk/enums/AnalysisStatusEnum.py @@ -0,0 +1,21 @@ +from enum import Enum, unique + + +# 分析状态枚举 +@unique +class AnalysisStatus(Enum): + + # 等待 + WAITING = "waiting" + + # 分析中 + RUNNING = "running" + + # 分析完成 + SUCCESS = "success" + + # 超时 + TIMEOUT = "timeout" + + # 失败 + FAILED = "failed" diff --git a/vodsdk/enums/AnalysisTypeEnum.py b/vodsdk/enums/AnalysisTypeEnum.py new file mode 100644 index 0000000..6172d2a --- /dev/null +++ b/vodsdk/enums/AnalysisTypeEnum.py @@ -0,0 +1,25 @@ +from enum import Enum, unique + + +# 分析类型枚举 +@unique +class AnalysisType(Enum): + # 在线 + ONLINE = "1" + + # 离线 + OFFLINE = "2" + + # 图片 + IMAGE = "3" + + # 录屏 + RECORDING = "9999" + + # 转推流 + PULLTOPUSH = "10000" + + + + + diff --git a/vodsdk/enums/BaiduSdkEnum.py b/vodsdk/enums/BaiduSdkEnum.py new file mode 100644 index 0000000..8ea05cd --- /dev/null +++ b/vodsdk/enums/BaiduSdkEnum.py @@ -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 ,建议长宽比3:1以内,图片请求格式支持:PNG、JPG、BMP", 1, 0) + + SDK_IMAGE_LENGTH_ERROR = ('SDK101', "image length error", "图片边长不符合要求,最短边至少50px,最长边最大4096px ,建议长宽比3:1以内", 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 +} \ No newline at end of file diff --git a/vodsdk/enums/ExceptionEnum.py b/vodsdk/enums/ExceptionEnum.py new file mode 100644 index 0000000..59859b7 --- /dev/null +++ b/vodsdk/enums/ExceptionEnum.py @@ -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", "系统内部异常!") diff --git a/vodsdk/enums/ModelTypeEnum.py b/vodsdk/enums/ModelTypeEnum.py new file mode 100644 index 0000000..e3d473a --- /dev/null +++ b/vodsdk/enums/ModelTypeEnum.py @@ -0,0 +1,812 @@ +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, + #车辆","垃圾","商贩","裸土","占道经营","违停"---> + #"车辆","垃圾","商贩","违停","占道经营","裸土" + 'classReindex':{ 0:0,1:1,2:2,3:5,4:4,5:3} + } + }, + '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],'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.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 diff --git a/vodsdk/enums/ModelTypeEnum2.py b/vodsdk/enums/ModelTypeEnum2.py new file mode 100644 index 0000000..7e796c0 --- /dev/null +++ b/vodsdk/enums/ModelTypeEnum2.py @@ -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 diff --git a/vodsdk/enums/RecordingStatusEnum.py b/vodsdk/enums/RecordingStatusEnum.py new file mode 100644 index 0000000..c7bcad7 --- /dev/null +++ b/vodsdk/enums/RecordingStatusEnum.py @@ -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", "录制失败") diff --git a/vodsdk/enums/StatusEnum.py b/vodsdk/enums/StatusEnum.py new file mode 100644 index 0000000..0a8c4b3 --- /dev/null +++ b/vodsdk/enums/StatusEnum.py @@ -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, "失败") diff --git a/vodsdk/enums/__init__.py b/vodsdk/enums/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/enums/__pycache__/AnalysisStatusEnum.cpython-38.pyc b/vodsdk/enums/__pycache__/AnalysisStatusEnum.cpython-38.pyc new file mode 100644 index 0000000..f571b45 Binary files /dev/null and b/vodsdk/enums/__pycache__/AnalysisStatusEnum.cpython-38.pyc differ diff --git a/vodsdk/enums/__pycache__/AnalysisTypeEnum.cpython-38.pyc b/vodsdk/enums/__pycache__/AnalysisTypeEnum.cpython-38.pyc new file mode 100644 index 0000000..2e06f47 Binary files /dev/null and b/vodsdk/enums/__pycache__/AnalysisTypeEnum.cpython-38.pyc differ diff --git a/vodsdk/enums/__pycache__/BaiduSdkEnum.cpython-310.pyc b/vodsdk/enums/__pycache__/BaiduSdkEnum.cpython-310.pyc new file mode 100644 index 0000000..d3391b0 Binary files /dev/null and b/vodsdk/enums/__pycache__/BaiduSdkEnum.cpython-310.pyc differ diff --git a/vodsdk/enums/__pycache__/BaiduSdkEnum.cpython-38.pyc b/vodsdk/enums/__pycache__/BaiduSdkEnum.cpython-38.pyc new file mode 100644 index 0000000..e79c754 Binary files /dev/null and b/vodsdk/enums/__pycache__/BaiduSdkEnum.cpython-38.pyc differ diff --git a/vodsdk/enums/__pycache__/ExceptionEnum.cpython-310.pyc b/vodsdk/enums/__pycache__/ExceptionEnum.cpython-310.pyc new file mode 100644 index 0000000..f05bf3b Binary files /dev/null and b/vodsdk/enums/__pycache__/ExceptionEnum.cpython-310.pyc differ diff --git a/vodsdk/enums/__pycache__/ExceptionEnum.cpython-38.pyc b/vodsdk/enums/__pycache__/ExceptionEnum.cpython-38.pyc new file mode 100644 index 0000000..e2126d1 Binary files /dev/null and b/vodsdk/enums/__pycache__/ExceptionEnum.cpython-38.pyc differ diff --git a/vodsdk/enums/__pycache__/ModelTypeEnum.cpython-38.pyc b/vodsdk/enums/__pycache__/ModelTypeEnum.cpython-38.pyc new file mode 100644 index 0000000..9dd09f3 Binary files /dev/null and b/vodsdk/enums/__pycache__/ModelTypeEnum.cpython-38.pyc differ diff --git a/vodsdk/enums/__pycache__/ModelTypeEnum2.cpython-38.pyc b/vodsdk/enums/__pycache__/ModelTypeEnum2.cpython-38.pyc new file mode 100644 index 0000000..b4815eb Binary files /dev/null and b/vodsdk/enums/__pycache__/ModelTypeEnum2.cpython-38.pyc differ diff --git a/vodsdk/enums/__pycache__/RecordingStatusEnum.cpython-38.pyc b/vodsdk/enums/__pycache__/RecordingStatusEnum.cpython-38.pyc new file mode 100644 index 0000000..b7c0f70 Binary files /dev/null and b/vodsdk/enums/__pycache__/RecordingStatusEnum.cpython-38.pyc differ diff --git a/vodsdk/enums/__pycache__/StatusEnum.cpython-38.pyc b/vodsdk/enums/__pycache__/StatusEnum.cpython-38.pyc new file mode 100644 index 0000000..ec5fb91 Binary files /dev/null and b/vodsdk/enums/__pycache__/StatusEnum.cpython-38.pyc differ diff --git a/vodsdk/enums/__pycache__/__init__.cpython-310.pyc b/vodsdk/enums/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..d0c53ad Binary files /dev/null and b/vodsdk/enums/__pycache__/__init__.cpython-310.pyc differ diff --git a/vodsdk/enums/__pycache__/__init__.cpython-38.pyc b/vodsdk/enums/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..17fbca0 Binary files /dev/null and b/vodsdk/enums/__pycache__/__init__.cpython-38.pyc differ diff --git a/vodsdk/exception/CustomerException.py b/vodsdk/exception/CustomerException.py new file mode 100644 index 0000000..08cab3b --- /dev/null +++ b/vodsdk/exception/CustomerException.py @@ -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) + + + diff --git a/vodsdk/exception/__init__.py b/vodsdk/exception/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/exception/__pycache__/CustomerException.cpython-310.pyc b/vodsdk/exception/__pycache__/CustomerException.cpython-310.pyc new file mode 100644 index 0000000..b3b91b5 Binary files /dev/null and b/vodsdk/exception/__pycache__/CustomerException.cpython-310.pyc differ diff --git a/vodsdk/exception/__pycache__/CustomerException.cpython-38.pyc b/vodsdk/exception/__pycache__/CustomerException.cpython-38.pyc new file mode 100644 index 0000000..473fc42 Binary files /dev/null and b/vodsdk/exception/__pycache__/CustomerException.cpython-38.pyc differ diff --git a/vodsdk/exception/__pycache__/__init__.cpython-310.pyc b/vodsdk/exception/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..80858e8 Binary files /dev/null and b/vodsdk/exception/__pycache__/__init__.cpython-310.pyc differ diff --git a/vodsdk/exception/__pycache__/__init__.cpython-38.pyc b/vodsdk/exception/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..5fb7efd Binary files /dev/null and b/vodsdk/exception/__pycache__/__init__.cpython-38.pyc differ diff --git a/vodsdk/font/__init__.py b/vodsdk/font/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/font/simsun.ttc b/vodsdk/font/simsun.ttc new file mode 100644 index 0000000..40e9693 Binary files /dev/null and b/vodsdk/font/simsun.ttc differ diff --git a/vodsdk/image/logo.png b/vodsdk/image/logo.png new file mode 100644 index 0000000..d91cba4 Binary files /dev/null and b/vodsdk/image/logo.png differ diff --git a/vodsdk/readme.md b/vodsdk/readme.md new file mode 100644 index 0000000..d29501a --- /dev/null +++ b/vodsdk/readme.md @@ -0,0 +1,8 @@ +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,决定是否启用。 diff --git a/vodsdk/service/Dispatcher.py b/vodsdk/service/Dispatcher.py new file mode 100644 index 0000000..0641c05 --- /dev/null +++ b/vodsdk/service/Dispatcher.py @@ -0,0 +1,482 @@ +# -*- 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): + 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"}) + + # 新增该函数用于,向子任务发送命令(algStart,algStop) + 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): + 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) + + ''' + 在线分析逻辑 + ''' + + 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 offline(self, message, analysisType): + 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", [])}) diff --git a/vodsdk/service/__init__.py b/vodsdk/service/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/service/__pycache__/Dispatcher.cpython-310.pyc b/vodsdk/service/__pycache__/Dispatcher.cpython-310.pyc new file mode 100644 index 0000000..060bc19 Binary files /dev/null and b/vodsdk/service/__pycache__/Dispatcher.cpython-310.pyc differ diff --git a/vodsdk/service/__pycache__/Dispatcher.cpython-38.pyc b/vodsdk/service/__pycache__/Dispatcher.cpython-38.pyc new file mode 100644 index 0000000..1919f51 Binary files /dev/null and b/vodsdk/service/__pycache__/Dispatcher.cpython-38.pyc differ diff --git a/vodsdk/service/__pycache__/__init__.cpython-310.pyc b/vodsdk/service/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..d0d3a66 Binary files /dev/null and b/vodsdk/service/__pycache__/__init__.cpython-310.pyc differ diff --git a/vodsdk/service/__pycache__/__init__.cpython-38.pyc b/vodsdk/service/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..a52c2a3 Binary files /dev/null and b/vodsdk/service/__pycache__/__init__.cpython-38.pyc differ diff --git a/vodsdk/start.sh b/vodsdk/start.sh new file mode 100644 index 0000000..606bd68 --- /dev/null +++ b/vodsdk/start.sh @@ -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 \ No newline at end of file diff --git a/vodsdk/stop.sh b/vodsdk/stop.sh new file mode 100644 index 0000000..5512a80 --- /dev/null +++ b/vodsdk/stop.sh @@ -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 \ No newline at end of file diff --git a/vodsdk/test/__init__.py b/vodsdk/test/__init__.py new file mode 100644 index 0000000..b346b0f --- /dev/null +++ b/vodsdk/test/__init__.py @@ -0,0 +1,3 @@ + +dd = {} +print(dd.get('name', 'aaa')) \ No newline at end of file diff --git a/vodsdk/test/__pycache__/__init__.cpython-38.pyc b/vodsdk/test/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..1335fd3 Binary files /dev/null and b/vodsdk/test/__pycache__/__init__.cpython-38.pyc differ diff --git a/vodsdk/test/aliyun/__init__.py b/vodsdk/test/aliyun/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/aliyun/aaa.jpeg b/vodsdk/test/aliyun/aaa.jpeg new file mode 100644 index 0000000..620fd55 Binary files /dev/null and b/vodsdk/test/aliyun/aaa.jpeg differ diff --git a/vodsdk/test/aliyun/ossdemo.py b/vodsdk/test/aliyun/ossdemo.py new file mode 100644 index 0000000..c22d771 --- /dev/null +++ b/vodsdk/test/aliyun/ossdemo.py @@ -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。 + 对于CentOS、RHEL、Fedora系统,请执行以下命令安装python-devel。 + sudo yum install python-devel + 对于Debian,Ubuntu系统,请执行以下命令安装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 + diff --git a/vodsdk/test/aliyun/vod.py b/vodsdk/test/aliyun/vod.py new file mode 100644 index 0000000..57733d5 --- /dev/null +++ b/vodsdk/test/aliyun/vod.py @@ -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('') + # 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('') +# # 标签 +# # 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) \ No newline at end of file diff --git a/vodsdk/test/aliyun/vodTest.py b/vodsdk/test/aliyun/vodTest.py new file mode 100644 index 0000000..903b050 --- /dev/null +++ b/vodsdk/test/aliyun/vodTest.py @@ -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('') + # 标签 + # 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)) \ No newline at end of file diff --git a/vodsdk/test/aliyun/voddemo.py b/vodsdk/test/aliyun/voddemo.py new file mode 100644 index 0000000..51378a8 --- /dev/null +++ b/vodsdk/test/aliyun/voddemo.py @@ -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) + + + diff --git a/vodsdk/test/aliyun/vodtest1.py b/vodsdk/test/aliyun/vodtest1.py new file mode 100644 index 0000000..2149c8e --- /dev/null +++ b/vodsdk/test/aliyun/vodtest1.py @@ -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"]) \ No newline at end of file diff --git a/vodsdk/test/aliyun/vodtest2.py b/vodsdk/test/aliyun/vodtest2.py new file mode 100644 index 0000000..f767f18 --- /dev/null +++ b/vodsdk/test/aliyun/vodtest2.py @@ -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()) \ No newline at end of file diff --git a/vodsdk/test/collections/ChainMap.py b/vodsdk/test/collections/ChainMap.py new file mode 100644 index 0000000..fb0d8ec --- /dev/null +++ b/vodsdk/test/collections/ChainMap.py @@ -0,0 +1,55 @@ + + + +""" +1、ChainMap是什么 +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) diff --git a/vodsdk/test/collections/Counter.py b/vodsdk/test/collections/Counter.py new file mode 100644 index 0000000..dd91abb --- /dev/null +++ b/vodsdk/test/collections/Counter.py @@ -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)) + +""" +1、elements() +描述:返回一个迭代器,其中每个元素将重复出现计数值所指定次。 元素会按首次出现的顺序返回。 如果一个元素的计数值小于1,elements() 将会忽略它。 +语法: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())) + +""" +2、most_common() +返回一个列表,其中包含n个最常见的元素及出现次数,按常见程度由高到低排序。 +如果n被省略或为None,most_common() 将返回计数器中的所有元素, +计数值相等的元素按首次出现的顺序排序,经常用来计算top词频的词语。 +""" +print(Counter('abracadabra').most_common(3)) +print(Counter('abracadabra').most_common(5)) + +""" +3、subtract() +从迭代对象或映射对象减去元素。像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) diff --git a/vodsdk/test/collections/OrderedDict.py b/vodsdk/test/collections/OrderedDict.py new file mode 100644 index 0000000..ffe5842 --- /dev/null +++ b/vodsdk/test/collections/OrderedDict.py @@ -0,0 +1,35 @@ +from collections import OrderedDict + + +""" +1、popitem +语法: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)) + +""" +2、move_to_end +""" +d = OrderedDict.fromkeys('abcde') +d.move_to_end('b') +print(d) +d.move_to_end('b', last=False) +print(d) + +""" +3、reversed() +相对于通常的映射方法,有序字典还另外提供了逆序迭代的支持,通过reversed()。 +""" +d = OrderedDict.fromkeys('acbde') +print(d) +print(list(reversed(d))) + +c = OrderedDict({'a': 1, 'c': 2, 'b': 3}) +print(c) \ No newline at end of file diff --git a/vodsdk/test/collections/__init__.py b/vodsdk/test/collections/__init__.py new file mode 100644 index 0000000..ecaf0a7 --- /dev/null +++ b/vodsdk/test/collections/__init__.py @@ -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] diff --git a/vodsdk/test/collections/defaultdict.py b/vodsdk/test/collections/defaultdict.py new file mode 100644 index 0000000..e6a6e09 --- /dev/null +++ b/vodsdk/test/collections/defaultdict.py @@ -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']) + diff --git a/vodsdk/test/collections/deque.py b/vodsdk/test/collections/deque.py new file mode 100644 index 0000000..1c98a64 --- /dev/null +++ b/vodsdk/test/collections/deque.py @@ -0,0 +1,148 @@ + +""" +deque +双端队列,可以快速的从另外一侧追加和推出对象,deque是一个双向链表, +针对list连续的数据结构插入和删除进行优化。它提供了两端都可以操作的序列, +这表示在序列的前后你都可以执行添加或删除操作。双向队列(deque)对象支持以下方法: +""" +from collections import deque + +""" +1、append() +添加 x 到右端。 +""" +d = deque('ghi') +d.append('j') +print(d) + +""" +2、appendleft() +添加 x 到左端。 +""" +d.appendleft('f') +print(d) + +""" +3、clear() +移除所有元素,使其长度为0. +""" +d = deque('ghi') +d.clear() +print(d) + +""" +4、copy() +创建一份浅拷贝。 +""" +d = deque('xiaoweuge') +y = d.copy() +print(y) + +""" +5、count() +计算 deque 中元素等于 x 的个数。 +""" +d = deque('xiaoweuge-shuai') +print(d.count('a')) + +""" +6、extend() +扩展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) + +""" +7、extendleft() +扩展deque的左侧,通过添加iterable参数中的元素。注意,左添加时,在结果中iterable参数中的顺序将被反过来添加。 +""" +a = deque('abc') +b = deque('cd') +a.extendleft(b) +print(a) + +""" +8、index() +返回 x 在 deque 中的位置(在索引 start 之后,索引 stop 之前)。 返回第一个匹配项,如果未找到则引发 ValueError。 +""" +d = deque('xiaoweuge') +print(d.index('w')) + +""" +9、insert() +在位置 i 插入 x 。 +如果插入会导致一个限长 deque 超出长度 maxlen 的话,就引发一个 IndexError。 +""" +a = deque('abc') +a.insert(1, 'X') +print(a) + +""" +10、pop() +移去并且返回一个元素,deque 最右侧的那一个。 如果没有元素的话,就引发一个 IndexError。 +""" +d = deque('abc') +print(d.pop()) + +""" +11、popleft() +移去并且返回一个元素,deque 最左侧的那一个。 如果没有元素的话,就引发 IndexError。 +""" +d = deque('abc') +print(d.popleft()) + +""" +12、remove(value) +移除找到的第一个 value。 如果没有的话就引发 ValueError。 +""" +a = deque('abca') +a.remove('a') +print(a) + +""" +13、reverse() +将deque逆序排列。返回 None 。 +""" +#逆序排列 +d = deque('ghi') # 创建一个deque +print(list(reversed(d))) + +""" +14、rotate(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) + +""" +15、maxlen +Deque的最大尺寸,如果没有限定的话就是 None 。 +""" +d=deque(maxlen=10) +for i in range(20): + d.append(i) +print(d) \ No newline at end of file diff --git a/vodsdk/test/collections/namedtuple.py b/vodsdk/test/collections/namedtuple.py new file mode 100644 index 0000000..884b79e --- /dev/null +++ b/vodsdk/test/collections/namedtuple.py @@ -0,0 +1,83 @@ + + +from collections import namedtuple + +""" +可命名元组-namedtuple +生成可以使用名字来访问元素内容的tuple子类,命名元组赋予每个位置一个含义,提供可读性和自文档性。 +它们可以用于任何普通元组,并添加了通过名字获取值的能力,通过索引值也是可以的。 +1、参数介绍 +namedtuple(typename,field_names,*,verbose=False, rename=False, module=None) +1)typename:该参数指定所创建的tuple子类的类名,相当于用户定义了一个新类。 +2)field_names:该参数是一个字符串序列,如 ['x','y']。此外,field_names 也可直接使用单个字符串代表所有字段名,多个字段名用空格、逗号隔开,如 'x y' 或 'x,y'。任何有效的 Python 标识符都可作为字段名(不能以下画线开头)。有效的标识符可由字母、数字、下画线组成,但不能以数字、下面线开头,也不能是关键字(如 return、global、pass、raise 等)。 +3)rename:如果将该参数设为 True,那么无效的字段名将会被自动替换为位置名。例如指定 ['abc','def','ghi','abc'],它将会被替换为 ['abc', '_1','ghi','_3'],这是因为 def 字段名是关键字,而 abc 字段名重复了。 +4)verbose:如果该参数被设为 True,那么当该子类被创建后,该类定义就被立即打印出来。 +5)module:如果设置了该参数,那么该类将位于该模块下,因此该自定义类的 __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')) \ No newline at end of file diff --git a/vodsdk/test/color/__init__.py b/vodsdk/test/color/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/color/color_test.py b/vodsdk/test/color/color_test.py new file mode 100644 index 0000000..f421c1e --- /dev/null +++ b/vodsdk/test/color/color_test.py @@ -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) diff --git a/vodsdk/test/color/platech.ttf b/vodsdk/test/color/platech.ttf new file mode 100644 index 0000000..d66a970 Binary files /dev/null and b/vodsdk/test/color/platech.ttf differ diff --git a/vodsdk/test/cpu/__init__.py b/vodsdk/test/cpu/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/cpu/test.py b/vodsdk/test/cpu/test.py new file mode 100644 index 0000000..8c8c080 --- /dev/null +++ b/vodsdk/test/cpu/test.py @@ -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())) + + diff --git a/vodsdk/test/cuda/__init__.py b/vodsdk/test/cuda/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/cuda/test.py b/vodsdk/test/cuda/test.py new file mode 100644 index 0000000..56de0cc --- /dev/null +++ b/vodsdk/test/cuda/test.py @@ -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) diff --git a/vodsdk/test/cuda/test1.py b/vodsdk/test/cuda/test1.py new file mode 100644 index 0000000..3613b74 --- /dev/null +++ b/vodsdk/test/cuda/test1.py @@ -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) \ No newline at end of file diff --git a/vodsdk/test/demo/__init__.py b/vodsdk/test/demo/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/demo/demo1.py b/vodsdk/test/demo/demo1.py new file mode 100644 index 0000000..0be8b68 --- /dev/null +++ b/vodsdk/test/demo/demo1.py @@ -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() + + + + + + diff --git a/vodsdk/test/demo/demo2.py b/vodsdk/test/demo/demo2.py new file mode 100644 index 0000000..1d37fed --- /dev/null +++ b/vodsdk/test/demo/demo2.py @@ -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() + + + + + diff --git a/vodsdk/test/demo/demo3.py b/vodsdk/test/demo/demo3.py new file mode 100644 index 0000000..c7e508a --- /dev/null +++ b/vodsdk/test/demo/demo3.py @@ -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)) \ No newline at end of file diff --git a/vodsdk/test/demo/demo4.py b/vodsdk/test/demo/demo4.py new file mode 100644 index 0000000..56d87f8 --- /dev/null +++ b/vodsdk/test/demo/demo4.py @@ -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) + diff --git a/vodsdk/test/demo/demo5.py b/vodsdk/test/demo/demo5.py new file mode 100644 index 0000000..e1ff745 --- /dev/null +++ b/vodsdk/test/demo/demo5.py @@ -0,0 +1,16 @@ +import multiprocessing as mp + + +def aa1(aa2): + print("1111111111", id(aa2), aa2) + + +aa = [1, 2, 3, 4, 5, 6] +print(id(aa)) +# num = mp.Array('i', aa) +p = mp.Process(target=aa1, args=(aa,)) +p1 = mp.Process(target=aa1, args=(aa,)) +p2 = mp.Process(target=aa1, args=(aa,)) +p.start() +p1.start() +p2.start() diff --git a/vodsdk/test/demo/demo6.py b/vodsdk/test/demo/demo6.py new file mode 100644 index 0000000..be70d1b --- /dev/null +++ b/vodsdk/test/demo/demo6.py @@ -0,0 +1,25 @@ +import multiprocessing +from multiprocessing import Process, Lock, Queue +import time +import sys; print('Python %s on %s' % (sys.version, sys.platform)) +sys.path.extend([r'D:\tuoheng\codenew\update\tuoheng_alg\test\demo\demo6.py']) +# 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() +def add_one(aaa): + aaa.put("111111111") + aaa.cancel_join_thread() + + +if __name__ == '__main__': + aa = Queue() + + p1 = Process(target=add_one, args=(aa,)) + p1.start() + time.sleep(2) + print(aa.get()) + + diff --git a/vodsdk/test/demo/demo7.py b/vodsdk/test/demo/demo7.py new file mode 100644 index 0000000..7ba29b8 --- /dev/null +++ b/vodsdk/test/demo/demo7.py @@ -0,0 +1,167 @@ +import multiprocessing as mp +import sys +import time +from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor, wait, ALL_COMPLETED +from multiprocessing import Queue + +import cv2 +import tensorrt as trt +sys.path.extend(['/home/th/tuo_heng/dev/tuoheng_alg', '/home/th/tuo_heng/dev/tuoheng_alg/util']) +from util.PlotsUtils import get_label_arrays +from util.TorchUtils import select_device + +sys.path.extend(['/home/th/tuo_heng/', '/home/th/tuo_heng/dev', '/home/th/tuo_heng/dev/AIlib2', '/home/th/tuo_heng/dev/AIlib2/segutils']) +from segutils.segmodel import SegModel +from models.experimental import attempt_load +from AI import AI_process +from utilsK.queRiver import riverDetSegMixProcess + +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]) +par = { + 'device': '0', + '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': "/home/th/tuo_heng/dev/AIlib2/weights/river/yolov5_2080Ti_fp16.engine", + 'Segweights': '/home/th/tuo_heng/dev/AIlib2/weights/river/stdc_360X640_2080Ti_fp16.engine' +} +mode, postPar, segPar = par.get('mode', 'others'), par.get('postPar'), par.get('segPar') +new_device = select_device(par.get('device')) +names = par['labelnames'] +half = new_device.type != 'cpu' +Detweights = par['Detweights'] +with open(Detweights, "rb") as f, trt.Runtime(trt.Logger(trt.Logger.ERROR)) as runtime: + model = runtime.deserialize_cuda_engine(f.read()) +Segweights = par['Segweights'] +if Segweights: + with open(Segweights, "rb") as f, trt.Runtime(trt.Logger(trt.Logger.ERROR)) as runtime: + segmodel = runtime.deserialize_cuda_engine(f.read()) +else: + segmodel = None +postFile = par['postFile'] +rainbows = postFile["rainbows"] +objectPar = { + 'half': half, + 'device': new_device, + 'conf_thres': postFile["conf_thres"], + 'ovlap_thres_crossCategory': postFile.get("ovlap_thres_crossCategory"), + 'iou_thres': postFile["iou_thres"], + 'allowedList': [], + 'segRegionCnt': par['segRegionCnt'], + 'trtFlag_det': par['trtFlag_det'], + 'trtFlag_seg': par['trtFlag_seg'] +} +Detweights = "/home/th/tuo_heng/dev/AIlib2/weights/river2/yolov5_2080Ti_fp16.engine" +with open(Detweights, "rb") as f, trt.Runtime(trt.Logger(trt.Logger.ERROR)) as runtime: + model = runtime.deserialize_cuda_engine(f.read()) +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()) + + +allowedList = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] + + + +def one_label(width, height, model_param): + names = model_param[4] + rainbows = model_param[6] + digitFont, label_arraylist, font_config = get_label_arraylist(width, height, names, rainbows) + """ + font_config, frame, model, segmodel, names, label_arraylist, rainbows, objectPar, font, segPar, mode, postPar, + requestId + """ + model_param[5] = label_arraylist + model_param[8] = digitFont + model_param[0] = font_config + + +def get_label_arraylist(*args): + width, height, names, rainbows = args + # line = int(round(0.002 * (height + width) / 2) + 1) + line = int(width / 1920 * 3 - 1) + label = ' 0.95' + tf = max(line, 1) + fontScale = line * 0.33 + text_width, text_height = cv2.getTextSize(label, 0, fontScale=fontScale, thickness=tf)[0] + fontsize = int(width / 1920 * 40) + numFontSize = float(format(width / 1920 * 1.1, '.1f')) + digitFont = {'line_thickness': line, + 'boxLine_thickness': line, + 'fontSize': numFontSize, + 'waterLineColor': (0, 255, 255), + 'segLineShow': False, + 'waterLineWidth': line} + label_arraylist = get_label_arrays(names, rainbows, text_height, fontSize=fontsize, + fontPath="/home/th/tuo_heng/dev/AIlib2/conf/platech.ttf") + return digitFont, label_arraylist, (line, text_width, text_height, fontScale, tf) +image = cv2.imread("/home/th/tuo_heng/dev/ompv2fn94m_1687259193110.jpg") +start_time1 = time.time() +with ThreadPoolExecutor(max_workers=3) as t: + rs = [] + for i in range(500): + rr = t.submit(AI_process, [image], model, segmodel, names, None, rainbows, objectPar=objectPar, + font={'line_thickness': 1, + 'boxLine_thickness': 1, + 'fontSize': 1.1, + 'waterLineColor': (0, 255, 255), + 'segLineShow': False, + 'waterLineWidth': 1}, segPar=segPar, mode=mode, postPar=postPar) + rs.append(rr) + for i in rs: + i.result() +print(time.time() - start_time1) + +start_time = time.time() +for i in range(500): + AI_process([image], model, segmodel, names, None, rainbows, objectPar=objectPar, + font={'line_thickness': 1, + 'boxLine_thickness': 1, + 'fontSize': 1.1, + 'waterLineColor': (0, 255, 255), + 'segLineShow': False, + 'waterLineWidth': 1}, segPar=segPar, mode=mode, postPar=postPar) +print(time.time() - start_time) diff --git a/vodsdk/test/demo/demo8.py b/vodsdk/test/demo/demo8.py new file mode 100644 index 0000000..8d05ffa --- /dev/null +++ b/vodsdk/test/demo/demo8.py @@ -0,0 +1,10 @@ +import cv2 +from PIL import ImageFont + +label = ' 0.95' +# fontScale=fontScale, thickness=tf +text_width, text_height = cv2.getTextSize(label, 0, fontScale=1, thickness=1)[0] +print(text_height) +font = ImageFont.truetype("/home/th/tuo_heng/dev/AIlib2/conf/platech.ttf", 22, encoding='utf-8') +x, y, width, height = font.getbbox("植被") +print(x, y, width, height) \ No newline at end of file diff --git a/vodsdk/test/demo1.py b/vodsdk/test/demo1.py new file mode 100644 index 0000000..9ff5613 --- /dev/null +++ b/vodsdk/test/demo1.py @@ -0,0 +1,130 @@ +# -*- coding: utf-8 -*- +import datetime +import time + +import json + +from aliyunsdkcore.client import AcsClient +from aliyunsdkvod.request.v20170321 import GetPlayInfoRequest +from loguru import logger + +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 +5. 视频域名地址:https://vod.play.t-aaron.com/ +''' + + +class AliyunVodSdk: + + def __init__(self, requestId): + self.__client = None + self.__access_key = 'LTAI5tMiefafZ6br4zmrQWv9' + self.__access_secret = 'JgzQjSCkwZ7lefZO6egOArw38YH1Tk' + self.__regionId = "cn-shanghai" + self.__cateId = '1000468340' + self.__requestId = requestId + + def init_vod_client(self): + return AcsClient(self.__access_key, self.__access_secret, self.__regionId, auto_retry=True, max_retry_time=3, timeout=30) + + ''' + 根据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)): + logger.exception("获取视频地址失败: {}", e) + raise e + diff_time = current_time - start + if diff_time > 60 * 60 * 5: + logger.exception("获取视频地址失败超时异常: {},超时时间:{}", str(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, self.__requestId) + 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 Exception as e: + retry_count += 1 + time.sleep(1) + logger.error("vod视频上传失败,重试次数:{}", retry_count) + if retry_count >= MAX_RETRIES: + logger.exception("vod视频上传重试失败: {}", str(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\\111.mp4' + codClinet = AliyunVodSdk("1111111") + result = codClinet.upload_local_video(filePath, 'aiOnLineVideo') + print(result) + url = codClinet.get_play_info(result) + print(url) + + + + diff --git a/vodsdk/test/dsp/logs/dsp.log b/vodsdk/test/dsp/logs/dsp.log new file mode 100644 index 0000000..402e4f4 --- /dev/null +++ b/vodsdk/test/dsp/logs/dsp.log @@ -0,0 +1,7 @@ +2023-04-18 13:41:42.066 [ERROR][MainProcess-25160-MainThread-30168][16] Test- - 异常信息:division by zero +Traceback (most recent call last): + +> File "D:\tuoheng\codenew\tuoheng_alg\test\路径\Test.py", line 14, in + 2/0 + +ZeroDivisionError: division by zero diff --git a/vodsdk/test/editimage/__init__.py b/vodsdk/test/editimage/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/editimage/editImage.py b/vodsdk/test/editimage/editImage.py new file mode 100644 index 0000000..b8e0755 --- /dev/null +++ b/vodsdk/test/editimage/editImage.py @@ -0,0 +1,45 @@ +from io import BytesIO + +import cv2 +import matplotlib.pyplot as plt +import matplotlib.patches as pat +import numpy as np +import requests +from PIL import ImageDraw, Image + +from util.ImageUtils import url2Array + +url = "https://www.2008php.com/2015_Website_appreciate/2015-12-06/20151206234254.jpg" + +color= (255, 255, 0) +#( 蓝, 绿, 红) +# 红色 (0, 0, 255) +# 洋红色 (255, 0, 255) +# 青色 (255, 255, 0) +# 黑色 (0, 0, 0) +# 蓝色 (255, 0, 0) +# 绿色 (0, 255, 0) +# 黄色 (0, 255, 255) # 不考虑 +img = url2Array(url) +cv2.putText(img,"Hello World", (100,100), cv2.FONT_HERSHEY_SIMPLEX, 1.0,color, 1, cv2.LINE_AA) +# rectangle 坐标的参数格式为左上角(x1, y1),右下角(x2, y2), 颜色 , 粗细 +cv2.rectangle(img, (100, 110), (400, 310), color, 2) +cv2.imshow('img', img) +cv2.waitKey() + +# fig, ax = plt.subplots(1) +# ax.imshow(img) +# # Rectangle 坐标的参数格式为左上角(x, y),width, height。 +# rec = pat.Rectangle((386, 144), 1049, 760, linewidth=2, edgecolor='r', facecolor='None') +# ax.add_patch(rec) +# plt.imshow(img) +# plt.show() +# response = requests.get(url) +# image = Image.open(BytesIO(response.content)) +# a = ImageDraw.ImageDraw(image) +# # rectangle 坐标的参数格式为左上角(x1, y1),右下角(x2, y2)。 +# a.rectangle(((386, 144), (1435, 904)), fill=None, outline='red', width=2) +# image.show() + + + diff --git a/vodsdk/test/ffmpeg11/Test.py b/vodsdk/test/ffmpeg11/Test.py new file mode 100644 index 0000000..ee2e272 --- /dev/null +++ b/vodsdk/test/ffmpeg11/Test.py @@ -0,0 +1,843 @@ +import sys, yaml +from easydict import EasyDict as edict +from concurrent.futures import ThreadPoolExecutor + +sys.path.extend(['..','../AIlib2' ]) + +from AI import AI_process,AI_process_forest,get_postProcess_para,get_postProcess_para_dic,ocr_process,AI_det_track,AI_det_track_batch +import cv2,os,time +from segutils.segmodel import SegModel +from segutils.segmodel import SegModel +from segutils.trafficUtils import tracfficAccidentMixFunction +from models.experimental import attempt_load +from utils.torch_utils import select_device +from utilsK.queRiver import get_labelnames,get_label_arrays,save_problem_images,riverDetSegMixProcess +from ocrUtils.ocrUtils import CTCLabelConverter,AlignCollate +from trackUtils.sort import Sort,track_draw_boxAndTrace,track_draw_trace_boxes,moving_average_wang,drawBoxTraceSimplied +from trackUtils.sort_obb import OBB_Sort,obbTohbb,track_draw_all_boxes,track_draw_trace +from obbUtils.shipUtils import OBB_infer,OBB_tracker,draw_obb,OBB_tracker_batch +from utilsK.noParkingUtils import mixNoParking_road_postprocess +from obbUtils.load_obb_model import load_model_decoder_OBB +import numpy as np +import torch,glob +import tensorrt as trt +from utilsK.masterUtils import get_needed_objectsIndex +from copy import deepcopy +from scipy import interpolate +from utilsK.drownUtils import mixDrowing_water_postprocess +#import warnings +#warnings.filterwarnings("error") + +def view_bar(num, total,time1,prefix='prefix'): + rate = num / total + time_n=time.time() + rate_num = int(rate * 30) + rate_nums = np.round(rate * 100) + r = '\r %s %d / %d [%s%s] %.2f s'%(prefix,num,total, ">" * rate_num, " " * (30 - rate_num), time_n-time1 ) + sys.stdout.write(r) + sys.stdout.flush() + + +''' + 多线程 +''' + +def process_v1(frame): + #try: + print('demo.py beging to :',frame[8]) + time00 = time.time() + H,W,C = frame[0][0].shape + + p_result,timeOut = AI_process(frame[0],frame[1],frame[2],frame[3],frame[4],frame[5],objectPar=frame[6],font=frame[7],segPar=frame[9],mode=frame[10],postPar=frame[11]) + + time11 = time.time() + image_array = p_result[1] + + cv2.imwrite(os.path.join('images/results/',frame[8] ) ,image_array) + bname = frame[8].split('.')[0] + if len(p_result)==5: + image_mask = p_result[4] + cv2.imwrite(os.path.join('images/results/',bname+'_mask.png' ) , (image_mask).astype(np.uint8)) + + boxes=p_result[2] + with open( os.path.join('images/results/',bname+'.txt' ),'w' ) as fp: + for box in boxes: + box_str=[str(x) for x in box] + out_str=','.join(box_str)+'\n' + fp.write(out_str) + time22 = time.time() + print('%s,%d*%d,AI-process: %.1f,image save:%.1f , %s'%(frame[8],H,W, (time11 - time00) * 1000.0, (time22-time11)*1000.0,timeOut), boxes) + return 'success' + #except Exception as e: + # return 'failed:'+str(e) +def process_video(video,par0,mode='detSeg'): + cap=cv2.VideoCapture(video) + if not cap.isOpened(): + print('#####error url:',video) + return False + bname=os.path.basename(video).split('.')[0] + fps = int(cap.get(cv2.CAP_PROP_FPS)+0.5) + width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH )+0.5) + height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)+0.5) + framecnt=int(cap.get(7)+0.5) + save_path_AI = os.path.join(par0['outpth'],os.path.basename(video)) + problem_image_dir= os.path.join( par0['outpth'], 'probleImages' ) + os.makedirs(problem_image_dir,exist_ok=True) + vid_writer_AI = cv2.VideoWriter(save_path_AI, cv2.VideoWriter_fourcc(*'mp4v'), fps, (width,height)) + num=0 + iframe=0;post_results=[];fpsample=30*10 + + imgarray_list = []; iframe_list = [] + + patch_cnt = par0['trackPar']['patchCnt'] + ##windowsize 对逐帧插值后的结果做平滑,windowsize为平滑的长度,没隔det_cnt帧做一次跟踪。 + trackPar={'det_cnt':10,'windowsize':29 } + + + ##track_det_result_update= np.empty((0,8)) ###每100帧跑出来的结果,放在track_det_result_update,只保留当前100帧里有的tracker Id. + while cap.isOpened(): + ret, imgarray = cap.read() #读取摄像头画面 + iframe +=1 + if not ret:break + if mode=='detSeg': + p_result,timeOut = AI_process([imgarray],par0['model'],par0['segmodel'],par0['names'],par0['label_arraylist'],par0['rainbows'],objectPar=par0['objectPar'],font=par0['digitFont'],segPar=par0['segPar']) + elif mode == 'track': + #sampleCount=10 + imgarray_list.append( imgarray ) + iframe_list.append(iframe ) + if iframe%patch_cnt==0: + time_patch0 = time.time() + retResults,timeInfos = AI_det_track_batch(imgarray_list, iframe_list ,par0['modelPar'],par0['processPar'],par0['sort_tracker'] ,par0['trackPar'],segPar=par0['segPar']) + #print('###line111:',retResults[2]) + ###需要保存成一个二维list,每一个list是一帧检测结果。 + ###track_det_result 内容格式:x1, y1, x2, y2, conf, cls,iframe,trackId + time_patch2 = time.time() + frame_min = iframe_list[0];frame_max=iframe_list[-1] + for iiframe in range(frame_min,frame_max+1): + img_draw = imgarray_list[ iiframe- frame_min ] + img_draw = drawBoxTraceSimplied(retResults[1] ,iiframe, img_draw,rainbows=par0['drawPar']['rainbows'],boxFlag=True,traceFlag=True,names=par0['drawPar']['names'] ) + ret = vid_writer_AI.write(img_draw) + view_bar(iiframe, framecnt,time.time(),prefix=os.path.basename(video)) + imgarray_list=[];iframe_list=[] + elif mode =='obbTrack': + imgarray_list.append( imgarray ) + iframe_list.append(iframe ) + if iframe%patch_cnt==0: + time_patch0 = time.time() + + track_det_results, timeInfos = OBB_tracker_batch(imgarray_list,iframe_list,par0['modelPar'],par0['obbModelPar'],par0['sort_tracker'],par0['trackPar'],segPar=None) + print( timeInfos ) + + #对结果画图 + track_det_np = track_det_results[1] + frame_min = iframe_list[0];frame_max=iframe_list[-1] + for iiframe in range(frame_min,frame_max+1): + img_draw = imgarray_list[ iiframe- frame_min ] + + if len( track_det_results[2][ iiframe- frame_min]) > 0: + img_draw = draw_obb( track_det_results[2][iiframe- frame_min ] ,img_draw,par0['drawPar']) + if True: + frameIdex=12;trackIdex=13; + boxes_oneFrame = track_det_np[ track_det_np[:,frameIdex]==iiframe ] + + ###在某一帧上,画上轨迹 + track_ids = boxes_oneFrame[:,trackIdex].tolist() + boxes_before_oneFrame = track_det_np[ track_det_np[:,frameIdex]<=iiframe ] + for trackId in track_ids: + boxes_before_oneFrame_oneId = boxes_before_oneFrame[boxes_before_oneFrame[:,trackIdex]==trackId] + xcs = boxes_before_oneFrame_oneId[:,8] + ycs = boxes_before_oneFrame_oneId[:,9] + [cv2.line(img_draw, ( int(xcs[i]) , int(ycs[i]) ), + ( int(xcs[i+1]),int(ycs[i+1]) ),(255,0,0), thickness=2) + for i,_ in enumerate(xcs) if i < len(xcs)-1 ] + + ret = vid_writer_AI.write(img_draw) + + #sys.exit(0) + #print('vide writer ret:',ret) + imgarray_list=[];iframe_list=[] + + view_bar(iframe, framecnt,time.time(),prefix=os.path.basename(video)) + + else: + p_result,timeOut = AI_process_forest([imgarray],par0['model'],par0['segmodel'],par0['names'],par0['label_arraylist'],par0['rainbows'],par0['half'],par0['device'],par0['conf_thres'], par0['iou_thres'],par0['allowedList'],font=par0['digitFont'],trtFlag_det=par0['trtFlag_det']) + + + if mode not in [ 'track','obbTrack']: + image_array = p_result[1];num+=1 + ret = vid_writer_AI.write(image_array) + view_bar(num, framecnt,time.time(),prefix=os.path.basename(video)) + ##每隔 fpsample帧处理一次,如果有问题就保存图片 + if (iframe % fpsample == 0) and (len(post_results)>0) : + parImage=save_problem_images(post_results,iframe,par0['names'],streamName=bname,outImaDir=problem_image_dir,imageTxtFile=False) + post_results=[] + + if len(p_result[2] )>0: + post_results.append(p_result) + + vid_writer_AI.release(); + +def det_track_demo(business, videopaths): + ''' + 跟踪参数说明: + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100} + sort_max_age--跟踪链断裂时允许目标消失最大的次数。超过之后,会认为是新的目标。 + sort_min_hits--每隔目标连续出现的次数,超过这个次数才认为是一个目标。 + sort_iou_thresh--检测最小的置信度。 + det_cnt--每隔几次做一个跟踪和检测,默认10。 + windowsize--轨迹平滑长度,一定是奇数,表示每隔几帧做一平滑,默认29。 + patchCnt--每次送入图像的数量,不宜少于100帧。 + ''' + + ''' 以下是基于检测和分割的跟踪模型,分割用来修正检测的结果''' + ####河道巡检的跟踪模型参数 + if opt['business'] == 'river' or opt['business'] == 'river2' : + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/%s/labelnames.json"%(opt['business']), ###检测类别对照表 + 'gpuname':'2080Ti',###显卡名称 + 'max_workers':1, ###并行线程数 + 'half':True, + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出 + + 'seg_nclass':2,###分割模型类别数目,默认2类 + 'segRegionCnt':0,###分割模型结果需要保留的等值线数目 + + '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}} #分割和检测混合处理的函数 + }, + + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + + 'Segweights' : "../weights/%s/AIlib2/%s/stdc_360X640_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/%s/para.json'%( opt['business'] ),###后处理参数文件 + 'txtFontSize':80,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':1.0,'waterLineColor':(0,255,255),'waterLineWidth':3},###显示框、线设置 + #'testImgPath':'images/videos/river',###测试图像的位置 + 'testImgPath':'images/tt',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + + } + + if opt['business'] == 'highWay2': + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/%s/labelnames.json"%( opt['business'] ), ###检测类别对照表 + 'half':True, + 'gpuname':'3090',###显卡名称 + 'max_workers':1, ###并行线程数 + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + #'Detweights':"../AIlib2/weights/conf/highWay2/yolov5.pt", + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,5,6,7,8,9] ],###控制哪些检测类别显示、输出 + 'seg_nclass':3,###分割模型类别数目,默认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':tracfficAccidentMixFunction, + '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 } + } + }, + + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'mode':'highWay3.0', + 'Segweights' : "../weights/%s/AIlib2/%s/stdc_360X640_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/%s/para.json'%(opt['business'] ),###后处理参数文件 + 'txtFontSize':20,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':0.5,'waterLineColor':(0,255,255),'segLineShow':True,'waterLineWidth':2},###显示框、线设置 + #'testImgPath':'images/trafficAccident/8.png',###测试图像的位置 + 'testImgPath':'images/noParking/',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + } + par['segPar']['mixFunction']['pars']['modelSize'] = par['segPar']['modelSize'] + if opt['business'] == 'noParking': + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/%s/labelnames.json"%( opt['business'] ), ###检测类别对照表 + 'half':True, + 'gpuname':'3090',###显卡名称 + 'max_workers':1, ###并行线程数 + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + #'Detweights':"../AIlib2/weights/conf/highWay2/yolov5.pt", + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,5,6,7,8,9] ],###控制哪些检测类别显示、输出 + 'seg_nclass':4,###分割模型类别数目,默认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':mixNoParking_road_postprocess, + 'pars': + #{ 'roundness': 0.3, 'cls': 9, 'laneArea': 10, 'laneAngleCha': 5 ,'RoadArea': 16000, } + + {'RoadArea': 16000, 'roadVehicleAngle': 15,'radius': 50, 'distanceFlag': False, 'vehicleFlag': False} + } + }, + + + + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'mode':'highWay3.0', + 'Segweights' : "../weights/%s/AIlib2/%s/stdc_360X640_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/%s/para.json'%('highWay2' ),###后处理参数文件 + 'txtFontSize':20,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':1.0,'waterLineColor':(0,255,255),'segLineShow':True,'waterLineWidth':2},###显示框、线设置 + 'testImgPath':'images/noParking/',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + } + par['segPar']['mixFunction']['pars']['modelSize'] = par['segPar']['modelSize'] + if opt['business'] == 'drowning': + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/%s/labelnames.json"%( opt['business'] ), ###检测类别对照表 + 'half':True, + 'gpuname':'3090',###显卡名称 + 'max_workers':1, ###并行线程数 + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + #'Detweights':"../AIlib2/weights/conf/highWay2/yolov5.pt", + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,5,6,7,8,9] ],###控制哪些检测类别显示、输出 + 'seg_nclass':2,###分割模型类别数目,默认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':{ } + } + }, + + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'Segweights' : "../weights/%s/AIlib2/%s/stdc_360X640_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/%s/para.json'%('highWay2' ),###后处理参数文件 + 'txtFontSize':20,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':1.0,'waterLineColor':(0,255,255),'segLineShow':True,'waterLineWidth':2},###显示框、线设置 + 'testImgPath':'images/drowning/',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + } + par['segPar']['mixFunction']['pars']['modelSize'] = par['segPar']['modelSize'] + + + ''' 以下是基于检测的跟踪模型,只有检测没有分割 ''' + if opt['business'] == 'forest2': + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/forest2/labelnames.json", ###检测类别对照表 + 'gpuname':opt['gpu'],###显卡名称 + 'max_workers':1, ###并行线程数 + 'half':True, + 'trtFlag_det':True,###检测模型是否采用TRT + 'trtFlag_seg':False,###分割模型是否采用TRT + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + #'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出 + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [] ], + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'seg_nclass':2,###分割模型类别数目,默认2类 + 'segRegionCnt':0,###分割模型结果需要保留的等值线数目 + 'segPar':None,###分割模型预处理参数 + 'Segweights' : None,###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/forest/para.json',###后处理参数文件 + 'txtFontSize':80,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':1.0,'waterLineColor':(0,255,255),'waterLineWidth':3},###显示框、线设置 + 'testImgPath':'../AIdemo2/images/forest2/',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + } + + ###车辆巡检参数 + if opt['business'] == 'vehicle': + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/vehicle/labelnames.json", ###检测类别对照表 + 'gpuname':'2080T',###显卡名称 + 'half':True, + 'max_workers':1, ###并行线程数 + 'trtFlag_det':True,###检测模型是否采用TRT + 'trtFlag_seg':False,###分割模型是否采用TRT + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出 + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'seg_nclass':2,###分割模型类别数目,默认2类 + 'segRegionCnt':0,###分割模型结果需要保留的等值线数目 + 'segPar':None,###分割模型预处理参数 + 'Segweights' : None,###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/vehicle/para.json',###后处理参数文件 + 'txtFontSize':40,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':1.0,'waterLineColor':(0,255,255),'waterLineWidth':3},###显示框、线设置 + 'testImgPath':'images/videos/vehicle/',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + } + ###行人检测模型 + if opt['business'] == 'pedestrian': + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/pedestrian/labelnames.json", ###检测类别对照表 + 'gpuname':'2080T',###显卡名称 + 'half':True, + 'max_workers':1, ###并行线程数 + 'trtFlag_det':True,###检测模型是否采用TRT + 'trtFlag_seg':False,###分割模型是否采用TRT + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出 + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'seg_nclass':2,###分割模型类别数目,默认2类 + 'segRegionCnt':0,###分割模型结果需要保留的等值线数目 + 'segPar':None,###分割模型预处理参数 + 'Segweights' : None,###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/pedestrian/para.json',###后处理参数文件 + 'txtFontSize':40,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':1.0,'waterLineColor':(0,255,255),'waterLineWidth':3},###显示框、线设置 + 'testImgPath':'../AIdemo2/images/pedestrian/',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + } + if opt['business'] == 'smogfire': + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/smogfire/labelnames.json", ###检测类别对照表 + 'gpuname':'2080T',###显卡名称 + 'half':True, + 'max_workers':1, ###并行线程数 + 'trtFlag_det':True,###检测模型是否采用TRT + 'trtFlag_seg':False,###分割模型是否采用TRT + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出 + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'seg_nclass':2,###没有分割模型,此处不用 + 'segRegionCnt':0,###没有分割模型,此处不用 + 'segPar':None,###分割模型预处理参数 + 'Segweights' : None,###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/smogfire/para.json',###后处理参数文件 + 'txtFontSize':40,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':1.0,'waterLineColor':(0,255,255),'waterLineWidth':3},###显示框、线设置 + 'testImgPath':'../AIdemo2/images/smogfire/',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + } + ###钓鱼游泳检测 + if opt['business'] == 'AnglerSwimmer': + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/AnglerSwimmer/labelnames.json", ###检测类别对照表 + 'gpuname':'2080T',###显卡名称 + 'half':True, + 'max_workers':1, ###并行线程数 + 'trtFlag_det':True,###检测模型是否采用TRT + 'trtFlag_seg':False,###分割模型是否采用TRT + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出 + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'seg_nclass':2,###没有分割模型,此处不用 + 'segRegionCnt':0,###没有分割模型,此处不用 + 'segPar':None,###分割模型预处理参数 + 'Segweights' : None,###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/AnglerSwimmer/para.json',###后处理参数文件 + 'txtFontSize':40,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':1.0,'waterLineColor':(0,255,255),'waterLineWidth':3},###显示框、线设置 + 'testImgPath':'../AIdemo2/images/AnglerSwimmer/',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + } + ###航道应急,做落水人员检测, channelEmergency + if opt['business'] == 'channelEmergency': + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/channelEmergency/labelnames.json", ###检测类别对照表 + 'gpuname':'2080T',###显卡名称 + 'half':True, + 'max_workers':1, ###并行线程数 + 'trtFlag_det':True,###检测模型是否采用TRT + 'trtFlag_seg':False,###分割模型是否采用TRT + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + #'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出 + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [] ],###控制哪些检测类别显示、输出 + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'seg_nclass':2,###没有分割模型,此处不用 + 'segRegionCnt':0,###没有分割模型,此处不用 + 'segPar':None,###分割模型预处理参数 + 'Segweights' : None,###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/channelEmergency/para.json',###后处理参数文件 + 'txtFontSize':40,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':1.0,'waterLineColor':(0,255,255),'waterLineWidth':3},###显示框、线设置 + 'testImgPath':'../AIdemo2/images/channelEmergency/',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + } + + ###乡村路违法种植 + if opt['business'] == 'countryRoad': + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/countryRoad/labelnames.json", ###检测类别对照表 + 'gpuname':'2080T',###显卡名称 + 'half':True, + 'max_workers':1, ###并行线程数 + 'trtFlag_det':True,###检测模型是否采用TRT + 'trtFlag_seg':False,###分割模型是否采用TRT + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出 + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'seg_nclass':2,###没有分割模型,此处不用 + 'segRegionCnt':0,###没有分割模型,此处不用 + 'segPar':None,###分割模型预处理参数 + 'Segweights' : None,###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/countryRoad/para.json',###后处理参数文件 + 'txtFontSize':40,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':1.0,'waterLineColor':(0,255,255),'waterLineWidth':3},###显示框、线设置 + 'testImgPath':'../AIdemo2/images/countryRoad/',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + } + + ###城管项目,检测城市垃圾和车辆 + if opt['business'] == 'cityMangement': + par={ + 'device':'0', ###显卡号,如果用TRT模型,只支持0(单显卡) + 'labelnames':"../AIlib2/weights/conf/%s/labelnames.json"%(opt['business']), ###检测类别对照表 + 'gpuname':'2080Ti',###显卡名称 + 'half':True, + 'max_workers':1, ###并行线程数 + 'trtFlag_det':True,###检测模型是否采用TRT + 'trtFlag_seg':False,###分割模型是否采用TRT + 'Detweights':"../weights/%s/AIlib2/%s/yolov5_%s_fp16.engine"%(opt['gpu'], opt['business'] ,opt['gpu'] ),###检测模型路径 + 'detModelpara':[{"id":str(x),"config":{"k1":"v1","k2":"v2"}} for x in [0,1,2,3,4,5,6] ],###控制哪些检测类别显示、输出 + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'seg_nclass':2,###没有分割模型,此处不用 + 'segRegionCnt':0,###没有分割模型,此处不用 + 'segPar':None,###分割模型预处理参数 + 'Segweights' : None,###分割模型权重位置 + 'postFile': '../AIlib2/weights/conf/%s/para.json'%(opt['business']),###后处理参数文件 + 'txtFontSize':40,###文本字符的大小 + 'digitFont': { 'line_thickness':2,'boxLine_thickness':1, 'fontSize':1.0,'waterLineColor':(0,255,255),'waterLineWidth':3},###显示框、线设置 + 'testImgPath':'images/cityMangement',###测试图像的位置 + 'testOutPath':'images/results/',###输出测试图像位置 + } + + + + par['trtFlag_det']=True if par['Detweights'].endswith('.engine') else False + if par['Segweights']: + par['segPar']['trtFlag_seg']=True if par['Segweights'].endswith('.engine') else False + + ##使用森林,道路模型,business 控制['forest','road'] + ##预先设置的参数 + gpuname=par['gpuname']#如果用trt就需要此参数,只能是"3090" "2080Ti" + device_=par['device'] ##选定模型,可选 cpu,'0','1' + + + device = select_device(device_) + half = device.type != 'cpu' # half precision only supported on CUDA + trtFlag_det=par['trtFlag_det'] ###是否采用TRT模型加速 + + ##以下参数目前不可改 + imageW=1080 ####道路模型 + digitFont= par['digitFont'] + + + ####加载检测模型 + if trtFlag_det: + Detweights=par['Detweights'] + logger = trt.Logger(trt.Logger.ERROR) + with open(Detweights, "rb") as f, trt.Runtime(logger) as runtime: + model=runtime.deserialize_cuda_engine(f.read())# 输入trt本地文件,返回ICudaEngine对象 + print('####load TRT model :%s'%(Detweights)) + else: + Detweights=par['Detweights'] + model = attempt_load(Detweights, map_location=device) # load FP32 model + if half: model.half() + + ####加载分割模型 + seg_nclass = par['seg_nclass'] + segPar=par['segPar'] + if par['Segweights']: + if par['segPar']['trtFlag_seg']: + Segweights = par['Segweights'] + logger = trt.Logger(trt.Logger.ERROR) + with open(Segweights, "rb") as f, trt.Runtime(logger) as runtime: + segmodel=runtime.deserialize_cuda_engine(f.read())# 输入trt本地文件,返回ICudaEngine对象 + print('############locad seg model trt success: ',Segweights) + else: + Segweights = par['Segweights'] + segmodel = SegModel(nclass=seg_nclass,weights=Segweights,device=device) + print('############locad seg model pth success:',Segweights) + else: + segmodel=None + + + trackPar=par['trackPar'] + sort_tracker = Sort(max_age=trackPar['sort_max_age'], + min_hits=trackPar['sort_min_hits'], + iou_threshold=trackPar['sort_iou_thresh']) + + + labelnames = par['labelnames'] + postFile= par['postFile'] + print( Detweights,labelnames ) + conf_thres,iou_thres,classes,rainbows=get_postProcess_para(postFile) + + detPostPar = get_postProcess_para_dic(postFile) + conf_thres,iou_thres,classes,rainbows = detPostPar["conf_thres"],detPostPar["iou_thres"],detPostPar["classes"],detPostPar["rainbows"] + if 'ovlap_thres_crossCategory' in detPostPar.keys(): iou2nd=detPostPar['ovlap_thres_crossCategory'] + else:iou2nd = None + + + ####模型选择参数用如下: + mode_paras=par['detModelpara'] + + allowedList,allowedList_string=get_needed_objectsIndex(mode_paras) + #slopeIndex = par['slopeIndex'] + ##只加载检测模型,准备好显示字符 + + names=get_labelnames(labelnames) + #imageW=4915;###默认是1920,在森林巡检的高清图像中是4920 + outfontsize=int(imageW/1920*40);### + label_arraylist = get_label_arrays(names,rainbows,outfontsize=par['txtFontSize'],fontpath="../AIlib2/conf/platech.ttf") + + + + + ##图像测试和视频 + outpth = par['testOutPath'] + impth = par['testImgPath'] + imgpaths=[]###获取文件里所有的图像 + videopaths=videopaths###获取文件里所有的视频 + img_postfixs = ['.jpg','.JPG','.PNG','.png']; + vides_postfixs= ['.MP4','.mp4','.avi'] + if os.path.isdir(impth): + for postfix in img_postfixs: + imgpaths.extend(glob.glob('%s/*%s'%(impth,postfix )) ) + for postfix in ['.MP4','.mp4','.avi']: + videopaths.extend(glob.glob('%s/*%s'%(impth,postfix )) ) + else: + postfix = os.path.splitext(impth)[-1] + if postfix in img_postfixs: imgpaths=[ impth ] + if postfix in vides_postfixs: videopaths = [impth ] + + + + + imgpaths.sort() + + + modelPar={ 'det_Model': model,'seg_Model':segmodel } + + processPar={'half':par['half'],'device':device,'conf_thres':conf_thres,'iou_thres':iou_thres,'trtFlag_det':trtFlag_det,'iou2nd':iou2nd} + drawPar={'names':names,'label_arraylist':label_arraylist,'rainbows':rainbows,'font': par['digitFont'],'allowedList':allowedList} + + for i in range(len(imgpaths)): + #for i in range(2): + #imgpath = os.path.join(impth, folders[i]) + imgpath = imgpaths[i] + bname = os.path.basename(imgpath ) + im0s=[cv2.imread(imgpath)] + time00 = time.time() + retResults,timeOut = AI_det_track_batch(im0s, [i] ,modelPar,processPar,sort_tracker ,trackPar,segPar) + #print('###line627:',retResults[2]) + #retResults,timeInfos = AI_det_track_batch(imgarray_list, iframe_list ,par0['modelPar'],par0['processPar'],par0['sort_tracker'] ,par0['trackPar'],segPar=par0['segPar']) + if len(retResults[1])>0: + retResults[0][0] = drawBoxTraceSimplied(retResults[1],i, retResults[0][0],rainbows=rainbows,boxFlag=True,traceFlag=False,names=drawPar['names']) + time11 = time.time() + image_array = retResults[0][0] + ''' + + 返回值retResults[2] --list,其中每一个元素为一个list,表示每一帧的检测结果,每一个结果是由多个list构成,每个list表示一个框,格式为[ cls , x0 ,y0 ,x1 ,y1 ,conf,ifrmae,trackId ] + --etc. retResults[2][j][k]表示第j帧的第k个框。 + ''' + cv2.imwrite( os.path.join( outpth,bname ) ,image_array ) + + print('----image:%s, process:%s ( %s ),save:%s'%(bname,(time11-time00) * 1000, timeOut,(time.time() - time11) * 1000) ) + + ##process video + + print('##begin to process videos, total %d videos'%( len(videopaths))) + for i,video in enumerate(videopaths): + print('process video%d :%s '%(i,video)) + par0={'modelPar':modelPar,'processPar':processPar,'drawPar':drawPar,'outpth':par['testOutPath'], 'sort_tracker':sort_tracker,'trackPar':trackPar,'segPar':segPar} + process_video(video,par0,mode='track') + + + +def OCR_demo2(opt): + from ocrUtils2 import crnn_model + from ocrUtils2.ocrUtils import get_cfg,recognition_ocr,strLabelConverter + + if opt['business'] == 'ocr2': + par={ + 'image_dir':'images/ocr_en', + 'outtxt':'images/results', + 'weights':'../AIlib2/weights/conf/ocr2/crnn_448X32.pth', + + #'weights':'../weights/2080Ti/AIlib2/ocr2/crnn_2080Ti_fp16_448X32.engine', + 'device':'cuda:0', + 'cfg':'../AIlib2/weights/conf/ocr2/360CC_config.yaml', + + 'char_file':'../AIlib2/weights/conf/ocr2/chars.txt', + 'imgH':32, + 'imgW':448, + 'workers':1 + + + } + image_dir=par['image_dir'] + outtxt=par['outtxt'] + workers=par['workers'] + weights= par['weights'] + device=par['device'] + + char_file=par['char_file'] + imgH=par['imgH'] + imgW=par['imgW'] + cfg = par['cfg'] + + + + config = get_cfg(cfg, char_file) + + + par['contextFlag']=False + device = torch.device('cuda:0') if torch.cuda.is_available() else torch.device('cpu') + if weights.endswith('.pth'): + model = crnn_model.get_crnn(config,weights=weights).to(device) + par['model_mode']='pth' + else: + logger = trt.Logger(trt.Logger.ERROR) + with open(weights, "rb") as f, trt.Runtime(logger) as runtime: + model = runtime.deserialize_cuda_engine(f.read())# 输入trt本地文件,返回ICudaEngine对象 + print('#####load TRT file:',weights,'success #####') + context = model.create_execution_context() + par['model_mode']='trt';par['contextFlag']=context + + converter = strLabelConverter(config.DATASET.ALPHABETS) + + img_urls=glob.glob('%s/*.jpg'%( image_dir )) + img_urls.extend( glob.glob('%s/*.png'%( image_dir )) ) + cnt=len(img_urls) + print('%s has %d images'%(image_dir ,len(img_urls) ) ) + # 准备数据 + parList=[] + for i in range(cnt): + img_patch=cv2.imread( img_urls[i] , cv2.IMREAD_GRAYSCALE) + started = time.time() + img = cv2.imread(img_urls[i]) + sim_pred = recognition_ocr(config, img, model, converter, device,par=par) + finished = time.time() + print('{0}: elapsed time: {1} prd:{2} '.format( os.path.basename( img_urls[i] ), finished - started, sim_pred )) + + + + + +def OBB_track_demo(opt): + ###倾斜框(OBB)的ship目标检测 + ''' + par={ + 'model_size':(608,608), #width,height + 'K':100, #Maximum of objects' + 'conf_thresh':0.18,##Confidence threshold, 0.1 for general evaluation + 'device':"cuda:0", + + 'down_ratio':4,'num_classes':15, + #'weights':'../AIlib2/weights/conf/ship2/obb_608X608.engine', + 'weights':'../weights/%s/AIlib2/%s/obb_608X608_%s_fp16.engine'%(opt['gpu'],opt['business'],opt['gpu']), + 'dataset':'dota', + 'test_dir': '/mnt/thsw2/DSP2/videos/obbShips', + 'outpth': 'images/results', + 'half': False, + 'mean':(0.5, 0.5, 0.5), + 'std':(1, 1, 1), + 'model_size':(608,608),##width,height + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'heads': {'hm': None,'wh': 10,'reg': 2,'cls_theta': 1}, + 'decoder':None, + 'test_flag':True, + 'postFile': '../AIlib2/weights/conf/%s/para.json'%(opt['business'] ),###后处理参数文件 + 'drawBox':True,#####是否画框 + 'digitWordFont': { 'line_thickness':2,'boxLine_thickness':1,'wordSize':40, 'fontSize':1.0,'label_location':'leftTop'}, + 'labelnames':"../AIlib2/weights/conf/%s/labelnames.json"%(opt['business'] ), ###检测类别对照表 + } + ''' + par={ + + 'obbModelPar':{ + '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,'decoder':None, + 'weights':'../weights/%s/AIlib2/%s/obb_608X608_%s_fp16.engine'%(opt['gpu'],opt['business'],opt['gpu']), + + }, + 'outpth': 'images/results', + 'trackPar':{'sort_max_age':2,'sort_min_hits':3,'sort_iou_thresh':0.2,'det_cnt':10,'windowsize':29,'patchCnt':100}, + 'device':"cuda:0", + + #'test_dir': '/mnt/thsw2/DSP2/videos/obbShips/DJI_20230208110806_0001_W_6M.MP4', + 'test_dir':'/mnt/thsw2/DSP2/videos/obbShips/freighter2.mp4', + + 'test_flag':True, + 'postFile': '../AIlib2/weights/conf/%s/para.json'%(opt['business'] ),###后处理参数文件 + 'drawBox':True,#####是否画框 + 'drawPar': { 'digitWordFont' :{'line_thickness':2,'boxLine_thickness':1,'wordSize':40, 'fontSize':1.0,'label_location':'leftTop'}} , + 'labelnames':"../AIlib2/weights/conf/%s/labelnames.json"%(opt['business'] ), ###检测类别对照表 + } + #par['model_size'],par['mean'],par['std'],par['half'],par['saveType'],par['heads'],par['labelnames'],par['decoder'],par['down_ratio'],par['drawBox'] + #par['rainbows'],par['label_array'],par['digitWordFont'] + + obbModelPar = par['obbModelPar'] + ####加载模型 + model,decoder2=load_model_decoder_OBB(obbModelPar) + obbModelPar['decoder']=decoder2 + + names=get_labelnames(par['labelnames']);obbModelPar['labelnames']=names + + _,_,_,rainbows=get_postProcess_para(par['postFile']);par['drawPar']['rainbows']=rainbows + + + label_arraylist = get_label_arrays(names,rainbows,outfontsize=par['drawPar']['digitWordFont']['wordSize'],fontpath="../AIlib2/conf/platech.ttf") + #par['label_array']=label_arraylist + + trackPar=par['trackPar'] + sort_tracker = OBB_Sort(max_age=trackPar['sort_max_age'], + min_hits=trackPar['sort_min_hits'], + iou_threshold=trackPar['sort_iou_thresh']) + + + ##图像测试和视频 + impth = par['test_dir'] + img_urls=[]###获取文件里所有的图像 + video_urls=[]###获取文件里所有的视频 + img_postfixs = ['.jpg','.JPG','.PNG','.png']; + vides_postfixs= ['.MP4','.mp4','.avi'] + if os.path.isdir(impth): + for postfix in img_postfixs: + img_urls.extend(glob.glob('%s/*%s'%(impth,postfix )) ) + for postfix in ['.MP4','.mp4','.avi']: + video_urls.extend(glob.glob('%s/*%s'%(impth,postfix )) ) + else: + postfix = os.path.splitext(impth)[-1] + if postfix in img_postfixs: img_urls=[ impth ] + if postfix in vides_postfixs: video_urls = [impth ] + + parIn = {'obbModelPar':obbModelPar,'modelPar':{'obbmodel': model},'sort_tracker':sort_tracker,'outpth':par['outpth'],'trackPar':trackPar,'drawPar':par['drawPar']} + par['drawPar']['label_array']=label_arraylist + for img_url in img_urls: + #print(img_url) + ori_image=cv2.imread(img_url) + + #ori_image_list,infos = OBB_infer(model,ori_image,obbModelPar) + + ori_image_list,infos = OBB_tracker_batch([ori_image],[0],parIn['modelPar'],parIn['obbModelPar'],None,parIn['trackPar'],None) + + ori_image_list[1] = draw_obb(ori_image_list[2] ,ori_image_list[1],par['drawPar']) + + imgName = os.path.basename(img_url) + saveFile = os.path.join(par['outpth'], imgName) + ret=cv2.imwrite(saveFile, ori_image_list[1]) + if not ret: + print(saveFile, ' not created ') + print( os.path.basename(img_url),':',infos,ori_image_list[2]) + + ###处理视频 + + for video_url in video_urls: + process_video(video_url, parIn ,mode='obbTrack') + +if __name__=="__main__": + + #jkm_demo() + #businessAll=['river', 'river2','highWay2','noParking','drowning','forest2','vehicle','pedestrian','smogfire' , 'AnglerSwimmer','channelEmergency', 'countryRoad','cityMangement','ship2'] + businessAll = ['river2'] + videopaths = ['/home/th/tuo_heng/dev/DJI_20211229100908_0002_S.mp4'] + for busi in businessAll: + print('-'*40,'beg to test:',busi,'-'*40) + opt={'gpu':'2080Ti','business':busi} + if busi in ['ship2']: + OBB_track_demo(opt) + else: + #if opt['business'] in ['river','highWay2','noParking','drowning','']: + det_track_demo(opt, videopaths) \ No newline at end of file diff --git a/vodsdk/test/ffmpeg11/__init__.py b/vodsdk/test/ffmpeg11/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/ffmpeg11/aa.py b/vodsdk/test/ffmpeg11/aa.py new file mode 100644 index 0000000..8662965 --- /dev/null +++ b/vodsdk/test/ffmpeg11/aa.py @@ -0,0 +1,175 @@ +import json +import time +import subprocess as sp +import ffmpeg +import cv2 +import sys + +import numpy as np + + + +""" +获取视频基本信息 +""" + + +def get_video_info(in_file): + try: + probe = ffmpeg.probe('https://vod.play.t-aaron.com/customerTrans/edc96ea2115a0723a003730956208134/55547af9-184f0827dae-0004-f90c-f2c-7ec68.mp4') + # format = probe['format'] + # size = int(format['size'])/1024/1024 + video_stream = next((stream for stream in probe['streams'] if stream['codec_type'] == 'video'), None) + if video_stream is None: + print('No video stream found', file=sys.stderr) + return + width = int(video_stream['width']) + height = int(video_stream['height']) + num_frames = int(video_stream['nb_frames']) + up, down = str(video_stream['r_frame_rate']).split('/') + fps = eval(up) / eval(down) + print("fbs:", fps) + # duration = float(video_stream['duration']) + bit_rate = int(video_stream['bit_rate'])/1000 + print('width: {}'.format(width)) + print('height: {}'.format(height)) + # print('num_frames: {}'.format(num_frames)) + print('bit_rate: {}k'.format(bit_rate)) + # print('fps: {}'.format(fps)) + # print('size: {}MB'.format(size)) + # print('duration: {}'.format(duration)) + return video_stream + + + + except Exception as err: + if isinstance(err, ffmpeg._run.Error): + print(err.stderr.decode(encoding = 'utf-8')) + raise err + + +if __name__ == '__main__': + file_path = r'D:\shipin\777.mp4' + video_info = get_video_info(file_path) + print(json.dumps(video_info)) + # total_frames = int(video_info['nb_frames']) + # print('总帧数:' + str(total_frames)) + # random_frame = random.randint(1, total_frames) + # print('随机帧:' + str(random_frame)) + # out = read_frame_as_jpeg(file_path, i) + # image_array = numpy.asarray(bytearray(out), dtype="uint8") + # image = cv2.imdecode(image_array, cv2.IMREAD_COLOR) + # kwargs={'fflags': 'nobuffer', 'flags': 'low_delay'} + width = int(video_info['width']) + height = int(video_info['height']) + width_2_1 = int(width/2) + height_2_1 = int(height/2) + print("长:", width, "宽:", height) + text = '' + command = ['ffmpeg', + # '-hwaccel', 'cuvid', + '-c:v', 'h264_cuvid', + # '-hwaccel_output_format', 'cuda', + # '-resize', '%sx%s' % (width_2_1, height_2_1), + '-i', file_path, + # '-c:v', 'hevc_nvenc', + # '-pix_fmt', 'yuv420p', + '-f', 'rawvideo', + '-pix_fmt', 'bgr24', + '-an', + '-'] + p = sp.Popen(command, stdout=sp.PIPE) + # for line in p.stderr: + # # print(line.strip()) + # for line in p.stdout: + # print(text) + + command1 = ['ffmpeg', + '-report', + # '-loglevel', 'debug', + '-y', # 不经过确认,输出时直接覆盖同名文件。 + '-f', 'rawvideo', + '-vcodec', 'rawvideo', + '-pix_fmt', 'bgr24', + # '-hwaccel', 'cuvid', + # '-c:v', 'h264_cuvid', + # '-hwaccel_output_format', 'cuda', + # '-s', "{}x{}".format(self.width * 2, self.height), + '-s', "{}x{}".format(width, height), + '-r', str(25), + '-i', '-', # 指定输入文件 + '-g', str(5), + # '-maxrate', '15000k', + # '-profile:v', 'high', + # '-b:v', '4000k', + # '-crf', '18', + '-rc:v', 'vbr', + '-cq:v', '30', + '-qmin', '30', + '-qmax', '30', + '-bufsize', '1', + '-c:v', 'h264_nvenc', # + + # '-c:v', 'libx264', # 指定视频编码器 + # '-tune', 'zerolatency', # 加速编码速度 + # '-sc_threshold', '0', + '-pix_fmt', 'yuv420p', + "-an", + # '-flvflags', 'no_duration_filesize', + '-preset', 'fast', + # '-f', 'flv',ags', 'no_duration_filesize', + # '-preset', 'fast', # 指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, + # superfast, veryfast, faster, fast, medium, slow, slower, veryslow。 + '-f', 'flv', + 'rtmp://live.push.t-aaron.com/live/THSAr'] + + # # 管道配置 + p1 = sp.Popen(command1, stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE, ) + start1 = time.time() + num = 0 + while True: + + # num += 1 + # # if num ==100: + # # print(time.time()-start1) + # # break + # start = time.time() + in_bytes = p.stdout.read(int(width * height*3)) + # # print(type(in_bytes)) + img = (np.frombuffer(in_bytes, np.uint8)).reshape((height, width, 3)) + # # result = cv2.cvtColor(img, cv2.COLOR_YUV2BGR_NV12) + # # result = cv2.resize(result, (int(width / 2), int(height / 2)), interpolation=cv2.INTER_LINEAR) + # # result = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) + + for line in iter(p1.stdout.readline, b''): + print(line) + # if in_bytes: + # p1.stdin.write(img.tostring()) + # print(p1.stderr.read().decode('utf-8')) + # for line in iter(p1.std + # + # + # out.readline, ''): + # line = line.decode('utf-8') + # print(line) + # print(num) + # time.sleep(0.001) + + # p1.stdin.write(in_frame.tostring()) + # frame + # .astype(np.uint8) + # .tobytes() + # frame = cv2.resize(in_frame, (1280, 720)) # 改变图片尺寸 + # frame = cv2.cvtColor(in_frame, cv2.COLOR_RGB2BGR) # 转成BGR + # i += 1 + # print(round(time.time()-start, 5)) + # + # ai_video_file.write(in_frame) + # if time.time() - start1 > 60: + # ai_video_file.release() + # p.stdout.close() + # p.wait() + # break + # cv2.imshow('frame', frame) + # time.sleep(1111) + # p.kill() \ No newline at end of file diff --git a/vodsdk/test/ffmpeg11/cv2test.py b/vodsdk/test/ffmpeg11/cv2test.py new file mode 100644 index 0000000..b52157f --- /dev/null +++ b/vodsdk/test/ffmpeg11/cv2test.py @@ -0,0 +1,107 @@ +# import cv2,os +# import time +# import subprocess as sp +# # 图片合并 +# # def readImage(): +# # p1 = cv2.imread("C:/Users/chenyukun/Pictures/Camera Roll/a.jpg") +# # p2 = cv2.imread("C:/Users/chenyukun/Pictures/Camera Roll/b.jpg") +# # ret = cv2.add(p1, p2) +# # cv2.imwrite(r"C:\Users\chenyukun\Pictures\Camera Roll\aa.jpg", ret) +# # +# # readImage() +# # https://opencv.apachecn.org/#/docs/4.0.0/2.1-tutorial_py_image_display +# if __name__ == "__main__": +# # print(cv2.__version__) +# # # 读取图像 +# # p1 = cv2.imread("C:/Users/chenyukun/Pictures/Camera Roll/a.jpg", 0) # 以灰度模式加载图像 +# # p2 = cv2.imread("C:/Users/chenyukun/Pictures/Camera Roll/b.jpg", 1) # **cv.IMREAD_COLOR**:加载彩色图像,任何图像的透明度都会被忽略,它是默认标志 +# # p3 = cv2.imread("C:/Users/chenyukun/Pictures/Camera Roll/b.jpg", -1) # 加载图像,包括 alpha 通道 +# # p4 = cv2.imread("C:/Users/chenyukun/Pictures/Camera Roll/a.jpg") +# # p5 = cv2.imread("C:/Users/chenyukun/Pictures/Camera Roll/c.jpg") +# # print(type(p5)) +# # ret = cv2.add(p4, p5) +# # # 显示图像 +# # cv2.imshow('frame', p1) +# # cv2.imshow('frame1', p2) +# # cv2.imshow('frame2', p3) +# # # 对显示窗口做调整,WINDOW_AUTOSIZE不可调整,WINDOW_NORMAL可调整窗口大小 +# # cv2.namedWindow('frame3', cv2.WINDOW_AUTOSIZE) +# # cv2.imshow('frame3', ret) +# # # 等待时间 按下任务键 +# # k = cv2.waitKey(1) & 0xFF +# # if k == 27: #ESC退出 +# # cv2.destroyAllWindows() +# # elif k == ord('s'): # 's' 保存退出 +# # # 保存图像 +# # cv2.imwrite("C:/Users/chenyukun/Pictures/Camera Roll/d.jpg", ret) +# # cv2.destroyAllWindows() +# +# +# +# # 视频入门 +# try: +# cap = cv2.VideoCapture("rtmp://live.play.t-aaron.com/live/THSAf_hd") # 0:表示连接一台摄像机 +# print(cap.isOpened()) +# print(cap) +# except Exception as e: +# print(e) +# raise e +# print("aaaa") +# # 有时,cap 可能没有初始化 capture。在这种情况下,此代码显示错误。你可以通过该方法 cap.isOpened() 检查它是否初始化。 +# # 如果它是 True,那么是好的,否则用 cap.open() 打开在使用。 +# fps = int(cap.get(cv2.CAP_PROP_FPS)) +# width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) +# height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) +# print(fps,width,height) +# # # 设置宽 +# # print(cap.set(cv2.CAP_PROP_FRAME_WIDTH, 320)) +# # # 设置高 +# # print(cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 240)) +# +# # 声明编码器和创建 VideoWrite 对象 +# fourcc = cv2.VideoWriter_fourcc(*'mp4v') +# out = cv2.VideoWriter('/home/DATA/dsp/ai/video/eee.mp4',fourcc, fps, (width, height)) +# command=['/usr/bin/ffmpeg', +# '-y', # 覆盖输出文件 +# '-f', 'rawvideo', # 强迫采用格式fmt +# '-vcodec','rawvideo', +# '-pix_fmt', 'bgr24', +# '-s', "{}x{}".format(640, 480),# 图片分辨率 +# '-r', str(25.0),# 视频帧率 +# '-i', '-', +# '-c:v', 'libx264', +# '-pix_fmt', 'yuv420p', +# '-preset', 'ultrafast', +# '-f', 'flv', +# "rtmp://live.push.t-aaron.com/live/THSAb"] +# # p = sp.Popen(command, stdin=sp.PIPE) +# start = time.time() +# while True: +# +# try: +# if not cap.isOpened(): +# cap = cv2.VideoCapture("rtmp://live.play.t-aaron.com/live/THSAf_hd") +# continue +# # 一帧一帧捕捉 +# ret, frame = cap.read() # 返回一个 bool 值(True/False)。如果加载成功,它会返回True +# if not ret: +# cap = cv2.VideoCapture("rtmp://live.play.t-aaron.com/live/THSAf_hd") +# continue +# # print(ret) #True +# # # 我们对帧的操作在这里 +# # gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) +# end = time.time() +# print("bbbbbbbbb") +# # p.stdin.write(frame.tostring()) +# # print("aaaaa") +# out.write(frame) +# except Exception as e: +# raise e +# # # 显示返回的每帧 +# # cv2.imshow('frame',gray) +# # if cv2.waitKey(1) & 0xFF == ord('q'): +# # break +# # 当所有事完成,释放 VideoCapture 对象 +# cap.release() +# out.release() +# cv2.destroyAllWindows() diff --git a/vodsdk/test/ffmpeg11/cv2test1.py b/vodsdk/test/ffmpeg11/cv2test1.py new file mode 100644 index 0000000..99fc97b --- /dev/null +++ b/vodsdk/test/ffmpeg11/cv2test1.py @@ -0,0 +1,103 @@ +import time +import cv2 +import subprocess as sp +# 推流 +import ffmpeg +import numpy as np + +if __name__== "__main__": + + + # with open(str(cv2.__file__),"r") as f: + # print (f.read()) + + # cap = cv2.VideoCapture("rtmp://live.play.t-aaron.com/live/THSAs") + # # Get video information + # fps = int(cap.get(cv2.CAP_PROP_FPS)) + # print(fps) + # width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + # print(width) + # height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + # print(height) + # fourcc = int(cap.get(cv2.CAP_PROP_FOURCC)) + # print(fourcc) + # # print(cv2.getBuildInformation()) + # # cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920) + # # cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080) + # # cap.set(cv2.CAP_PROP_FPS, 60) + # # cap.setExceptionMode(True) + # print(cap.getExceptionMode()) + + + # ffmpeg command + # command = ['ffmpeg', + # '-y', # 不经过确认,输出时直接覆盖同名文件。 + # '-f', 'rawvideo', + # '-vcodec','rawvideo', + # '-pix_fmt', 'bgr24', + # '-s', "{}x{}".format(1920, 1080), + # # '-s', "{}x{}".format(1280, 720), + # '-i', '-', # 指定输入文件 + # '-c:v', 'libx264', # 指定视频编码器 + # '-pix_fmt', 'yuv420p', + # '-g', '5', + # "-an", + # '-b:v', '3000k', + # '-preset', 'ultrafast', # 指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, + # # superfast, veryfast, faster, fast, medium, slow, slower, veryslow。 + # '-f', 'flv', + # "rtmp://live.push.t-aaron.com/live/THSAk"] + kwargs = {'format': 'rawvideo', + 'vcodec': 'rawvideo', + 'pix_fmt': 'bgr24', + 's': '{}x{}'.format(int(1920), int(1080))} + out = { + 'g': str(25), + 'b:v': '6000k', + # '-bufsize': '3000k', + 'tune': 'zerolatency', # 加速编码速度 + 'c:v': 'libx264', # 指定视频编码器 + 'sc_threshold': '0', + 'pix_fmt': 'yuv420p', + 'flvflags': 'no_duration_filesize', + 'preset': 'ultrafast', # 指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, + # superfast, veryfast, faster, fast, medium, slow, slower, veryslow。 + 'format': 'flv'} + # 管道配置 + process2 = ( + ffmpeg + .input('pipe:', **kwargs) + .output('rtmp://live.push.t-aaron.com/live/THSAk', **out) + .global_args('-y', '-an') + .overwrite_output() + .run_async(pipe_stdin=True) + ) + # 管道配置 + # p = sp.Popen(command, stdin=sp.PIPE, shell=False) + + process = ( + ffmpeg + .input('rtmp://221.226.114.142:19350/rlive/stream_4?sign=PZIGmXvw') + .output('pipe:', format='rawvideo', pix_fmt='bgr24') + .overwrite_output() + .global_args('-an') + .run_async(pipe_stdout=True) + ) + # while(cap.isOpened()): + while True: + start =time.time() + # ret, frame = cap.read() + # print(cap.grab()) + in_bytes = process.stdout.read(1920 * 1080 * 3) + # print("aaaaaaaaaaaaaaa", time.time()-start) + # print("aaaaaaaaaaaaaa", time.time()-start) + # start =time.time() + # a,b = cap.retrieve() + if not in_bytes: + print("Opening camera is failed") + break + frame = (np.frombuffer(in_bytes, np.uint8).reshape([1080, 1920, 3])) + print("ccccccccccccccc", time.time()-start) + # process2.stdin.write(frame.tostring()) + # print("bbbbbbbbbbbbbb", time.time()-start) + diff --git a/vodsdk/test/ffmpeg11/ffmpeg11.py b/vodsdk/test/ffmpeg11/ffmpeg11.py new file mode 100644 index 0000000..9f2b5c7 --- /dev/null +++ b/vodsdk/test/ffmpeg11/ffmpeg11.py @@ -0,0 +1,144 @@ +import json +import time +import subprocess as sp +import ffmpeg +import cv2 +import sys +import random + +import numpy as np + + +def read_frame_as_jpeg(in_file, frame_num): + """ + 指定帧数读取任意帧 + """ + out, err = ( + ffmpeg.input(in_file) + .filter('select', 'gte(n,{})'.format(frame_num)) + .output('pipe:', vframes=1, format='image2', vcodec='mjpeg') + .run(capture_stdout=True) + ) + return out + + +""" +获取视频基本信息 +""" + + +def get_video_info(in_file): + try: + probe = ffmpeg.probe(in_file) + # format = probe['format'] + # size = int(format['size'])/1024/1024 + video_stream = next((stream for stream in probe['streams'] if stream['codec_type'] == 'video'), None) + if video_stream is None: + print('No video stream found', file=sys.stderr) + return + width = int(video_stream['width']) + height = int(video_stream['height']) + # num_frames = int(video_stream['nb_frames']) + # up, down = str(video_stream['r_frame_rate']).split('/') + # fps = eval(up) / eval(down) + # duration = float(video_stream['duration']) + bit_rate = int(video_stream['bit_rate'])/1000 + print('width: {}'.format(width)) + print('height: {}'.format(height)) + # print('num_frames: {}'.format(num_frames)) + print('bit_rate: {}k'.format(bit_rate)) + # print('fps: {}'.format(fps)) + # print('size: {}MB'.format(size)) + # print('duration: {}'.format(duration)) + return video_stream + + + + except Exception as err: + print("aaaaaaaaaaaaaaaaaaaa", err) + + +if __name__ == '__main__': + #file_path = 'https://vod.play.t-aaron.com/0bc905ef5651439da2bfba8427fe467e/a76a7ebb6e3b44ef9c0c7820c7e9c574-f2d7ee90cba11aa91971d58e06d295d2-4k.mp4' + file_path = 'https://vod.play.t-aaron.com/customerTrans/edc96ea2115a0723a003730956208134/55547af9-184f0827dae-0004-f90c-f2c-7ec68.mp4' + #file_path = 'https://vod.play.t-aaron.com/customerTrans/edc96ea2115a0723a003730956208134/40b416f7-183b57f6be0-0004-f90c-f2c-7ec68.mp4' + #file_path = 'https://vod.play.t-aaron.com/3301fc8e166f45be88f2214e7a8f4a9d/e29535365b54434d9ed2e8c3b0a175da-fba35541b31a1049ca05b145a283c33a-hd.mp4' + video_info = get_video_info(file_path) + print(json.dumps(video_info)) + # total_frames = int(video_info['nb_frames']) + # print('总帧数:' + str(total_frames)) + # random_frame = random.randint(1, total_frames) + # print('随机帧:' + str(random_frame)) +# out = read_frame_as_jpeg(file_path, i) +# image_array = numpy.asarray(bytearray(out), dtype="uint8") +# image = cv2.imdecode(image_array, cv2.IMREAD_COLOR) +# kwargs={'fflags': 'nobuffer', 'flags': 'low_delay'} + kwargs={ + # "hwaccel": "nvdec", + # "vcodec": "h264_cuvid", + # "c:v": "h264_cuvid" + } + output_args = { + # "vcodec": "hevc_nvenc", + # "c:v": "hevc_nvenc", + # "preset": "fast", + } + # i = 1 + # process1 = ( + # ffmpeg + # .input(file_path, **kwargs) + # .output('pipe:', format='rawvideo', pix_fmt='rgb24', **output_args) + # # .global_args("-an") + # .overwrite_output() + # .run_async(pipe_stdout=True, pipe_stderr=True) + # ) + width = int(video_info['width']) + height = int(video_info['height']) + command = ['ffmpeg', + '-hwaccel cuda', + '-c:v', 'h264_cuvid', + '-resize', '1920x1080', + # '-hwaccel_output_format', 'bgr24', + '-i', file_path, + # '-vf', "hwdownload,format=bgr24", + # "-vcodec", "h264_nvenc", # hevc_nvenc h264_nvenc + '-f', 'rawvideo', + # '-g', '5', + # '-pix_fmt', 'bgr24', + # '-hwaccel_output_format', 'bgr24', + # '-an', + '-'] + p = sp.Popen(command, stdout=sp.PIPE) + # ai_video_file = cv2.VideoWriter(r"C:\Users\chenyukun\Desktop\shipin\aa.mp4", cv2.VideoWriter_fourcc(*'mp4v'), 30, + # (width, height)) + start1 = time.time() + while True: + start = time.time() + # in_bytes = p.stdout.read() + in_bytes = p.stdout.read(int(width * height * 3 // 8)) + # in_bytes = p.stdout.read(int(width * height * 3/4)) + if not in_bytes: + print(in_bytes) + # ai_video_file.release() + p.stdout.close() + p.wait() + break + # 转成ndarray + img = (np.frombuffer(in_bytes, np.uint8)).reshape((int(height/2 * 3 // 2), int(width/2))) + bgr_img = cv2.cvtColor(img, cv2.COLOR_YUV2BGR_NV12) + # in_frame = (np.frombuffer(in_bytes, np.uint8).reshape([int(height/2), int(width/2), 3])) + # print("拉流时间:", time.time() - start) + # frame = cv2.resize(in_frame, (1280, 720)) # 改变图片尺寸 + # i += 1 + # print(round(time.time()-start, 5)) + # + # ai_video_file.write(in_frame) + # if time.time() - start1 > 60: + # ai_video_file.release() + # p.stdout.close() + # p.wait() + # break + # cv2.imshow('frame', bgr_img) + # cv2.waitKey(1) + # time.sleep(1111) + p.kill() diff --git a/vodsdk/test/ffmpeg11/ffmpeg12.py b/vodsdk/test/ffmpeg11/ffmpeg12.py new file mode 100644 index 0000000..f9aa087 --- /dev/null +++ b/vodsdk/test/ffmpeg11/ffmpeg12.py @@ -0,0 +1,101 @@ +import json +import time +import subprocess as sp +import ffmpeg +import cv2 +import sys +import random + +import numpy as np + +""" +获取视频基本信息 +""" + + +def get_video_info(in_file): + try: + probe = ffmpeg.probe(in_file) + # format = probe['format'] + # size = int(format['size'])/1024/1024 + video_stream = next((stream for stream in probe['streams'] if stream['codec_type'] == 'video'), None) + if video_stream is None: + print('No video stream found', file=sys.stderr) + return + width = int(video_stream['width']) + height = int(video_stream['height']) + # num_frames = int(video_stream['nb_frames']) + up, down = str(video_stream['r_frame_rate']).split('/') + video_stream['fps']=eval(up) / eval(down) + # duration = float(video_stream['duration']) + # bit_rate = int(video_stream['bit_rate'])/1000 + print('width: {}'.format(width)) + print('height: {}'.format(height)) + # print('num_frames: {}'.format(num_frames)) + # print('bit_rate: {}k'.format(bit_rate)) + # print('fps: {}'.format(fps)) + # print('size: {}MB'.format(size)) + # print('duration: {}'.format(duration)) + return video_stream + + + + except Exception as err: + print("aaaaaaaaaaaaaaaaaaaa", err) + return None + + +if __name__ == '__main__': + file_path = "rtmp://live.play.t-aaron.com/live/THSAa" + while True: + video_info = get_video_info(file_path) + print(json.dumps(video_info)) + if video_info is None: + time.sleep(2) + continue + else: + break + command = ['ffmpeg', + # '-re', + '-y', + '-c:v', 'h264_cuvid', + '-i', file_path, + '-pix_fmt', 'bgr24', + '-f', 'rawvideo', + '-an', + '-'] + width = int(video_info['width']) + height = int(video_info['height']) + fps = int(video_info['fps']) + p = sp.Popen(command, stdout=sp.PIPE) + ai_video_file = cv2.VideoWriter(r"C:\Users\chenyukun\Desktop\shipin\aaaa.mp4", cv2.VideoWriter_fourcc(*'mp4v'), fps, + (width, height)) + start1 = time.time() + while True: + start = time.time() + in_bytes = p.stdout.read(int(width * height * 3)) + if not in_bytes: + print(in_bytes) + p.stdout.close() + p.wait() + break + # img = (np.frombuffer(in_bytes, np.uint8)).reshape((int(height), int(width))) + # bgr_img = cv2.cvtColor(img, cv2.COLOR_YUV2BGR_NV12) + in_frame = (np.frombuffer(in_bytes, np.uint8).reshape([int(height), int(width), 3])) + # print("拉流时间:", time.time() - start) + # frame = cv2.resize(in_frame, (1280, 720)) # 改变图片尺寸 + # i += 1 + # print(round(time.time()-start, 5)) + # + ai_video_file.write(in_frame) + # if time.time() - start1 > 60: + # ai_video_file.release() + # p.stdout.close() + # p.wait() + # break + # cv2.imshow('frame', in_frame) + # cv2.waitKey(1) + # time.sleep(1111) + p.stdout.close() + p.wait() + p.kill() \ No newline at end of file diff --git a/vodsdk/test/ffmpeg11/ffmpeg13.py b/vodsdk/test/ffmpeg11/ffmpeg13.py new file mode 100644 index 0000000..acbbb32 --- /dev/null +++ b/vodsdk/test/ffmpeg11/ffmpeg13.py @@ -0,0 +1,20 @@ +import json +import time +import subprocess as sp +import ffmpeg +import cv2 +import sys +import random + +import numpy as np + + + +if __name__ == '__main__': + + command = ["ffmpeg", + "-f", "concat", + "-i", r"C:\Users\chenyukun\Desktop\shipin\aaa.txt", + "-c", "copy", + r"C:\Users\chenyukun\Desktop\shipin\aaaa.mp4"] + p = sp.Popen(command, stdout=sp.PIPE) \ No newline at end of file diff --git a/vodsdk/test/ffmpeg11/ffmpeg2.py b/vodsdk/test/ffmpeg11/ffmpeg2.py new file mode 100644 index 0000000..f74ce8e --- /dev/null +++ b/vodsdk/test/ffmpeg11/ffmpeg2.py @@ -0,0 +1,292 @@ +import copy +from enum import Enum, unique +from PIL import Image + +import sys +sys.path.extend(['..','../AIlib' ]) + +from AI import AI_process, AI_process_forest, get_postProcess_para +import cv2,os,time +from segutils.segmodel import SegModel +from models.experimental import attempt_load +from utils.torch_utils import select_device +from utilsK.queRiver import get_labelnames,get_label_arrays +import numpy as np + + + + + +# 异常枚举 +@unique +class ModelType(Enum): + + WATER_SURFACE_MODEL = ("1", "001", "水面模型") + + FOREST_FARM_MODEL = ("2", "002", "森林模型") + + TRAFFIC_FARM_MODEL = ("3", "003", "交通模型") + + def checkCode(code): + for model in ModelType: + if model.value[1] == code: + return True + return False +class ModelConfig(): + def __init__(self): + postFile = '../AIlib/conf/para.json' + self.conf_thres, self.iou_thres, self.classes, self.rainbows = get_postProcess_para(postFile) + + +class SZModelConfig(ModelConfig): + + def __init__(self): + super(SZModelConfig, self).__init__() + labelnames = "../AIlib/weights/yolov5/class8/labelnames.json" ##对应类别表 + self.names = get_labelnames(labelnames) + self.label_arraylist = get_label_arrays(self.names, self.rainbows, outfontsize=40, + fontpath="../AIlib/conf/platech.ttf") + + +class LCModelConfig(ModelConfig): + def __init__(self): + super(LCModelConfig, self).__init__() + labelnames = "../AIlib/weights/forest/labelnames.json" + self.names = get_labelnames(labelnames) + self.label_arraylist = get_label_arrays(self.names, self.rainbows, outfontsize=40, fontpath="../AIlib/conf/platech.ttf") + + +class RFModelConfig(ModelConfig): + def __init__(self): + super(RFModelConfig, self).__init__() + labelnames = "../AIlib/weights/road/labelnames.json" + self.names = get_labelnames(labelnames) + imageW = 1536 + outfontsize=int(imageW/1920*40) + self.label_arraylist = get_label_arrays(self.names, self.rainbows, outfontsize=outfontsize, fontpath="../AIlib/conf/platech.ttf") + +class Model(): + def __init__(self, device, allowedList=None): + ##预先设置的参数 + self.device_ = device ##选定模型,可选 cpu,'0','1' + self.allowedList = allowedList + + +# 水面模型 +class SZModel(Model): + def __init__(self, device, allowedList=None): + super().__init__(device, allowedList) + + self.device = select_device(self.device_) + self.half = self.device.type != 'cpu' + self.model = attempt_load("../AIlib/weights/yolov5/class8/bestcao.pt", map_location=self.device) + if self.half: + self.model.half() + self.segmodel = SegModel(nclass=2, weights='../AIlib/weights/STDC/model_maxmIOU75_1720_0.946_360640.pth', + device=self.device) + + # names, label_arraylist, rainbows, conf_thres, iou_thres + def process(self, frame, config): + return AI_process([frame], self.model, self.segmodel, config[0], config[1], + config[2], self.half, self.device, config[3], config[4], + self.allowedList) + + +# 森林模型 +class LCModel(Model): + def __init__(self, device, allowedList=None): + super().__init__(device, allowedList) + self.device = select_device(self.device_) + self.half = self.device.type != 'cpu' # half precision only supported on CUDA + self.model = attempt_load("../AIlib/weights/forest/best.pt", map_location=self.device) # load FP32 model + if self.half: + self.model.half() + self.segmodel = None + + # names, label_arraylist, rainbows, conf_thres, iou_thres + def process(self, frame, config): + return AI_process_forest([frame], self.model, self.segmodel, config[0], config[1], config[2], + self.half, self.device, config[3], config[4], self.allowedList) + +# 交通模型 +class RFModel(Model): + def __init__(self, device, allowedList=None): + super().__init__(device, allowedList) + self.device = select_device(self.device_) + self.half = self.device.type != 'cpu' # half precision only supported on CUDA + self.model = attempt_load("../AIlib/weights/road/best.pt", map_location=self.device) # load FP32 model + if self.half: + self.model.half() + self.segmodel = None + + # names, label_arraylist, rainbows, conf_thres, iou_thres + def process(self, frame, config): + return AI_process_forest([frame], self.model, self.segmodel, config[0], config[1], config[2], + self.half, self.device, config[3], config[4], self.allowedList) + +def get_model(args): + for model in args[2]: + try: + code = '001' + needed_objectsIndex = [int(category.get("id")) for category in model.get("categories")] + if code == ModelType.WATER_SURFACE_MODEL.value[1]: + return SZModel(args[1], needed_objectsIndex), code, args[0].get("sz") + elif code == ModelType.FOREST_FARM_MODEL.value[1]: + return LCModel(args[1], needed_objectsIndex), code, args[0].get("lc") + elif code == ModelType.TRAFFIC_FARM_MODEL.value[1]: + return RFModel(args[1], needed_objectsIndex), code, args[0].get("rf") + else: + raise Exception("11111") + except Exception as e: + raise Exception("22222") +class PictureWaterMark(): + + def common_water(self, image, logo): + width, height = image.shape[1], image.shape[0] + mark_width, mark_height = logo.shape[1], logo.shape[0] + rate = int(width * 0.2) / mark_width + logo_new = cv2.resize(logo, None, fx=rate, fy=rate, interpolation=cv2.INTER_NEAREST) + position = (int(width * 0.95 - logo_new.shape[1]), int(height * 0.95 - logo_new.shape[0])) + b = Image.new('RGBA', (width, height), (0, 0, 0, 0)) # 创建新图像:透明' + a = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) + watermark = Image.fromarray(cv2.cvtColor(logo_new, cv2.COLOR_BGRA2RGBA)) + # 图片旋转 + # watermark = watermark.rotate(45) + b.paste(a, (0, 0)) + b.paste(watermark, position, mask=watermark) + return cv2.cvtColor(np.asarray(b), cv2.COLOR_BGR2RGB) + + def common_water_1(self, image, logo, alpha=1): + h, w = image.shape[0], image.shape[1] + if w >= h: + rate = int(w * 0.1) / logo.shape[1] + else: + rate = int(h * 0.1) / logo.shape[0] + mask = cv2.resize(logo, None, fx=rate, fy=rate, interpolation=cv2.INTER_NEAREST) + mask_h, mask_w = mask.shape[0], mask.shape[1] + mask_channels = cv2.split(mask) + dst_channels = cv2.split(image) + # b, g, r, a = cv2.split(mask) + # 计算mask在图片的坐标 + ul_points = (int(h * 0.95) - mask_h, int(w - h * 0.05 - mask_w)) + dr_points = (int(h * 0.95), int(w - h * 0.05)) + for i in range(3): + dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] = dst_channels[i][ + ul_points[0]: dr_points[0], + ul_points[1]: dr_points[1]] * ( + 255.0 - mask_channels[3] * alpha) / 255 + dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] += np.array( + mask_channels[i] * (mask_channels[3] * alpha / 255), dtype=np.uint8) + dst_img = cv2.merge(dst_channels) + return dst_img +def video_merge(frame1, frame2, width, height): + frameLeft = cv2.resize(frame1, (width, height), interpolation=cv2.INTER_LINEAR) + frameRight = cv2.resize(frame2, (width, height), interpolation=cv2.INTER_LINEAR) + frame_merge = np.hstack((frameLeft, frameRight)) + # frame_merge = np.hstack((frame1, frame2)) + return frame_merge +cap = cv2.VideoCapture("/home/DATA/chenyukun/3.mp4") + +# Get video information +fps = int(cap.get(cv2.CAP_PROP_FPS)) +print(fps) +width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) +print(width) +height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) +print(height) +# command = ['ffmpeg', +# '-y', # 不经过确认,输出时直接覆盖同名文件。 +# '-f', 'rawvideo', +# '-vcodec', 'rawvideo', +# '-pix_fmt', 'bgr24', +# # '-s', "{}x{}".format(self.width * 2, self.height), +# '-s', "{}x{}".format(width, height), +# '-r', str(15), +# '-i', '-', # 指定输入文件 +# '-g', '15', +# '-sc_threshold', '0', # 使得GOP的插入更加均匀 +# '-b:v', '3000k', # 指定码率 +# '-tune', 'zerolatency', # 加速编码速度 +# '-c:v', 'libx264', # 指定视频编码器 +# '-pix_fmt', 'yuv420p', +# "-an", +# '-preset', 'ultrafast', # 指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, +# # superfast, veryfast, faster, fast, medium, slow, slower, veryslow。 +# '-f', 'flv', +# "rtmp://live.push.t-aaron.com/live/THSAk"] +# +# # 管道配置 +# p = sp.Popen(command, stdin=sp.PIPE, shell=False) + +sz = SZModelConfig() +lc = LCModelConfig() +rf = RFModelConfig() +config = { + "sz": (sz.names, sz.label_arraylist, sz.rainbows, sz.conf_thres, sz.iou_thres), + "lc": (lc.names, lc.label_arraylist, lc.rainbows, lc.conf_thres, lc.iou_thres), + "rf": (rf.names, rf.label_arraylist, rf.rainbows, rf.conf_thres, rf.iou_thres), +} +model = { + "models": [ + { + "code": "001", + "categories": [ + { + "id": "0", + "config": {} + }, + { + "id": "1", + "config": {} + }, + { + "id": "2", + "config": {} + }, + { + "id": "3", + "config": {} + }, + { + "id": "4", + "config": {} + }, + { + "id": "5", + "config": {} + }, + { + "id": "6", + "config": {} + }, + { + "id": "7", + "config": {} + } + ] + }] +} + +mod, model_type_code, modelConfig = get_model((config, str(1), model.get("models"))) +pic = PictureWaterMark() +logo = cv2.imread("./image/logo.png", -1) +ai_video_file = cv2.VideoWriter("/home/DATA/chenyukun/aa/1.mp4", cv2.VideoWriter_fourcc(*'mp4v'), fps, (width*2, height)) +while(cap.isOpened()): + start =time.time() + ret, frame = cap.read() + # cap.grab() + if not ret: + print("Opening camera is failed") + break + p_result, timeOut = mod.process(copy.deepcopy(frame), modelConfig) + frame = pic.common_water_1(frame, logo) + p_result[1] = pic.common_water_1(p_result[1], logo) + frame_merge = video_merge(frame, p_result[1], width, height) + ai_video_file.write(frame_merge) + print(time.time()-start) +ai_video_file.release() +cap.release() + + + + diff --git a/vodsdk/test/ffmpeg11/ffmpeg3.py b/vodsdk/test/ffmpeg11/ffmpeg3.py new file mode 100644 index 0000000..4acfae1 --- /dev/null +++ b/vodsdk/test/ffmpeg11/ffmpeg3.py @@ -0,0 +1,297 @@ +import copy +import subprocess as sp +from enum import Enum, unique +from PIL import Image +import time +import cv2 + +import sys +sys.path.extend(['..','../AIlib' ]) + +from AI import AI_process, AI_process_forest, get_postProcess_para +import cv2,os,time +from segutils.segmodel import SegModel +from models.experimental import attempt_load +from utils.torch_utils import select_device +from utilsK.queRiver import get_labelnames,get_label_arrays +import numpy as np +import torch +from utilsK.masterUtils import get_needed_objectsIndex + + + + + +# 异常枚举 +@unique +class ModelType(Enum): + + WATER_SURFACE_MODEL = ("1", "001", "水面模型") + + FOREST_FARM_MODEL = ("2", "002", "森林模型") + + TRAFFIC_FARM_MODEL = ("3", "003", "交通模型") + + def checkCode(code): + for model in ModelType: + if model.value[1] == code: + return True + return False +class ModelConfig(): + def __init__(self): + postFile = '../AIlib/conf/para.json' + self.conf_thres, self.iou_thres, self.classes, self.rainbows = get_postProcess_para(postFile) + + +class SZModelConfig(ModelConfig): + + def __init__(self): + super(SZModelConfig, self).__init__() + labelnames = "../AIlib/weights/yolov5/class8/labelnames.json" ##对应类别表 + self.names = get_labelnames(labelnames) + self.label_arraylist = get_label_arrays(self.names, self.rainbows, outfontsize=40, + fontpath="../AIlib/conf/platech.ttf") + + +class LCModelConfig(ModelConfig): + def __init__(self): + super(LCModelConfig, self).__init__() + labelnames = "../AIlib/weights/forest/labelnames.json" + self.names = get_labelnames(labelnames) + self.label_arraylist = get_label_arrays(self.names, self.rainbows, outfontsize=40, fontpath="../AIlib/conf/platech.ttf") + + +class RFModelConfig(ModelConfig): + def __init__(self): + super(RFModelConfig, self).__init__() + labelnames = "../AIlib/weights/road/labelnames.json" + self.names = get_labelnames(labelnames) + imageW = 1536 + outfontsize=int(imageW/1920*40) + self.label_arraylist = get_label_arrays(self.names, self.rainbows, outfontsize=outfontsize, fontpath="../AIlib/conf/platech.ttf") + +class Model(): + def __init__(self, device, allowedList=None): + ##预先设置的参数 + self.device_ = device ##选定模型,可选 cpu,'0','1' + self.allowedList = allowedList + + +# 水面模型 +class SZModel(Model): + def __init__(self, device, allowedList=None): + super().__init__(device, allowedList) + + self.device = select_device(self.device_) + self.half = self.device.type != 'cpu' + self.model = attempt_load("../AIlib/weights/yolov5/class8/bestcao.pt", map_location=self.device) + if self.half: + self.model.half() + self.segmodel = SegModel(nclass=2, weights='../AIlib/weights/STDC/model_maxmIOU75_1720_0.946_360640.pth', + device=self.device) + + # names, label_arraylist, rainbows, conf_thres, iou_thres + def process(self, frame, config): + return AI_process([frame], self.model, self.segmodel, config[0], config[1], + config[2], self.half, self.device, config[3], config[4], + self.allowedList) + + +# 森林模型 +class LCModel(Model): + def __init__(self, device, allowedList=None): + super().__init__(device, allowedList) + self.device = select_device(self.device_) + self.half = self.device.type != 'cpu' # half precision only supported on CUDA + self.model = attempt_load("../AIlib/weights/forest/best.pt", map_location=self.device) # load FP32 model + if self.half: + self.model.half() + self.segmodel = None + + # names, label_arraylist, rainbows, conf_thres, iou_thres + def process(self, frame, config): + return AI_process_forest([frame], self.model, self.segmodel, config[0], config[1], config[2], + self.half, self.device, config[3], config[4], self.allowedList) + +# 交通模型 +class RFModel(Model): + def __init__(self, device, allowedList=None): + super().__init__(device, allowedList) + self.device = select_device(self.device_) + self.half = self.device.type != 'cpu' # half precision only supported on CUDA + self.model = attempt_load("../AIlib/weights/road/best.pt", map_location=self.device) # load FP32 model + if self.half: + self.model.half() + self.segmodel = None + + # names, label_arraylist, rainbows, conf_thres, iou_thres + def process(self, frame, config): + return AI_process_forest([frame], self.model, self.segmodel, config[0], config[1], config[2], + self.half, self.device, config[3], config[4], self.allowedList) + +def get_model(args): + for model in args[2]: + try: + code = '001' + needed_objectsIndex = [int(category.get("id")) for category in model.get("categories")] + if code == ModelType.WATER_SURFACE_MODEL.value[1]: + return SZModel(args[1], needed_objectsIndex), code, args[0].get("sz") + elif code == ModelType.FOREST_FARM_MODEL.value[1]: + return LCModel(args[1], needed_objectsIndex), code, args[0].get("lc") + elif code == ModelType.TRAFFIC_FARM_MODEL.value[1]: + return RFModel(args[1], needed_objectsIndex), code, args[0].get("rf") + else: + raise Exception("11111") + except Exception as e: + raise Exception("22222") +class PictureWaterMark(): + + def common_water(self, image, logo): + width, height = image.shape[1], image.shape[0] + mark_width, mark_height = logo.shape[1], logo.shape[0] + rate = int(width * 0.2) / mark_width + logo_new = cv2.resize(logo, None, fx=rate, fy=rate, interpolation=cv2.INTER_NEAREST) + position = (int(width * 0.95 - logo_new.shape[1]), int(height * 0.95 - logo_new.shape[0])) + b = Image.new('RGBA', (width, height), (0, 0, 0, 0)) # 创建新图像:透明' + a = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) + watermark = Image.fromarray(cv2.cvtColor(logo_new, cv2.COLOR_BGRA2RGBA)) + # 图片旋转 + # watermark = watermark.rotate(45) + b.paste(a, (0, 0)) + b.paste(watermark, position, mask=watermark) + return cv2.cvtColor(np.asarray(b), cv2.COLOR_BGR2RGB) + + def common_water_1(self, image, logo, alpha=1): + h, w = image.shape[0], image.shape[1] + if w >= h: + rate = int(w * 0.1) / logo.shape[1] + else: + rate = int(h * 0.1) / logo.shape[0] + mask = cv2.resize(logo, None, fx=rate, fy=rate, interpolation=cv2.INTER_NEAREST) + mask_h, mask_w = mask.shape[0], mask.shape[1] + mask_channels = cv2.split(mask) + dst_channels = cv2.split(image) + # b, g, r, a = cv2.split(mask) + # 计算mask在图片的坐标 + ul_points = (int(h * 0.95) - mask_h, int(w - h * 0.05 - mask_w)) + dr_points = (int(h * 0.95), int(w - h * 0.05)) + for i in range(3): + dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] = dst_channels[i][ + ul_points[0]: dr_points[0], + ul_points[1]: dr_points[1]] * ( + 255.0 - mask_channels[3] * alpha) / 255 + dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] += np.array( + mask_channels[i] * (mask_channels[3] * alpha / 255), dtype=np.uint8) + dst_img = cv2.merge(dst_channels) + return dst_img +def video_merge(frame1, frame2, width, height): + frameLeft = cv2.resize(frame1, (width, height), interpolation=cv2.INTER_LINEAR) + frameRight = cv2.resize(frame2, (width, height), interpolation=cv2.INTER_LINEAR) + frame_merge = np.hstack((frameLeft, frameRight)) + # frame_merge = np.hstack((frame1, frame2)) + return frame_merge +cap = cv2.VideoCapture("/home/DATA/chenyukun/4.mp4") + +# Get video information +fps = int(cap.get(cv2.CAP_PROP_FPS)) +print(fps) +width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) +print(width) +height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) +print(height) +# command = ['ffmpeg', +# '-y', # 不经过确认,输出时直接覆盖同名文件。 +# '-f', 'rawvideo', +# '-vcodec', 'rawvideo', +# '-pix_fmt', 'bgr24', +# # '-s', "{}x{}".format(self.width * 2, self.height), +# '-s', "{}x{}".format(width, height), +# '-r', str(15), +# '-i', '-', # 指定输入文件 +# '-g', '15', +# '-sc_threshold', '0', # 使得GOP的插入更加均匀 +# '-b:v', '3000k', # 指定码率 +# '-tune', 'zerolatency', # 加速编码速度 +# '-c:v', 'libx264', # 指定视频编码器 +# '-pix_fmt', 'yuv420p', +# "-an", +# '-preset', 'ultrafast', # 指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, +# # superfast, veryfast, faster, fast, medium, slow, slower, veryslow。 +# '-f', 'flv', +# "rtmp://live.push.t-aaron.com/live/THSAk"] +# +# # 管道配置 +# p = sp.Popen(command, stdin=sp.PIPE, shell=False) + +sz = SZModelConfig() +lc = LCModelConfig() +rf = RFModelConfig() +config = { + "sz": (sz.names, sz.label_arraylist, sz.rainbows, sz.conf_thres, sz.iou_thres), + "lc": (lc.names, lc.label_arraylist, lc.rainbows, lc.conf_thres, lc.iou_thres), + "rf": (rf.names, rf.label_arraylist, rf.rainbows, rf.conf_thres, rf.iou_thres), +} +model = { + "models": [ + { + "code": "001", + "categories": [ + { + "id": "0", + "config": {} + }, + { + "id": "1", + "config": {} + }, + { + "id": "2", + "config": {} + }, + { + "id": "3", + "config": {} + }, + { + "id": "4", + "config": {} + }, + { + "id": "5", + "config": {} + }, + { + "id": "6", + "config": {} + }, + { + "id": "7", + "config": {} + } + ] + }] +} + +mod, model_type_code, modelConfig = get_model((config, str(0), model.get("models"))) +pic = PictureWaterMark() +logo = cv2.imread("./image/logo.png", -1) +ai_video_file = cv2.VideoWriter("/home/DATA/chenyukun/aa/2.mp4", cv2.VideoWriter_fourcc(*'mp4v'), fps, (width*2, height)) +while(cap.isOpened()): + start =time.time() + ret, frame = cap.read() + # cap.grab() + if not ret: + print("Opening camera is failed") + break + p_result, timeOut = mod.process(copy.deepcopy(frame), modelConfig) + frame = pic.common_water_1(frame, logo) + p_result[1] = pic.common_water_1(p_result[1], logo) + frame_merge = video_merge(frame, p_result[1], width, height) + ai_video_file.write(frame_merge) + print(time.time()-start) +ai_video_file.release() +cap.release() + + + + diff --git a/vodsdk/test/ffmpeg11/ffmpeg33.py b/vodsdk/test/ffmpeg11/ffmpeg33.py new file mode 100644 index 0000000..4089f52 --- /dev/null +++ b/vodsdk/test/ffmpeg11/ffmpeg33.py @@ -0,0 +1,79 @@ +import subprocess as sp +import time +import cv2 +import ffmpeg +# 推流 +import numpy as np + +if __name__== "__main__": + + + # with open(str(cv2.__file__),"r") as f: + # print (f.read()) + # aa = {'loglevel': 'error'} + # process = ( + # ffmpeg + # .input("http://cmgw-vpc.lechange.com:8888/LCO/8D0B355PAN8B3B3/0/0/20221019T130437/eabfe43d95971e0ae03de28dad4fd4ce.m3u8", **aa) + # .output('pipe:', format='rawvideo', pix_fmt='bgr24', loglevel='error')# , bufsize='1000000k' + # .overwrite_output() + # .global_args('-an') + # .run_async(pipe_stdout=True) + # ) + # self.pull_p = sp.Popen(command, stdout=sp.PIPE, stderr=sp.PIPE) + cap = cv2.VideoCapture("https://vod.play.t-aaron.com/customerTrans/edc96ea2115a0723a003730956208134/55547af9-184f0827dae-0004-f90c-f2c-7ec68.mp4") + fps = int(cap.get(cv2.CAP_PROP_FPS)) + print(fps) + width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + print(width) + height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + print(height) + fourcc = int(cap.get(cv2.CAP_PROP_FOURCC)) + print(fourcc) + print(cap.get(7)) + # print(cv2.getBuildInformation()) + # cap.setExceptionMode(True) + # print(cap.getExceptionMode()) + # cap.set(cv2.CAP_PROP_FRAME_WIDTH, 1920) + # cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 1080) + # cap.set(cv2.CAP_PROP_FPS, 25) + # command = ['ffmpeg', + # '-y', # 不经过确认,输出时直接覆盖同名文件。 + # '-f', 'rawvideo', + # '-vcodec','rawvideo', + # '-pix_fmt', 'bgr24', + # # '-r', str(13), + # '-s', "{}x{}".format(width, height), + # # '-s', "{}x{}".format(1280, 720), + # '-i', '-', # 指定输入文件 + # '-c:v', 'libx264', # 指定视频编码器 + # '-pix_fmt', 'yuv420p', + # "-an", + # # '-b:v', '3000k', + # '-preset', 'ultrafast', # 指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, + # # superfast, veryfast, faster, fast, medium, slow, slower, veryslow。 + # '-f', 'flv', + # "rtmp://live.push.t-aaron.com/live/THSAq"] + # + # # # 管道配置 + # p = sp.Popen(command, stdin=sp.PIPE) + # # while(cap.isOpened()): + # while True: + # start =time.time() + # # in_bytes = process.stdout.read(1920 * 1080 * 3) + # # result = (np.frombuffer(in_bytes, np.uint8).reshape([1080, 1920, 3])) + # # time.sleep(0.04) + # ret, frame = cap.read() + # # print(cap.grab()) + # # print("aaaaaaaaaaaaaa", time.time()-start) + # # start =time.time() + # # a,b = cap.retrieve() + # # print("bbbbbbbbbbbbbb", time.time()-start) + # # if not ret: + # # print("Opening camera is failed") + # # break + # # cv2.namedWindow('picture',0) + # # cv2.resizeWindow("picture", 1980, 1080) + # # cv2.imshow('picture', result) + # # cv2.waitKey(1) & 0xFF == ord('q') + # p.stdin.write(frame.tostring()) + diff --git a/vodsdk/test/ffmpeg11/test1.py b/vodsdk/test/ffmpeg11/test1.py new file mode 100644 index 0000000..05557e7 --- /dev/null +++ b/vodsdk/test/ffmpeg11/test1.py @@ -0,0 +1,122 @@ +import json +import time +import subprocess as sp +from concurrent.futures import ThreadPoolExecutor +from traceback import format_exc + +import ffmpeg +import sys + +import numpy as np + +""" +获取视频基本信息 +""" + + +def get_video_info(in_file): + try: + probe = ffmpeg.probe( + 'https://vod.play.t-aaron.com/customerTrans/edc96ea2115a0723a003730956208134/55547af9-184f0827dae-0004-f90c-f2c-7ec68.mp4') + # format = probe['format'] + # size = int(format['size'])/1024/1024 + video_stream = next((stream for stream in probe['streams'] if stream['codec_type'] == 'video'), None) + if video_stream is None: + print('No video stream found', file=sys.stderr) + return + width = int(video_stream['width']) + height = int(video_stream['height']) + num_frames = int(video_stream['nb_frames']) + up, down = str(video_stream['r_frame_rate']).split('/') + fps = eval(up) / eval(down) + print("fbs:", fps) + # duration = float(video_stream['duration']) + bit_rate = int(video_stream['bit_rate']) / 1000 + print('width: {}'.format(width)) + print('height: {}'.format(height)) + # print('num_frames: {}'.format(num_frames)) + print('bit_rate: {}k'.format(bit_rate)) + # print('fps: {}'.format(fps)) + # print('size: {}MB'.format(size)) + # print('duration: {}'.format(duration)) + return video_stream + + + + except Exception as err: + if isinstance(err, ffmpeg._run.Error): + print(err.stderr.decode(encoding='utf-8')) + raise err + +def aa(p1, in_bytes): + try: + p1.stdin.write(in_bytes) + except Exception: + print(format_exc()) + +if __name__ == '__main__': + file_path = 'rtsp://localhost:8554/live' + command = ['ffmpeg', + '-c:v', 'h264_cuvid', + '-i', file_path, + '-f', 'rawvideo', + '-pix_fmt', 'bgr24', + '-an', + '-'] + p = sp.Popen(command, stdout=sp.PIPE) + command1 = ['ffmpeg', + '-y', + "-an", + '-f', 'rawvideo', + '-vcodec', 'rawvideo', + '-pix_fmt', 'bgr24', + '-thread_queue_size', '1024', + '-s', "{}x{}".format(1280, 720), + '-i', '-', # 指定输入文件 + '-r', str(25), + '-g', str(25), + '-maxrate', '6000k', + '-b:v', '4000k', + '-c:v', 'h264_nvenc', # + '-bufsize', '4000k', + '-pix_fmt', 'yuv420p', + '-preset', 'p6', + '-tune', 'll', + '-f', 'flv', + "rtmp://192.168.10.101:19350/rlive/stream_124?sign=YJ8aBPFp"] + # # 管道配置 + p1 = sp.Popen(command1, stdin=sp.PIPE, shell=False) + command2 = ['ffmpeg', + '-y', + "-an", + '-f', 'rawvideo', + '-vcodec', 'rawvideo', + '-pix_fmt', 'bgr24', + '-thread_queue_size', '1024', + '-s', "{}x{}".format(1280, 720), + '-i', '-', # 指定输入文件 + '-r', str(25), + '-g', str(25), + '-maxrate', '6000k', + '-b:v', '4000k', + '-c:v', 'h264_nvenc', # + '-bufsize', '4000k', + '-pix_fmt', 'yuv420p', + '-preset', 'p6', + '-tune', 'll', + '-f', 'flv', + "rtmp://192.168.10.101:19350/rlive/stream_125?sign=uMdRHj9R"] + # # 管道配置 + p2 = sp.Popen(command1, stdin=sp.PIPE, shell=False) + start1 = time.time() + num = 0 + with ThreadPoolExecutor(max_workers=100) as t: + while True: + in_bytes = p.stdout.read(1280 * 720 * 3) + if in_bytes: + img = (np.frombuffer(in_bytes, np.uint8)).reshape((720, 1280, 3)) + for i in range(1): + t.submit(aa, p1, in_bytes) + t.submit(aa, p2, in_bytes) + else: + break diff --git a/vodsdk/test/ffmpeg11/test222.py b/vodsdk/test/ffmpeg11/test222.py new file mode 100644 index 0000000..2ab2617 --- /dev/null +++ b/vodsdk/test/ffmpeg11/test222.py @@ -0,0 +1,80 @@ +from traceback import format_exc + +import cv2 +import numpy as np +from loguru import logger +import subprocess as sp +from common import Constant +from enums.ExceptionEnum import ExceptionType +from exception.CustomerException import ServiceException +from util.Cv2Utils import push_video_stream, clear_pull_p + +pull_p = None +push_p =None +p_push_status=[0,0] + +def start_pull_p(pull_url, requestId): + try: + command = ['ffmpeg'] + # if pull_url.startswith("rtsp://"): + # command.extend(['-timeout', '20000000', '-rtsp_transport', 'tcp']) + # if pull_url.startswith("http") or pull_url.startswith("rtmp"): + # command.extend(['-rw_timeout', '20000000']) + command.extend(['-re', + '-y', + '-an', + # '-hwaccel', 'cuda', cuvid + '-c:v', 'h264_cuvid', + # '-resize', self.wah, + '-i', pull_url, + '-f', 'rawvideo', + # '-pix_fmt', 'bgr24', + '-r', '25', + '-']) + return sp.Popen(command, stdout=sp.PIPE) + except ServiceException as s: + logger.error("构建拉流管道异常: {}, requestId:{}", s.msg, requestId) + raise s + except Exception as e: + logger.error("构建拉流管道异常:{}, requestId:{}", format_exc(), requestId) + raise e + +def pull_read_video_stream(pull_p, pull_url, width, height, width_height_3, w_2, h_2, requestId): + result = None + try: + if pull_p is None: + pull_p = start_pull_p(pull_url, requestId) + in_bytes = pull_p.stdout.read(width_height_3) + if in_bytes is not None and len(in_bytes) > 0: + try: + # result = (np.frombuffer(in_bytes, np.uint8).reshape([height * 3 // 2, width, 3])) + # ValueError: cannot reshape array of size 3110400 into shape (1080,1920) + result = (np.frombuffer(in_bytes, np.uint8)).reshape((height, width)) + result = cv2.cvtColor(result, cv2.COLOR_YUV2BGR_NV12) + # result = cv2.cvtColor(result, cv2.COLOR_RGB2BGR) + if result.shape[1] > Constant.width: + result = cv2.resize(result, (result.shape[1] // 2, result.shape[0] // 2), interpolation=cv2.INTER_LINEAR) + except Exception: + logger.error("视频格式异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.VIDEO_RESOLUTION_EXCEPTION.value[0], + ExceptionType.VIDEO_RESOLUTION_EXCEPTION.value[1]) + except ServiceException as s: + clear_pull_p(pull_p, requestId) + raise s + except Exception: + clear_pull_p(pull_p, requestId) + pull_p = None + width = None + height = None + width_height_3 = None + logger.error("读流异常:{}, requestId:{}", format_exc(), requestId) + return result, pull_p, width, height, width_height_3 + +while True: + frame, pull_p, width, height, width_height_3 = pull_read_video_stream(pull_p, 'rtmp://live.play.t-aaron.com/live/THSAr', 1920, + 1080*3//2, 1920*1080*3//2, 960, 540, + '111') + if frame is not None: + push_p = push_video_stream(frame, push_p, 'rtmp://live.push.t-aaron.com/live/THSAs', p_push_status, '11') +clear_pull_p(pull_p, "11111") +close_all_p(push_p, None, None, "11111") \ No newline at end of file diff --git a/vodsdk/test/gpu/__init__.py b/vodsdk/test/gpu/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/gpu/gputest.py b/vodsdk/test/gpu/gputest.py new file mode 100644 index 0000000..67dd379 --- /dev/null +++ b/vodsdk/test/gpu/gputest.py @@ -0,0 +1,7 @@ + +import tensorflow as tf +import torch + +if __name__ == '__main__': + gpu_name = torch.cuda.get_device_name(0) + print(gpu_name) \ No newline at end of file diff --git a/vodsdk/test/gpu/gputest1.py b/vodsdk/test/gpu/gputest1.py new file mode 100644 index 0000000..2b1a116 --- /dev/null +++ b/vodsdk/test/gpu/gputest1.py @@ -0,0 +1,54 @@ +import GPUtil +import json +# 网址:https://github.com/anderskm/gputil +GPUtil.showUtilization() +#返回可用 GPU 的列表 ID。 +# order- 确定返回可用 GPU 设备 ID 的顺序。order应指定为以下字符串之一: +# 'first'- 按升序排列可用的 GPU 设备 ID(默认) +# 'last'- 按 id 降序排列可用的 GPU 设备 id +# 'random'- 随机订购可用的 GPU 设备 ID +# 'load'- 按负载递增排序可用的 GPU 设备 ID +# 'memory'- 通过升序内存使用来排序可用的 GPU 设备 ID +# limit- 将返回的 GPU 设备 ID 数量限制为指定数量。必须是正整数。(默认 = 1) +# maxLoad- 被认为可用的 GPU 的最大当前相对负载。负载大于 的 GPUmaxLoad不会返回。(默认 = 0.5) +# maxMemory- 被视为可用的 GPU 的最大当前相对内存使用量。maxMemory不返回当前内存使用量大于的 GPU 。(默认 = 0.5) +# includeNan- 真/假标志,指示是否包括负载或内存使用为 NaN 的 GPU(指示无法检索使用情况)。(默认 = 假) +# excludeID- ID 列表,应从可用 GPU 列表中排除。见GPU类描述。(默认 = []) +# excludeUUIDexcludeID-除了它使用 UUID 之外,其他相同。(默认 = []) +# 输出 +# deviceIDs - 所有可用 GPU 设备 ID 的列表。如果当前负载和内存使用量分别小于maxLoad和maxMemory,则认为 GPU 可用。该列表是根据 排序的order。返回的设备 ID 的最大数量由 限制limit。 +deviceIDs = GPUtil.getAvailable(order = 'memory', limit = 1, maxLoad = 0.8, maxMemory = 0.8, includeNan=False, excludeID=[], excludeUUID=[]) +print(deviceIDs) +# 返回第一个可用的 GPU。可用性是根据当前的内存使用和负载确定的,排序由指定的顺序确定。如果找不到可用的 GPU,则会引发错误。使用默认值时,与getAvailable(order = 'first', limit = 1, maxLoad = 0.5, maxMemory = 0.5) +# 输入 +# order- 见描述GPUtil.getAvailable(...) +# maxLoad- 被认为可用的 GPU 的最大当前相对负载。负载大于 的 GPUmaxLoad不会返回。(默认 = 0.5) +# maxMemory- 被视为可用的 GPU 的最大当前相对内存使用量。maxMemory不返回当前内存使用量大于的 GPU 。(默认 = 0.5) +# attempts- 在放弃寻找可用 GPU 之前,该函数应进行的尝试次数。(默认 = 1) +# interval- 每次尝试查找可用 GPU 的时间间隔(以秒为单位)。(默认 = 900 --> 15 分钟) +# verbose- 如果True是,则在每次尝试之前打印尝试次数,如果找到可用的,则打印 GPU id。 +# includeNan- 见说明GPUtil.getAvailable(...)。(默认 = 假) +# excludeID- 见说明GPUtil.getAvailable(...)。(默认 = []) +# excludeUUID- 见说明GPUtil.getAvailable(...)。(默认 = []) +# 输出 +# deviceID - 包含 1 个元素的列表,其中包含第一个可用的 GPU 设备 ID。如果当前负载和内存使用量分别小于maxLoad和maxMemory,则认为 GPU 可用。顺序和限制分别固定为'first'和1。 +deviceID = GPUtil.getFirstAvailable(order = 'first', maxLoad=0.5, maxMemory=0.5, attempts=1, interval=900, verbose=False) +print(deviceID) +GPUtil.showUtilization(all=True, attrList=None, useOldCode=True) +# 打印所有 GPU 的当前状态(id、内存使用情况、uuid 负载) +# 输入 +# all- 真/假标志,指示是否应显示 GPU 上的所有信息。覆盖attrList。 +# attrListGPU-要显示的属性列表列表。有关更多信息/示例,请参见代码。 +# useOldCode- 真/假标志,指示是否应使用显示 GPU 利用率的旧代码。 +# 输出 +# 没有任何 + +GPUs = GPUtil.getGPUs() +for gpu in GPUs: + print(gpu.id) +# 输入 +# 没有任何 +# 输出 +# GPUs- 所有 GPU 的列表。每个GPU对应于计算机中的一个 GPU,并包含一个设备 ID、相对负载和相对内存使用情况。 +if __name__ == "___main__": + pass \ No newline at end of file diff --git a/vodsdk/test/image/1.jpg b/vodsdk/test/image/1.jpg new file mode 100644 index 0000000..7129dda Binary files /dev/null and b/vodsdk/test/image/1.jpg differ diff --git a/vodsdk/test/image/11.jpg b/vodsdk/test/image/11.jpg new file mode 100644 index 0000000..b559e91 Binary files /dev/null and b/vodsdk/test/image/11.jpg differ diff --git a/vodsdk/test/image/2.jpg b/vodsdk/test/image/2.jpg new file mode 100644 index 0000000..4ec90ec Binary files /dev/null and b/vodsdk/test/image/2.jpg differ diff --git a/vodsdk/test/image/22.jpg b/vodsdk/test/image/22.jpg new file mode 100644 index 0000000..fadfacb Binary files /dev/null and b/vodsdk/test/image/22.jpg differ diff --git a/vodsdk/test/ip/__init__.py b/vodsdk/test/ip/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/ip/test.py b/vodsdk/test/ip/test.py new file mode 100644 index 0000000..d3156a3 --- /dev/null +++ b/vodsdk/test/ip/test.py @@ -0,0 +1,34 @@ +import socket + +# def get_local_ip(): +# client = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +# # 连接谷歌的dns服务器 +# client.connect(("8.8.8.8", 80)) +# ip, _ = client.getsockname() # 获取套接字自己的地址,返回元组,ip地址和端口号 +# client.close() +# return ip +# +# +# if __name__ == '__main__': +# print(get_local_ip()) + + +import socket +from concurrent.futures import wait, ALL_COMPLETED, ThreadPoolExecutor + + +def getport(port): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(1) + state = sock.connect_ex(("192.168.11.8", port)) + if 0 == state: + print("port: {} is open".format(port)) + sock.close() + + +with ThreadPoolExecutor(max_workers=100) as t: + task_array = [] + for port in range(1, 65535): + task = t.submit(getport, port) + task_array.append(task) + wait(task_array, return_when=ALL_COMPLETED) diff --git a/vodsdk/test/kafka/__init__.py b/vodsdk/test/kafka/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/kafka/producer_start.py b/vodsdk/test/kafka/producer_start.py new file mode 100644 index 0000000..16dc59c --- /dev/null +++ b/vodsdk/test/kafka/producer_start.py @@ -0,0 +1,148 @@ +# import sys +# sys.path.extend(["..", "../util"]) +# from util.AliyunSdk import AliyunVodSdk +# from concurrency.CommonThread import Common +from kafka import KafkaProducer +import json +import threading + +topicName = 'dsp-alg-online-tasks' +# eBody = { +# "request_id": "d4c909912ac741ce81ccef03fd1b2ec45", +# "models": [ +# { +# "code": "001", +# "categories": [{ +# "id": "0", +# "config": {} +# }, +# { +# "id": "1", +# "config": {} +# }, +# { +# "id": "2", +# "config": {} +# }, +# { +# "id": "3", +# "config": {} +# }, +# { +# "id": "4", +# "config": {} +# }, +# { +# "id": "5", +# "config": {} +# } +# ] +# }], +# "command": "start", +# "pull_url": "rtmp://live.play.t-aaron.com/live/THSAr", +# "push_url": "rtmp://live.push.t-aaron.com/live/THSAs", +# "results_base_dir": "P20220802133841159" +# } +# producer = KafkaProducer(bootstrap_servers=['192.168.11.242:9092'], +# value_serializer=lambda m: json.dumps(m).encode('utf-8')) +# future = producer.send(topicName, key=b'd4c909912ac741ce81ccef03fd1b2ec45', value=eBody) +# result = future.get(timeout=10) +# print(result) + +# topicName = 'dsp-alg-image-tasks' +eBody = { + "request_id": "d4c909912ac741ce81ccef03fd1b2ec46", + "models": [ + { + "code": "001", + "categories": [ + { + "id": "0", + "config": {} + }, + { + "id": "1", + "config": {} + }, + { + "id": "2", + "config": {} + }, + { + "id": "3", + "config": {} + }, + { + "id": "4", + "config": {} + }, + { + "id": "5", + "config": {} + }, + { + "id": "6", + "config": {} + }, + { + "id": "7", + "config": {} + } + ] + }], + "command": "start", + "image_urls": ["https://ta-tech-image.oss-cn-shanghai.aliyuncs.com/imagedir/cmn5kvdl23l_1669862645395.bmp"], + "results_base_dir": "P20220802133841159" +} +# topicName = 'dsp-alg-offline-tasks' +# eBody = { +# "request_id": "d4c909912ac741ce81ccef03fd1b2ec46", +# "models": [ +# { +# "code": "001", +# "categories": [ +# { +# "id": "0", +# "config": {} +# }, +# { +# "id": "1", +# "config": {} +# }, +# { +# "id": "2", +# "config": {} +# }, +# { +# "id": "3", +# "config": {} +# }, +# { +# "id": "4", +# "config": {} +# }, +# { +# "id": "5", +# "config": {} +# }, +# { +# "id": "6", +# "config": {} +# }, +# { +# "id": "7", +# "config": {} +# } +# ] +# }], +# "command": "start", +# "original_url": "https://vod.play.t-aaron.com/0bc905ef5651439da2bfba8427fe467e/a76a7ebb6e3b44ef9c0c7820c7e9c574-f2d7ee90cba11aa91971d58e06d295d2-4k.mp4", +# "original_type": ".mp4", +# "push_url": "rtmp://live.push.t-aaron.com/live/THSAr", +# "results_base_dir": "P20220802133841159" +# } +producer = KafkaProducer(bootstrap_servers=['101.132.127.1:19094','101.132.127.1:29094','101.132.127.1:39094'], + value_serializer=lambda m: json.dumps(m).encode('utf-8')) +future = producer.send(topicName, key=b'd4c909912ac741ce81ccef03fd1b2ec46', value=eBody) +result = future.get(timeout=10) +# print(result) \ No newline at end of file diff --git a/vodsdk/test/kafka/producer_stop.py b/vodsdk/test/kafka/producer_stop.py new file mode 100644 index 0000000..f6839ab --- /dev/null +++ b/vodsdk/test/kafka/producer_stop.py @@ -0,0 +1,18 @@ +# import sys +# sys.path.extend(["..", "../util"]) +# from util.AliyunSdk import AliyunVodSdk +# from concurrency.CommonThread import Common +from kafka import KafkaProducer +import json +import threading + +topicName = 'dsp-alg-online-tasks' +eBody = { + "request_id": "d4c909912ac741ce81ccef03fd1b2ec45", + "command": "stop" +} +producer = KafkaProducer(bootstrap_servers=['192.168.11.242:9092'], + value_serializer=lambda m: json.dumps(m).encode('utf-8')) +future = producer.send(topicName, key=b'd4c909912ac741ce81ccef03fd1b2ec45', value=eBody) +result = future.get(timeout=10) +print(result) \ No newline at end of file diff --git a/vodsdk/test/minio1/__pycache__/minio_test.cpython-310.pyc b/vodsdk/test/minio1/__pycache__/minio_test.cpython-310.pyc new file mode 100644 index 0000000..ede1742 Binary files /dev/null and b/vodsdk/test/minio1/__pycache__/minio_test.cpython-310.pyc differ diff --git a/vodsdk/test/minio1/minio_test.py b/vodsdk/test/minio1/minio_test.py new file mode 100644 index 0000000..1696b38 --- /dev/null +++ b/vodsdk/test/minio1/minio_test.py @@ -0,0 +1,31 @@ +import io +import json + +import cv2 +import urllib3 +from minio import Minio + +# MinIO + +minioClient = Minio('192.168.12.5:9000', + access_key='RoZc1NbZ6oAC4lTV', + secret_key='wC01Lup6SIoahwfSrYcoF2gSF3mPy6gJ', + secure=False) +aa = r'C:\Users\chenyukun\Desktop\shipin\DJI_20211229100908_0001_S.mp4' +# # 创建存储桶 +# img = cv2.imread(r"D:\work\alg\tuoheng_alg\test\image\1.jpg") +# ai_result, ai_image = cv2.imencode(".jpg", img) +# # minioClient.make_bucket("test/bb") +# print(len(ai_image)) +# minioClient.put_object('test', '1.jpg', io.BytesIO(ai_image.tobytes()), len(ai_image)) +result = minioClient.fput_object("test", "aa3.mp4", aa) +print(result.__dict__) +# 查看桶信息 +# buckets = minioClient.list_buckets() +# for bucket in buckets: +# print(bucket.name, bucket.creation_date) +# 判断桶是否存在 +if minioClient.bucket_exists("my-bucket"): + print("my-bucket exists") +else: + print("my-bucket does not exist") \ No newline at end of file diff --git a/vodsdk/test/numpy/__init__.py b/vodsdk/test/numpy/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/numpy/numpy_test.py b/vodsdk/test/numpy/numpy_test.py new file mode 100644 index 0000000..ce127d1 --- /dev/null +++ b/vodsdk/test/numpy/numpy_test.py @@ -0,0 +1,108 @@ + + +import numpy as np +# # 使用标量类型 +# dt = np.dtype(np.int32) +# print(dt) +# +# # int8, int16, int32, int64 四种数据类型可以使用字符串 'i1', 'i2','i4','i8' 代替 +# dt = np.dtype('i4') +# print(dt) +# +# # 字节顺序标注 +# dt = np.dtype(' 色彩的饱和度 +(3) Lab: 有国际照明委员会建立。 L: 整张图到的明亮度 a\b: 负责颜色的多少 +""" +import cv2 +import numpy as np +from matplotlib import pyplot as plt + +# img = cv2.imread(r'C:\Users\chenyukun\Pictures\R.png') +# cv2.imshow("img", img) + +# HSV +# hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) +# cv2.imshow("hsv", hsv) + +# YUV +# yuv = cv2.cvtColor(img, cv2.COLOR_BGR2YUV) +# cv2.imshow("yuv", yuv) + +# LAB +# lab = cv2.cvtColor(img, cv2.COLOR_BGR2Lab) +# cv2.imshow("lab", lab) + +# 分离颜色通道 +# print(img) +# b, g, r = cv2.split(img) +# h, w = np.shape(b) +# # 建立空白数组 +# hest = np.zeros([256], dtype=np.int32) +# print(hest) +# # 遍历图片 +# for i in [b, g, r]: +# for row in range(h): +# for col in range(w): +# pv = i[row, col] +# hest[pv] += 1 +# plt.plot(hest, color='r') +# plt.show() +# cv2.waitKey(100000) + +# array1 = np.random.randint(0, 255, (300, 150, 3), dtype=np.uint8) +# array2 = np.random.randint(200, 255, (300, 150, 3), dtype=np.uint8) +# new_array = np.hstack([array1, array2]) +# cv2.imshow("new_array", new_array) +# cv2.waitKey(100000) + +# 彩色图片 -> BGR +# 查看B +# img_B = img.copy() +# img_B[:, :, 1] = 0 +# img_B[:, :, 2] = 0 +# cv2.imshow("img_B", img_B) +# cv2.waitKey(100000) + +# 查看G +# img_G = img.copy() +# img_G[:, :, 0] = 0 +# img_G[:, :, 2] = 0 +# cv2.imshow("img_G", img_G) +# cv2.waitKey(100000) + +# 查看G +# img_R = img.copy() +# img_R[:, :, 0] = 0 +# img_R[:, :, 1] = 0 +# cv2.imshow("img_R", img_R) +# cv2.waitKey(100000) + +# 深入研究图片的读取 +""" +cv2.imread(path, way) +0: 读取灰度图片 +1: 读取彩色图片 +-1: 读取图片,加载Alpha通道 +Alpha通道: +指一张图片的透明与不透明度 +""" +img_color = cv2.imread(r'C:\Users\chenyukun\Pictures\R.png') + +img_gray = cv2.imread(r'C:\Users\chenyukun\Pictures\R.png', 0) + +img_transparent = cv2.imread(r'C:\Users\chenyukun\Pictures\R.png', -1) + +""" +彩色图像:三维 B G R -> (373*490) +灰度图像:二维:-> (373*490) +推断出的公式: Y = (B+G+R)/3 +官方给出的公式: Y = 0.299R + 0.587G + 0.114B +cv.imshow() -> 不仅仅是array()必须是uint8这种类型的。 +""" + +# 三通道分离 +# b, g, r = cv2.split(img_color) +# new_img = (b+g+r)/3 +# new_img = 0.299*r + 0.587*g + 0.114*b +# new_img = new_img.astype('uint8') +# cv2.imshow('new_img', new_img) + +# 官方的填充方式: 以初始的灰度二维矩阵进行RGB通道的填充 +# new_image = cv2.merge([img_gray,img_gray,img_gray]) +# cv2.imshow('new_img', new_image) +# cv2.waitKey(100000) + +# 图像的加法 -> 矩阵 + +# 加法 【前提:必须是一样大小的矩阵:对应的元素求和】 +""" +像素点: [0,255]超过255怎么办?【取余】 +150+150=300 +300%255 +""" + +""" +图片融合 +addWeighted(src1, alpha, src2, beta, gamma) +src1\src2: 第一张和第二张图片 +alpha\beta: 第一张图片的权重、第二张图片的权重 +gamma: 亮度的调节 +""" +# result = cv2.addWeighted(img_color, 0.6, img_color, 0.3, 0) +# cv2.imshow('new_img', result) +# cv2.waitKey(100000) +# +# # 图像的类型转换 +# # 原始图片BGR -> RGB +# cv2.cvtColor(img_color, cv2.COLOR_BGR2RGB) + +""" +1.沿着x轴进行翻转 +2.沿着y轴进行翻转 +3.同时沿着x轴和y进行翻转 +cv2.flip(src, flipCode) +src: 源图像 +flipCode: 翻转形式 +0:沿着x轴进行翻转 +1(大于等于1): 沿着y轴进行翻转 +-1(小于等于-1): 同时沿着x轴和y进行翻转 +""" + +""" +图像阈值化处理 +ret, dst = cv2.threshold(src, thresh, maxval, type) +ret: 阈值返回值(阈值设定的是多少) +dst: 输出的图像 +src: 源图像 需要阈值化处理的图像 +thresh: 人为指定的阈值 +maxval: 当像素超过了阈值,(小于等于阈值)所赋予的值,否则取0 +type: +(1) cv2.THRESH_BINARY: 当像素点大于阈值时,取指定255,小于等于阈值时,取0 +(2) cv2.THRESH_BINARY_INV: 当像素点大于阈值时,取0。小于等于阈值时,取255 +(3) cv2.THRESH_TRUNC: 超过阈值取阈值,低于阈值取自身 +(4) cv2.THRESH_TOZERO: 超过阈值不变,低于阈值取0 +(5) cv2.THRESH_TOZERO_INV: 超过阈值变为0, 低于阈值不变 +注意:当阈值处理彩色图像时,出现粉色等颜色的原因在于: BGR三通道的叠加 +""" +# ret, dst = cv2.threshold(img_color, 127, 255, cv2.THRESH_BINARY) +# cv2.imshow('new_img', dst) +# cv2.waitKey(100000) + +""" +均值滤波 +cv2.blur(src, kernel) +src: 源图像 +kernel: 大小(选择多大的矩阵进行平移[3*3最常见]) +""" +# new_img = cv2.blur(img_color, (3, 3)) +# cv2.imshow('new_img', new_img) +# cv2.waitKey(100000) +""" +方框滤波 +cv2.boxFilter(src,depth, ksize, normalize) +src: 源图像 +depth: 图像的深度 填-1就ok, 表示与源图像深度相同 +ksize: 核大小(3*3)(5*5) +normalize: 是否进行归一化 +0:false 不进行归一下(求和,像素点溢出,超过255取255) +1:True 进行归一化,也就是均值滤波 +""" +""" +高斯滤波【考虑了权重问题】 +cv2.GaussianBlur(src, ksize, sigmaX, sigmaY) +src:源图像 +ksize: (3*3)(5*5) 必须为奇数 +sigmaX, sigmaY: 高斯核函数在x或y方向上的标准偏差【控制权重】 +sigmaX = 0, sigmaX = 0.3 * ((ksize -1) * 0.5 -1) + 0.8 +""" +''' +中值滤波 +cv2.medianBlur(src, ksize) +src: 源图像 +ksize:核大小, 只能传递int(1,3,5,7,9)【(3, 3)(5, 5)】 +''' +new_img = cv2.medianBlur(img_color, 5) +cv2.imshow('new_img', new_img) +cv2.waitKey(100000) \ No newline at end of file diff --git a/vodsdk/test/os/__init__.py b/vodsdk/test/os/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/os/test.py b/vodsdk/test/os/test.py new file mode 100644 index 0000000..5a2471b --- /dev/null +++ b/vodsdk/test/os/test.py @@ -0,0 +1,15 @@ +""" +1.os.rename(原文件名,新的文件名) ——文件重命名 +2.os.remove(文件名) ——删除文件 + 如果不说明路径,则在源代码所在文件夹下寻找,寻找不到会报错。 + 若想删除指定文件夹下的文件,文件名则需要具体路径,例如 os.remove(r"D:\test_1\文件名"), r防止斜杠发生转义 +3.os.mkdir(文件夹名) ——创建文件夹 +4.os.rmdir(文件夹名) ——删除文件夹 +5.os.getced() ——获取当前目录 +6.os.chdir(目录) ——切换目录 +7.os.listdir(目录) ——获取当前文件夹下所有的文件或者文件夹,返回一个列表 + os.listdir("aa") #获取aa文件夹下的所有文件或文件夹,返回一个列表 + + +""" +import os \ No newline at end of file diff --git a/vodsdk/test/pachong/__init__.py b/vodsdk/test/pachong/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/pachong/pa.py b/vodsdk/test/pachong/pa.py new file mode 100644 index 0000000..3398783 --- /dev/null +++ b/vodsdk/test/pachong/pa.py @@ -0,0 +1,24 @@ +import requests +# url = 'https://www.baidu.com' +# response = requests.get(url) +# print(response) +# print(type(response)) +# # 返回的页面是requests库猜测的编码方式,有误 +# print(response.text) +# content = response.content.decode('utf-8') +# print(content) + +url = 'https://www.baidu.com/s' +kw = {"wd": "猫"} +headers = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/113.0.0.0 Safari/537.36" +} +response = requests.get(url, params=kw, headers=headers) +# 打印requests库猜测的解码方式 +print(response.encoding) +content = response.content.decode('utf-8') +print(content) +# 查看状态码 +print(response.status_code) + + diff --git a/vodsdk/test/str/test.py b/vodsdk/test/str/test.py new file mode 100644 index 0000000..62c58c9 --- /dev/null +++ b/vodsdk/test/str/test.py @@ -0,0 +1,26 @@ + + + +# aaa={"1":"1","2":"2","3":"3","4": {"1": "4"}} +# for i,v in aaa.items(): +# if i =="4": +# v["1"] = "5" +# +# print(aaa) +# class base(object): +# __slots__=('x') +# var=8 +# def __init__(self): +# pass +# +# def aa(self): +# print("aa") +# +# b=base() +# b.x=88 +# print(b.aa()) +aa = [1,2,3] +a,b,c = aa +print(a) +print(b) +print(c) diff --git a/vodsdk/test/test_minio.py b/vodsdk/test/test_minio.py new file mode 100644 index 0000000..7511dfd --- /dev/null +++ b/vodsdk/test/test_minio.py @@ -0,0 +1,11 @@ +from minio import Minio +minioClient = Minio('minio-jndsj.t-aaron.com:2443', + access_key='PJM0c2qlauoXv5TMEHm2', + secret_key='Wr69Dm3ZH39M3GCSeyB3eFLynLPuGCKYfphixZuI', + secure=True) +try: + #minioClient.fput_object('default', 'demo1.mp4', '/home/th/WJ/data/XunHe/ai_online_avc1.mp4',content_type='video/mp4') + #'/home/th/WJ/DSP2/AIdemo2/images/cityRoad/DJI_0019_142.jpg' + minioClient.fput_object('default','t2.jpg','/home/th/WJ/DSP2/AIdemo2/images/cityRoad/DJI_0019_142.jpg') +except Exception as err: + print(err) diff --git a/vodsdk/test/test_push_stream.py b/vodsdk/test/test_push_stream.py new file mode 100644 index 0000000..af3300f --- /dev/null +++ b/vodsdk/test/test_push_stream.py @@ -0,0 +1,42 @@ +from util.Cv2Utils import video_conjuncing, write_or_video, write_ai_video, push_video_stream, close_all_p,pull_read_video_stream +import inspect +import psutil + +def check_cpu(current_line_number): + cpu_use = psutil.cpu_percent() + cpu_mem = psutil.virtual_memory().percent + cpu_swap = psutil.swap_memory().percent + mem = psutil.virtual_memory() + + # 已经使用的内存量(包括缓存和缓冲区) + used_mem = mem.used/(1024**2) + #current_line_number = inspect.currentframe().f_lineno + print( '---line:{} ,CPU 使用率:{}, 内存使用:{},{:4.0f}M, SWAP内存使用率:{}'.format(current_line_number,cpu_use, cpu_mem,used_mem,cpu_swap) ) +if __name__=='__main__': + width=1920;height=1620;width_height_3=3110400;all_frames=3687; w_2=960;h_2=540 + request_id='11111111111111' + pull_p=None + #pull_url='https://vod.play.t-aaron.com/customerTrans/edc96ea2115a0723a003730956208134/4b773ace-18f56a8ed7d-0004-f90c-f2c-7ec68.mp4' + pull_url='https://vod.play.t-aaron.com/customerTrans/edc96ea2115a0723a003730956208134/55547af9-184f0827dae-0004-f90c-f2c-7ec68.mp4' + + + push_p=None + #push_url='rtmp://live.push.t-aaron.com/live/prod33' + push_url='rtmp://live.push.t-aaron.com/live/innertest32' + check_cpu(inspect.currentframe().f_lineno) + #测试拉流OK + while True: + check_cpu(inspect.currentframe().f_lineno) + 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: + break + + check_cpu(inspect.currentframe().f_lineno) + #测试推流 + + push_p=push_video_stream(frame, push_p, push_url, [1,1], '2222222222222222222') + check_cpu(inspect.currentframe().f_lineno) + + print('noth') + \ No newline at end of file diff --git a/vodsdk/test/test_video.py b/vodsdk/test/test_video.py new file mode 100644 index 0000000..a1478ad --- /dev/null +++ b/vodsdk/test/test_video.py @@ -0,0 +1,32 @@ +import cv2 +import ffmpeg + +vformat='X264'#mp4v,X264,H264 +inUrl='/home/th/WJ/data/XunHe/ai_online.mp4' +outUrl='/home/th/WJ/data/XunHe/ai_%s.avi'%(vformat) +# 打开输入视频文件 +input_video = cv2.VideoCapture(inUrl) + +# 获取视频的帧率和帧大小 +fps = input_video.get(cv2.CAP_PROP_FPS) +frame_width = int(input_video.get(cv2.CAP_PROP_FRAME_WIDTH)) +frame_height = int(input_video.get(cv2.CAP_PROP_FRAME_HEIGHT)) + +# 定义输出视频的编解码器和创建 VideoWriter 对象 +#fourcc = cv2.VideoWriter_fourcc(*'%s'%(vformat) ) +output_video = cv2.VideoWriter(outUrl, fourcc, fps, (frame_width, frame_height)) +#output_video = ffmpeg.VideoWriter(outUrl, vformat, fps, (frame_width, frame_height)) +# 逐帧读取视频 +iframe=0 +while input_video.isOpened(): + ret, frame = input_video.read() + if not ret: + break + if iframe>1000: break + iframe+=1 + # 将帧写入输出视频 + ret2=output_video.write(frame) + print(iframe,ret,ret2) +# 释放 VideoCapture 和 VideoWriter 对象 +input_video.release() +output_video.release() diff --git a/vodsdk/test/test_video2.py b/vodsdk/test/test_video2.py new file mode 100644 index 0000000..b32003a --- /dev/null +++ b/vodsdk/test/test_video2.py @@ -0,0 +1,26 @@ + +import cv2 +import numpy as np + +# 定义编码器并创建VideoWriter对象 +#fourcc = cv2.VideoWriter_fourcc(*'acv1') +fourcc = cv2.VideoWriter_fourcc(*'avc1') +output_video = 'output.mp4' +frame_width = 1920 +frame_height = 1080 +fps = 30 +out = cv2.VideoWriter(output_video, fourcc, fps, (frame_width, frame_height)) + +# 创建视频帧(使用黑色作为示例) +frame = np.zeros((frame_height, frame_width, 3), np.uint8) + +# 写入视频帧 +for i in range(60): # 假设我们只写入60帧 + # 这里可以替换为你的处理过程,比如添加文本或者处理帧 + # ... + + # 将帧写入视频 + out.write(frame) + +# 释放VideoWriter对象 +out.release() diff --git a/vodsdk/test/validate/Test.py b/vodsdk/test/validate/Test.py new file mode 100644 index 0000000..31b44e1 --- /dev/null +++ b/vodsdk/test/validate/Test.py @@ -0,0 +1,139 @@ + +import re +from cerberus import Validator +# pattern = re.compile('^[a-zA-Z0-9]{1,36}$') # 用于匹配至少一个数字 +# m = pattern.match('111aaa3213213123123213123a222') +# print(m) +# +# schema = { +# 'name': {'type': 'string', 'required': True}, +# 'age': {'type': 'integer', 'required': True, 'min': 18}, +# 'email': {'type': 'string', 'required': True, 'regex': r'\w+@\w+\.\w+'} +# } +# v = Validator(schema) +# print(v.validate({ 'name': '11', 'age': 20, 'email': '764784960@qq.com'})) +# aa = str({ 'name': '11', 'age': 20, 'email': '764784960@qq.com'}) +# print(isinstance(aa, dict)) + +# schema = {'name': {'type': 'string'}} +# v = Validator(schema) +# document = {'name1': 'john doe'} +# print(v.validate(document)) +# print(v.validate(document, schema)) + +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'] + }, + 'pull_url': { + 'type': 'string', + 'required': False, + 'nullable': True, + 'maxlength': 255 + }, + 'push_url': { + 'type': 'string', + 'required': False, + 'nullable': True, + 'maxlength': 255 + }, + 'original_url': { + 'type': 'string', + 'required': False, + 'nullable': True, + 'maxlength': 255 + }, + 'original_type': { + 'type': 'string', + 'required': False, + 'nullable': True, + 'maxlength': 255 + }, + 'image_urls': { + 'type': 'list', + 'required': False, + 'schema': { + 'type': 'string', + 'empty': False, + 'maxlength': 5000 + } + }, + 'results_base_dir': { + 'type': 'string', + 'required': False, + 'nullable': True, + 'regex': r'^[a-zA-Z0-9]{0,36}$' + }, + 'models': { + 'type': 'list', + 'required': False, + 'schema': { + 'type': 'dict', + 'required': False, + 'schema': { + 'code': { + 'type': 'string', + 'required': True, + 'empty': False, + 'dependencies': 'categories', + 'regex': r'^[a-zA-Z0-9]{1,255}$' + }, + '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', + } + } + } + } + } + } + } +} + +v = Validator(schema, allow_unknown=True) +aa={ + 'request_id': "111", + 'command': 'start', + 'pull_url': None, + 'push_url': None, + 'original_url': '', + 'original_type': '', + 'image_urls': ['1','1'], + 'results_base_dir': '111', + 'models': [ + # { + # 'code': '1', + # 'categories': [ + # # { + # # 'id': '1', + # # 'config': {} + # # } + # ] + # } + ] +} + +print(v.validate(aa)) +print(v.errors) \ No newline at end of file diff --git a/vodsdk/test/validate/__init__.py b/vodsdk/test/validate/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/video.py b/vodsdk/test/video.py new file mode 100644 index 0000000..cb1c8ea --- /dev/null +++ b/vodsdk/test/video.py @@ -0,0 +1,51 @@ +import time +from multiprocessing import Queue +from os import getpid + +import cv2 +import psutil +import requests +from moviepy.editor import VideoFileClip +from pymediainfo import MediaInfo + +# aa = time.time() +# try: +# clip = VideoFileClip("rtmp://192.168.10.101:19350/rlive/stream_107?sign=NQe66OXS") +# print("分辨率:", clip.size) +# print("帧率:", clip.fps) +# print("持续时间:", clip.duration) +# except: +# pass +# print(time.time() - aa) +# aa = time.time() +# cap = cv2.VideoCapture("rtmp://192.168.10.101:19350/rlive/stream_123?sign=w6RNKsFF") +# width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) +# height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) +# total_frames = int(cap.get(7)) +# fps = cap.get(cv2.CAP_PROP_FPS) +# duration = cap.get(cv2.CAP_PROP_POS_MSEC) / 1000 +# cap.release() +# print("分辨率:", (width, height)) +# print("帧率:", fps) +# print("持续时间:", duration) +# print("总帧数:", total_frames) +# print(time.time() - aa) +# aa = Queue() +# for i in range(1000): +# aa.put("1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +# "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" +# "11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111") +# aa.cancel_join_thread() +# aa.cancel_join_thread() +# aa.close() +# aa.cancel_join_thread() +# aa.cancel_join_thread() +# aa.close() +# aa.cancel_join_thread() +# aa.cancel_join_thread() +# aa.get() +# aa = time.time() +# psutil.Process(getpid()).ppid() +# print(time.time()-aa) + + diff --git a/vodsdk/test/webrtc/__init__.py b/vodsdk/test/webrtc/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/webrtc/test.py b/vodsdk/test/webrtc/test.py new file mode 100644 index 0000000..d2f59e3 --- /dev/null +++ b/vodsdk/test/webrtc/test.py @@ -0,0 +1,19 @@ +import cv2 +import numpy as np +# 创建VideoCapture对象并打开WebRTC视频流 +cap = cv2.VideoCapture('webrtc://221.230.150.241:10800/rtc/stream_14') +while True: + print(cap.isOpened()) + # 读取视频流的一帧 + ret, frame = cap.read() + if ret: + # 在这里进行帧处理 + # 例如,可以对每一帧进行图像处理、对象检测等操作 + # 显示处理后的帧 + cv2.imshow('Frame', frame) + # 按下'q'键退出循环 + if cv2.waitKey(1) & 0xFF == ord('q'): + break +# 释放VideoCapture对象和窗口 +cap.release() +cv2.destroyAllWindows() \ No newline at end of file diff --git a/vodsdk/test/while/__init__.py b/vodsdk/test/while/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/while/test.py b/vodsdk/test/while/test.py new file mode 100644 index 0000000..07f1cbe --- /dev/null +++ b/vodsdk/test/while/test.py @@ -0,0 +1,24 @@ +import time + +# def aa(): +# while True: +# +# print("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") +# return True +# +# +# # aa() +# +# aa = 810*3/2 +# aa_1 = 810*3//2 +# print(aa==aa_1, aa, aa_1) + +while True: + print("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + time.sleep(2) + num = 1 + while True: + time.sleep(1) + if num == 1: + print("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb") + break diff --git a/vodsdk/test/wifi/__init__.py b/vodsdk/test/wifi/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/wifi/test.py b/vodsdk/test/wifi/test.py new file mode 100644 index 0000000..4075658 --- /dev/null +++ b/vodsdk/test/wifi/test.py @@ -0,0 +1,9 @@ +import subprocess + +result = subprocess.check_output(['netsh', 'wlan', 'show', 'network']) +result = result.decode('gbk') +lst = result.split('\r\n') +lst = lst[4:] +for index in range(len(lst)): + if index % 5 == 0: + print(lst[index]) \ No newline at end of file diff --git a/vodsdk/test/偏函数/__init__.py b/vodsdk/test/偏函数/__init__.py new file mode 100644 index 0000000..fb5e0b5 --- /dev/null +++ b/vodsdk/test/偏函数/__init__.py @@ -0,0 +1,5 @@ +import getopt +import keyword + +print(keyword.kwlist) +print(getopt.__doc__) \ No newline at end of file diff --git a/vodsdk/test/偏函数/cmp_to_key.py b/vodsdk/test/偏函数/cmp_to_key.py new file mode 100644 index 0000000..79933d6 --- /dev/null +++ b/vodsdk/test/偏函数/cmp_to_key.py @@ -0,0 +1,50 @@ +""" +python标准模块functools中的cmp_to_key可以将一个cmp函数变成一个key函数,从而支持自定义排序 +python的列表提供了sort方法,下面是该方法的一个示例 +""" +lst = [(9, 4), (2, 10), (4, 3), (3, 6)] +lst.sort(key=lambda item: item[0]) +print(lst) +""" +sort方法的key参数需要设置一个函数,这个函数返回元素参与大小比较的值,这看起来没有问题,但如果想实现更加复杂的自定义排序,就不那么容易了。 +目前的排序规则是根据元组里第一个元素的大小进行排序,我现在修改规则,如果元组里第一个元素是奇数,就用元组里第一个元素进行排序, +如果元组里第一个元素是偶数,则用这个元组里的第二个元组进行大小比较,面对这样的需求,列表的sort方法无法满足。 +对于这种情形,可以使用functools.cmp_to_key来解决 +""" +from functools import cmp_to_key +lst = [(9, 4), (2, 10), (4, 3), (3, 6)] +def cmp(x, y): + a = x[0] if x[0] % 2 == 1 else x[1] + b = y[0] if y[0] % 2 == 1 else y[1] + return 1 if a > b else -1 if a < b else 0 + +lst.sort(key=cmp_to_key(cmp)) +print(lst) +# 仍然使用sort进行排序,我实现了一个cmp函数,该函数实现了需求中所提到的要求,该函数最终要返回两个元组比较的大小关系,其实cmp_to_key的实现非常简单 + +def cmp_to_key(mycmp): + """Convert a cmp= function into a key= function""" + class K(object): + __slots__ = ['obj'] + def __init__(self, obj): + self.obj = obj + def __lt__(self, other): + return mycmp(self.obj, other.obj) < 0 + def __gt__(self, other): + return mycmp(self.obj, other.obj) > 0 + def __eq__(self, other): + return mycmp(self.obj, other.obj) == 0 + def __le__(self, other): + return mycmp(self.obj, other.obj) <= 0 + def __ge__(self, other): + return mycmp(self.obj, other.obj) >= 0 + __hash__ = None + return K +""" +它在内部定义了一个类K, 并使用我传入的cmp函数完成了比较关系运算符的重载,函数返回的是一个类,而sort函数的key需要的是一个函数, +看起来矛盾,但在python中,这样做完全可行,因为类和函数都是callable的,这里把类当成了函数来用。 +在本篇第一段代码中 +lst.sort(key=lambda item: item[0]) +lambda表达式生成的匿名函数返回的是元组的第一个元素进行大小比较,而现在,cmp_to_key返回的是类K,参与比较的是K的对象, +由于K已经实现了比较关系运算符重载,且算法就是我刚刚实现的cmp函数,这样就最终实现了自定义排序。 +""" diff --git a/vodsdk/test/偏函数/demo.py b/vodsdk/test/偏函数/demo.py new file mode 100644 index 0000000..1fca7a5 --- /dev/null +++ b/vodsdk/test/偏函数/demo.py @@ -0,0 +1,31 @@ +""" +1. 偏函数 +偏函数partial是functools 模块里提供的一个函数。和装饰器对比来理解,装饰器改变了一个函数的行为, +而偏函数不能改变一个函数的行为。偏函数只能根据已有的函数生成一个新的函数,这个新的函数完成已有函数相同的功能, +但是,这个新的函数的部分参数已被偏函数确定下来 + +2. 场景示例 +2.1 常规实现 +为了便于理解,我们构造一个使用场景,假设我们的程序要在dest目录下新建一些文件夹,那么常见的实现功能代码如下 +import os +from os import mkdir +mkdir(os.path.join('./dest', 'dir1')) +mkdir(os.path.join('./dest', 'dir2')) +mkdir(os.path.join('./dest', 'dir3')) +功能很简单,代码很简洁,但是有个小小的不如意之处,每次都是在dest目录下新建文件夹,既然它这么固定,是不是可以不用传递dest参数呢? +2.2 偏函数实现 +import os +from os import mkdir +from functools import partial + +dest_join = partial(os.path.join, './dest') +mkdir(dest_join('dir1')) +mkdir(dest_join('dir2')) +mkdir(dest_join('dir3')) + +dest_join是partial创建出来的一个新的函数,这个函数在执行时会调用os.path.join并将'./dest'作为参数传给join +偏函数将预先确定的参数冻结,起到了缓存的作用,在获得了剩余的参数后,连同之前冻结的确定参数一同传给最终的处理函数。 +虽然看起来代码没有减少,但如果你实际使用就会发现,用了偏函数,免去了反复输入相同参数的麻烦,尤其当这些参数很多很难记忆时 +""" + + diff --git a/vodsdk/test/偏函数/singledispatch.py b/vodsdk/test/偏函数/singledispatch.py new file mode 100644 index 0000000..ff287e8 --- /dev/null +++ b/vodsdk/test/偏函数/singledispatch.py @@ -0,0 +1,39 @@ +from functools import singledispatch + +class Stu(object): + def __init__(self, name): + self.name = name + + def wake_up(self): + print('起床') + +class Police(object): + def __init__(self, name): + self.name = name + + def wake_up(self): + print('起床') + + +@singledispatch +def wake_up(obj): + print('不处理') + + +@wake_up.register(Stu) +def wake_stu(obj): + print('今天周末休息,让孩子们再睡一会') + + +@wake_up.register(Police) +def wake_police(obj): + print('警察很辛苦,又要起床了') + obj.wake_up() + + +stu = Stu('小明') +police = Police('小明爸爸') + +wake_up(stu) +wake_police(police) +wake_up('一个字符串') \ No newline at end of file diff --git a/vodsdk/test/偏函数/wraps.py b/vodsdk/test/偏函数/wraps.py new file mode 100644 index 0000000..74f14e9 --- /dev/null +++ b/vodsdk/test/偏函数/wraps.py @@ -0,0 +1,26 @@ +import time +from functools import wraps + + +def cost(func): + @wraps(func) + def warpper(*args, **kwargs): + t1 = time.time() + res = func(*args, **kwargs) + t2 = time.time() + print(func.__name__ + "执行耗时" + str(t2-t1)) + return res + return warpper + +@cost +def test(sleep_time): + """ + 测试装饰器 + :param sleep_time: + :return: + """ + time.sleep(sleep_time) + + +print(test.__name__) +print(test.__doc__) \ No newline at end of file diff --git a/vodsdk/test/元类/__init__.py b/vodsdk/test/元类/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/元类/demo1.py b/vodsdk/test/元类/demo1.py new file mode 100644 index 0000000..95b9356 --- /dev/null +++ b/vodsdk/test/元类/demo1.py @@ -0,0 +1,121 @@ +# -*- coding: utf-8 -*- +class Test: + pass + +print(type(Test)) +print(type(int)) + +# 结果都为,type就是内置的元类,class关键字定义的所有的类以及内置的类都是由元类type实例化产生。 + +""" + 由于在python3中没有经典类和新式类的区别,因此python3中object是所有类的基类,那内置元类type又是什么? + type是object类的类型,总结来说就是type是object的类型,同时,object又是type的基类,这句话看起来就有问题, + 到底是先有type还是先有object呢?这个问题有点类似于先有鸡还是先有蛋,我们可以通过代码简单分析一下 + + 在python3中类和类型是同一种东西,因此对象.__class__和type(对象)得到的结果是一致的,object的基类为空, + 但是type的基类为object,但是object的类型又是type。 +""" +print(type(object)) +print(object.__class__) + +print(type(type)) +print(type.__class__) + +print(object.__bases__) +print(type.__bases__) + +# python字符串 +strs = """ +global name +global age +name = 'py' +age = 18 +addr = 'xx' +""" +# 定义全局作用域中的名字和值 +globals = { + 'a': '1', + 'b': '2' +} +# 定义局部作用域中的名字和值 +locals = { + 'x': 3, + 'y': 4 +} +exec(strs, globals, locals) +print(globals['name']) +print(locals) + +# 了解了exec的作用之后,就可以分析class关键字如何借助type元类产生类的步骤: +# 1 定义类名 +class_name = 'Test' + +# 2 定义类的基类(父类) +class_bases = (object,) + +# 3 执行类体代码拿到类的名称空间 +class_dic = {} + +# 4 定义类体代码(本质是字符串) +class_body = """ +def __init__(self,name,age): + self.name=name + self.age=age + +def test(self): + print('%s:%s' %(self.name,self.name)) +""" +# 5 将字符串转为python能识别的语法:将class_body运行时产生的名字存入class_dic中 +exec(class_body, {}, class_dic) +# 查看类的名称空间 +print(class_dic) +# 6 调用元类产生类 +Test = type(class_name, class_bases, class_dic) +# 7 调用类产生对象 +t = Test('python', '12') +t.test() + +# 自定义元类 +class MyMeta(type): # 自定义元类必须继承type,否则就是普通的类 + + ''' + 早于__init__方法执行,必须返回空对象,由于该方法是调用类后第一个运行的方法, + 此时并没有对象产生,因此该方法的第一个参数必须是类本身(MyMeta),*args, **kwargs + 用来接收调用元类产生对象所需的参数(类名 类的基类 名称空间) + ''' + def __new__(cls, *args, **kwargs): + return type.__new__(cls, *args, **kwargs) # 直接调用父类type中的__new__方法 + + ''' + 通过__init__控制类的产生,调用自定义元类与调用内置元类type的方式相同, + 需要传入类名、类的父类们、类体代码的名称空间,__init__方法中第一个参数来自于__new__方法产生的空对象。 + ''' + def __init__(self, class_name, class_bases, class_dict): + + ''' + 在该方法内可以控制类的产生 + ''' + if not class_name.istitle(): # 实现类名首字母必须大写,否则抛出异常 + raise NameError('类名的首字母必须大写') + + if '__doc__' not in class_dict or len(class_dict['__doc__'].strip())==0: # 实现类必须有文档注释,否则抛出异常 + raise TypeError('必须有文档注释') + + def __call__(self, *args, **kwargs): + print(self) + print(args) + print(kwargs) + return 'test' + +class Test(metaclass=MyMeta): + + ''' + 我是文档注释 + ''' + + def __init__(self): + self.name = 'python' + + def test(self): + print('test') +t = Test() \ No newline at end of file diff --git a/vodsdk/test/内存优化/slots/test.py b/vodsdk/test/内存优化/slots/test.py new file mode 100644 index 0000000..d9c3f06 --- /dev/null +++ b/vodsdk/test/内存优化/slots/test.py @@ -0,0 +1,49 @@ +import sys +import time +from collections import namedtuple + +from memory_profiler import profile + +class A: + + __slots__ = ('_name', '_age', '_score') + + def __init__(self, name=None, age=None, score=None): + self._name = 'aaaa' + self._age = 'vbba' + self._score = '1111' + + def test1(self): + num =1 + while True: + num = num + 1 + if num > 1000000: + break + ddd=self._name + for i in range(100): + ddd + +class B(A): + # __slots__ = () + def __init__(self): + super().__init__() + + def test(self): + print(self._name) +a= A() +b = B() +b.test() +# print(b._name) +# print(sys.getsizeof(a), sys.getsizeof(b)) +# print(sys.getsizeof(a.__dict__), sys.getsizeof(b.__dict__)) +@profile +def main(): + Point = namedtuple('Point', ('x', 'y', 'z')) + object_list = [Point(i,i,i) for i in range(100000)] + +if __name__=='__main__': + # main() + # print(A().__dict__) + ss = time.time() + A().test1() + print(time.time() - ss) \ No newline at end of file diff --git a/vodsdk/test/内存优化/slots/test1.py b/vodsdk/test/内存优化/slots/test1.py new file mode 100644 index 0000000..048a562 --- /dev/null +++ b/vodsdk/test/内存优化/slots/test1.py @@ -0,0 +1,200 @@ +# # # import timeit +# # # class MyClass: +# # # @staticmethod +# # # def my_static_method(): +# # # pass +# # # def my_function(): +# # # pass +# # # # 通过类名调用静态方法 +# # # def test_static_method(): +# # # MyClass.my_static_method() +# # # # 通过函数名调用函数方法 +# # # def test_function(): +# # # my_function() +# # # # 测试执行速度 +# # # print("static method: ", timeit.timeit(test_static_method, number=10000000)) +# # # print("function: ", timeit.timeit(test_function, number=10000000)) +# # import copy +# # import os +# # import pickle +# # import time +# # import timeit +# # import traceback +# # from collections import namedtuple +# # from concurrent.futures import ThreadPoolExecutor +# # from multiprocessing import Queue +# # from threading import Thread +# # +# # import cv2 +# # import psutil +# # +# # # def mu(): +# # # aa ={ +# # # 'half': 1, +# # # 'iou_thres': (1,2,3), +# # # 'allowedList': [1,3], +# # # 'aa': {"1":"2"}, +# # # } +# # # bb = aa.copy() +# # # def mu1(): +# # # aa ={ +# # # 'half': 1, +# # # 'iou_thres': (1,2,3), +# # # 'allowedList': [1,3], +# # # 'aa': {"1":"2"}, +# # # } +# # # # copy.deepcopy(aa) +# # # print(pickle.loads(pickle.dumps(aa))) +# # # mu1() +# # # print("static method1: ", timeit.timeit(mu, number=100000)) +# # # print("static method2: ", timeit.timeit(mu1, number=100000)) +# # +# # +# # # def aa(): +# # # Point = namedtuple('Point', ('x', 'y', 'z')) +# # # aa = Point("1111111111", "22222222222", "333333333333") +# # # aa.x +# # # aa.y +# # # aa.z +# # # def aa1(): +# # # aa = ["1111111111", "22222222222", "333333333333"] +# # # aa[0] +# # # aa[1] +# # # aa[2] +# # # print("static method1: ", timeit.timeit(aa, number=100000)) +# # # print("static method2: ", timeit.timeit(aa1, number=100000)) +# # # aa=[] +# # # aa[28] = "11111" +# # # print(aa) +# # # def aa1(): +# # # # 获取当前进程的父进程的PID +# # # if psutil.pid_exists(psutil.Process(os.getpid()).ppid()): +# # # print("11111") +# # # else: +# # # print("2222") +# # # print("static method2: ", timeit.timeit(aa1, number=100)) +# # # def aa(): +# # # num=1 +# # # while num < 100: +# # # num+=1 +# # # time.sleep(100) +# # # dd = Thread(target=aa, args=()) +# # # dd.setDaemon(True) +# # # dd.start() +# # # try: +# # # dd.join(1) +# # # except Exception: +# # # print(traceback.format_exc()) +# # # a = Queue() +# # # aa = {"aa": "11"} +# # # a.put(aa) +# # # bb = a.get() +# # # bb["aa"] = "2222" +# # # print(aa) +# # # print(bb) +# # +# # +# # # def dd(): +# # # w = ["1111", "2222", "3333"] +# # # a = w[2] +# # # +# # # +# # # def cc(): +# # # aa = {"aa": "1111", "bb": "2222", "cc": "3333"} +# # # t= aa["cc"] +# # # +# # # print("static method1: ", timeit.timeit(dd, number=1000)) +# # # print("static method2: ", timeit.timeit(cc, number=1000)) +# # import numpy as np +# # +# # +# # # # 创建一个numpy数组 +# # # arr1 = np.array([[[1,2,3]], [[2,3, 4]]]) +# # # # 使用copy()方法深度拷贝数组 +# # # arr2 = arr1.copy() +# # # # 修改arr2中的元素 +# # # arr2[0][0][1] = 5 +# # # # 打印arr1和arr2 +# # # print("arr1:", arr1) +# # # print("arr2:", arr2) +# # # def cop2(): +# # # arr1 = np.array([[1, 2], [3, 4]]) +# # # arr2 = arr1 +# # # def cop(): +# # # arr1 = np.array([[1, 2], [3, 4]]) +# # # arr2 = arr1.copy() +# # # def cop1(): +# # # arr1 = np.array([[1, 2], [3, 4]]) +# # # arr2 = copy.deepcopy(arr1) +# # # print("static method1: ", timeit.timeit(cop2, number=1000)) +# # # print("static method1: ", timeit.timeit(cop, number=1000)) +# # # print("static method2: ", timeit.timeit(cop1, number=1000)) +# # +# # # aa = {} +# # # def dd(aa): +# # # aa["aa"] = 1 +# # # +# # # dd(aa) +# # # print(aa) +# # +# # def aa(num): +# # while True: +# # time.sleep(4) +# # num+= 1 +# # raise Exception("1111") +# # +# # +# # def dd(): +# # num = 1 +# # with ThreadPoolExecutor(max_workers=1) as t: +# # ddd = t.submit(aa, num) +# # while True: +# # ddd.result() +# # time.sleep(1) +# # print(num) +# # +# # image = cv2.imread(r'D:\tuoheng\codenew\tuoheng_alg\image\logo.png') +# # image1 = np.array(image) +# # or_result, or_image = cv2.imencode(".jpg", image1) +# # aa = or_image.tobytes() +# # +# # numpy_array = np.frombuffer(aa, dtype=np.uint8) +# # img_bgr = cv2.cvtColor(numpy_array, cv2.COLOR_RGB2BGR) +# # cv2.sh +# # print(img_bgr) +# import os +# import time +# from os import getpid +# +# import psutil +# +# +# from multiprocessing import Process +# +# def fun2(name, pid): +# while True: +# time.sleep(1) +# print("fun2", getpid(), os.getppid(), psutil.Process(getpid()).ppid(), psutil.pid_exists(psutil.Process(getpid()).ppid())) +# +# def fun1(name): +# print('测试%s多进程' %name) +# p = Process(target=fun2,args=('Python',getpid(),)) #实例化进程对象 +# # p.daemon = True +# p.start() +# print("funn1", getpid(), p.pid) +# +# +# +# if __name__ == '__main__': +# p = Process(target=fun1,args=('Python',)) #实例化进程对象 +# # p.daemon = True +# p.start() +# +# +# print('结束测试', os.getpid()) +# +listeningProcesses={"11111": "1111", "2222": "2222"} + +p = list(listeningProcesses.keys()) +p.reverse() +print(p) \ No newline at end of file diff --git a/vodsdk/test/内置函数/__init__.py b/vodsdk/test/内置函数/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/内置函数/test.py b/vodsdk/test/内置函数/test.py new file mode 100644 index 0000000..4f8d0aa --- /dev/null +++ b/vodsdk/test/内置函数/test.py @@ -0,0 +1,11 @@ + + + +# key参数,表示使用指定的方法来比较大小,而不是使用原数据比较大小 +x = (2, 3, 4, 5) +print(max(x)) + +print(max(x, key=lambda z: 1 / z)) + +############################### collections ################################# + diff --git a/vodsdk/test/协程/__init__.py b/vodsdk/test/协程/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/协程/asnyc.py b/vodsdk/test/协程/asnyc.py new file mode 100644 index 0000000..658bc9e --- /dev/null +++ b/vodsdk/test/协程/asnyc.py @@ -0,0 +1,19 @@ +import asyncio +import time + + +async def task(): + print(f"{time.strftime('%H:%M:%S')} task 开始 ") + time.sleep(2) + print(f"{time.strftime('%H:%M:%S')} task 结束") + + +coroutine = task() +print(f"{time.strftime('%H:%M:%S')} 产生协程对象 {coroutine},函数并未被调用") +loop = asyncio.get_event_loop() +print(f"{time.strftime('%H:%M:%S')} 开始调用协程任务") +start = time.time() +loop.run_until_complete(coroutine) +end = time.time() +print(f"{time.strftime('%H:%M:%S')} 结束调用协程任务, 耗时{end - start} 秒") + diff --git a/vodsdk/test/协程/asnyc回调.py b/vodsdk/test/协程/asnyc回调.py new file mode 100644 index 0000000..dee6177 --- /dev/null +++ b/vodsdk/test/协程/asnyc回调.py @@ -0,0 +1,27 @@ +import asyncio +import time + + +async def _task(): + print(f"{time.strftime('%H:%M:%S')} task 开始 ") + time.sleep(2) + print(f"{time.strftime('%H:%M:%S')} task 结束") + return "运行结束" + + +def callback(task): + print(f"{time.strftime('%H:%M:%S')} 回调函数开始运行") + print(f"状态:{task.result()}") + + +coroutine = _task() +print(f"{time.strftime('%H:%M:%S')} 产生协程对象 {coroutine},函数并未被调用") +task = asyncio.ensure_future(coroutine) # 返回task对象 +task.add_done_callback(callback) # 为task增加一个回调任务 +loop = asyncio.get_event_loop() +print(f"{time.strftime('%H:%M:%S')} 开始调用协程任务") +start = time.time() +loop.run_until_complete(task) +end = time.time() +print(f"{time.strftime('%H:%M:%S')} 结束调用协程任务, 耗时{end - start} 秒") + diff --git a/vodsdk/test/协程/协程.py b/vodsdk/test/协程/协程.py new file mode 100644 index 0000000..085e5c0 --- /dev/null +++ b/vodsdk/test/协程/协程.py @@ -0,0 +1,24 @@ +#-*- coding:utf8 -*- +def consumer(): + r = '' + while True: + n = yield r + if not n: + return + print('[CONSUMER]Consuming %s...' % n) + r = '200 OK' + +def producer(c): + # 启动生成器 + c.send(None) + n = 0 + while n < 5: + n = n + 1 + print('[PRODUCER]Producing %s...' % n) + r = c.send(n) + print('[PRODUCER]Consumer return: %s' % r) + c.close() + +if __name__ == '__main__': + c = consumer() + producer(c) \ No newline at end of file diff --git a/vodsdk/test/协程/协程1.py b/vodsdk/test/协程/协程1.py new file mode 100644 index 0000000..de7960f --- /dev/null +++ b/vodsdk/test/协程/协程1.py @@ -0,0 +1,13 @@ +import asyncio + +@asyncio.coroutine +def test(i): + print('test_1', i) + r = yield from asyncio.sleep(1) + print('test_2', i) + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + tasks = [test(i) for i in range(3)] + loop.run_until_complete(asyncio.wait(tasks)) + loop.close() \ No newline at end of file diff --git a/vodsdk/test/协程/协程2.py b/vodsdk/test/协程/协程2.py new file mode 100644 index 0000000..02ff317 --- /dev/null +++ b/vodsdk/test/协程/协程2.py @@ -0,0 +1,49 @@ +# import asyncio +# import threading +# import time +# +# +# async def print_hello(d): +# print("aaaaaaaaaaa") +# await asyncio.sleep(d) +# print("nnnnnnnnnnnnn") +# return 11 +# +# async def print_hello1(d): +# print("ssssssssssssssss") +# await asyncio.sleep(2) +# print("qqqqqqqqqqqqq") +# return 22 +# def aa(d): +# loop = asyncio.new_event_loop() +# asyncio.set_event_loop(loop) +# start = time.time() +# aaaa = loop.run_until_complete(asyncio.gather(print_hello(1), print_hello(2))) +# print(aaaa) +# # aa = loop.run_until_complete(asyncio.wait(tasks1)) +# # asyncio.gather() +# # print(aa[0].pop().result()) +# # asyncio.run(print_hello()) +# # asyncio.run(print_hello1()) +# # async def main(): +# # task = asyncio.create_task(print_hello()) +# # task1 = asyncio.create_task(print_hello1()) +# # # await task +# # # await task1 +# # asyncio.run(main()) +# print("ddddddddddddddddddddddd", time.time() - start) +# +# threading.Thread(target=aa, args=(1,)).start() +# # threading.Thread(target=aa, args=(loop, 2)).start() +# # threading.Thread(target=aa, args=(loop, 2)).start() +# # loop.close() +# # loop.close() +# # 打印结果 +# # cccccccccccccccccccccc +# # aaaaaaaaaaa +# # nnnnnnnnnnnnn +# # ssssssssssssssss +# # qqqqqqqqqqqqq +# # ddddddddddddddddddddddd +a = lambda x: print(x) +a(1) \ No newline at end of file diff --git a/vodsdk/test/协程/协程3.py b/vodsdk/test/协程/协程3.py new file mode 100644 index 0000000..ee60d8b --- /dev/null +++ b/vodsdk/test/协程/协程3.py @@ -0,0 +1,10 @@ +import time +from concurrent.futures import ThreadPoolExecutor +def aa(a): + print("aaaaaa") + time.sleep(2) + +with ThreadPoolExecutor(max_workers=2) as t: + while True: + time.sleep(10) + t.submit(aa, 1) diff --git a/vodsdk/test/协程/协程笔记.py b/vodsdk/test/协程/协程笔记.py new file mode 100644 index 0000000..88aabb5 --- /dev/null +++ b/vodsdk/test/协程/协程笔记.py @@ -0,0 +1,34 @@ +import asyncio +import time + + +async def sleep(delay): + time.sleep(delay) + print("1111") + + +async def say_after(delay, what): + await sleep(delay) + print(what) + +async def main(): + task1 = asyncio.create_task(say_after(1, 'hello')) + task2 = asyncio.create_task(say_after(2, 'world')) + # await task1 + # await task2 + await asyncio.gather(task1, task2) + # await say_after(1, 'hello') + # await say_after(2, 'world') + + +start = time.time() +loop = asyncio.new_event_loop() +print(loop) +asyncio.set_event_loop(loop) +task1 = loop.create_task(say_after(1, 'hello')) +task2 = loop.create_task(say_after(2, 'world')) +loop.run_until_complete(asyncio.wait([task1, task2])) +loop.close() +# asyncio.run(main()) +print(time.time() - start) + diff --git a/vodsdk/test/字典/__init__.py b/vodsdk/test/字典/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/字典/字典.py b/vodsdk/test/字典/字典.py new file mode 100644 index 0000000..aa7c1ed --- /dev/null +++ b/vodsdk/test/字典/字典.py @@ -0,0 +1,12 @@ +# aa = {"aa": "aa", "a1": "a1", "a2": "a2"} +# print(aa.pop("aa")) +# print(aa) + +# b = {"11": "11"} +# c = {"12": "12"} +# b.update(c) +# b.update(c) +# print(b) + +aa = list(range(0, 1, 10)) +print(aa) \ No newline at end of file diff --git a/vodsdk/test/序列化/Test.py b/vodsdk/test/序列化/Test.py new file mode 100644 index 0000000..b5aa431 --- /dev/null +++ b/vodsdk/test/序列化/Test.py @@ -0,0 +1,23 @@ +from loguru import logger +import pickle +from loguru import logger +# 定义一个类 +# class Person: +# def __init__(self, name, age): +# self.name = name +# self.age = age +# +# # 创建一个Person实例 +# person = Person("Alice", 25) +# +# # 使用Loguru的serialize方法将Person实例序列化为字节字符串 +# serialized_person = logger.serialize(person) +# print(serialized_person) +# # 使用pickle库将字节字符串反序列化为Python对象 +# deserialized_person = pickle.loads(serialized_person) +# +# # 输出反序列化后的对象属性 +# print(deserialized_person.name) # Alice +# print(deserialized_person.age) # 25 +aa = {"name": "11111"} +logger.info(aa) \ No newline at end of file diff --git a/vodsdk/test/序列化/__init__.py b/vodsdk/test/序列化/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/序列化/test1.py b/vodsdk/test/序列化/test1.py new file mode 100644 index 0000000..ba03f91 --- /dev/null +++ b/vodsdk/test/序列化/test1.py @@ -0,0 +1,21 @@ +import sys + +import msgpack + +stu = { + 'name': 'lili', + 'age': 18, + 'score': 100 +} + +msg_str = msgpack.packb(stu) +print(msg_str) +print(len(msg_str)) +print(sys.platform) +print(sys.byteorder) +print(sys.modules) +print(sys.thread_info) +print(sys.implementation) +print(sys.hash_info) +print(sys.getwindowsversion()) +print(sys.getrecursionlimit()) \ No newline at end of file diff --git a/vodsdk/test/异常/__init__.py b/vodsdk/test/异常/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/异常/test.py b/vodsdk/test/异常/test.py new file mode 100644 index 0000000..9596ef6 --- /dev/null +++ b/vodsdk/test/异常/test.py @@ -0,0 +1,6 @@ +""" +1. try-except +2. try-except-except +3. try-except-else +4. try-except-finally +""" \ No newline at end of file diff --git a/vodsdk/test/日志/test.py b/vodsdk/test/日志/test.py new file mode 100644 index 0000000..406d2f3 --- /dev/null +++ b/vodsdk/test/日志/test.py @@ -0,0 +1,5 @@ + + +from os import environ + +print("LOGURU_TRACE_NO" not in environ) \ No newline at end of file diff --git a/vodsdk/test/正则/__init__.py b/vodsdk/test/正则/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/正则/__pycache__/re.cpython-38.pyc b/vodsdk/test/正则/__pycache__/re.cpython-38.pyc new file mode 100644 index 0000000..87b35c3 Binary files /dev/null and b/vodsdk/test/正则/__pycache__/re.cpython-38.pyc differ diff --git a/vodsdk/test/正则/demo.py b/vodsdk/test/正则/demo.py new file mode 100644 index 0000000..0d29dcc --- /dev/null +++ b/vodsdk/test/正则/demo.py @@ -0,0 +1,29 @@ +# -*- coding: UTF-8 -*- + +import re +print(re.match('www', 'www.runoob.com').span()) # 在起始位置匹配 +print(re.match('com', 'www.runoob.com')) # 不在起始位置匹配 + +line = "Cats are smarter than dogs"; + +matchObj = re.match(r'dogs', line, re.M|re.I) +if matchObj: + print("match --> matchObj.group() : ", matchObj.group()) +else: + print("No match!!") + +matchObj = re.search(r'dogs', line, re.M|re.I) +if matchObj: + print("search --> searchObj.group() : ", matchObj.group()) +else: + print("No match!!") + +phone = "2004-959-559 # 这是一个国外电话号码" + +# 删除字符串中的 Python注释 +num = re.sub(r'#.*$', "", phone) +print("电话号码是: ", num) + +# 删除非数字(-)的字符串 +num = re.sub(r'\D', "", phone) +print("电话号码是 : ", num) \ No newline at end of file diff --git a/vodsdk/test/正则/re.py b/vodsdk/test/正则/re.py new file mode 100644 index 0000000..f8c1aba --- /dev/null +++ b/vodsdk/test/正则/re.py @@ -0,0 +1,145 @@ +import re +''' +1.匹配某个字符串 +match():只能匹配某个 +''' +# text = 'python python' +# result = re.match('py', text) +# print(result) +# print(result.group()) + +''' +2.点 +匹配任意的某个字符【无法匹配换行符】【必须从开头开始匹配】 +''' +# text = 'python' +# result = re.match('.', text) +# print(result) +# print(result.group()) + +''' +3.\d +匹配任意的数字【除了数字外均无法匹配】 +''' +# text = '1python' +# result = re.match('\d', text) +# print(result) +# print(result.group()) + +''' +4.\D +除了数字外均可匹配【数字均无法匹配】 +''' +# text = 'python' +# result = re.match('\D', text) +# print(result) +# print(result.group()) + +''' +5.\s +匹配空白字符【\n、 \t、 \r 、空格】 +''' +# text = '\npython' +# result = re.match('\s', text) +# print(result) +# print(result.group()) + +''' +6.\w +匹配小写的a-z,大写的A-Z,数字和下划线 +''' +# text = 'python' +# result = re.match('\w', text) +# print(result) +# print(result.group()) + +''' +7.\W +匹配除小写\w之外的所有字符 +''' +# text = '\npython' +# result = re.match('\W', text) +# print(result) +# print(result.group()) + +''' +8.[] ->> 组合的方式 +只要在中括号内的内容均可匹配 +''' +# text = '\npython' +# result = re.match('[\n_]', text) +# print(result) +# print(result.group()) + +''' +9.星号 * +匹配零个或者多个字符 +''' +# text = '139-1234-5678' +# result = re.match('[-\d]*', text) +# print(result) +# print(result.group()) + +''' +10.加号 + +匹配1个或者多个字符 +''' +# text = '139-1234-5678' +# result = re.match('[-\d]+', text) +# print(result) +# print(result.group()) + +''' +11.问号 ? +匹配0个或者匹配1个 +''' +# text = '139-1234-5678' +# result = re.match('[-\d]?', text) +# print(result) +# print(result.group()) + +''' +12. {m,n} 匹配m到n个 +匹配0个或者匹配1个 +''' +# text = '139-1234-5678' +# result = re.match('[-\d]{1,5}', text) +# print(result) +# print(result.group()) + +''' +13. 匹配所有的数字 +''' +# text = '139-1234-5678' +# result = re.match('[-0-9]*', text) +# print(result) +# print(result.group()) + +''' +14. 匹配所有的非数字 +''' +# text = '139-1234-5678' +# result = re.match('[^0-9]*', text) +# print(result) +# print(result.group()) + +# re.match() 必须从字符串开头进行匹配 +# re.search() 从左到右进行字符串的遍历,找到就返回 +# text = 'aapython' +# result = re.match('py', text) +# print(result) +# print(result.group()) + +# text = 'aapython' +# result = re.search('py', text) +# print(result) +# print(result.group()) + +""" +1. 贪婪模式: 正则表达式会尽可能多地匹配字符【默认就是贪婪模式】 +2. 非贪婪模式: 正则表达式会尽可能少地匹配字符【?】 + +转义字符 \ +""" + + diff --git a/vodsdk/test/水印/ORB算法.py b/vodsdk/test/水印/ORB算法.py new file mode 100644 index 0000000..cf98486 --- /dev/null +++ b/vodsdk/test/水印/ORB算法.py @@ -0,0 +1,44 @@ + +# 自定义计算两个图片相似度函数 +import cv2 + + +def img_similarity(img1_path, img2_path): + """ + :param img1_path: 图片1路径 + :param img2_path: 图片2路径 + :return: 图片相似度 + """ + try: + # 读取图片 + img1 = cv2.imread(img1_path, cv2.IMREAD_GRAYSCALE) + img2 = cv2.imread(img2_path, cv2.IMREAD_GRAYSCALE) + + # 初始化ORB检测器 + orb = cv2.ORB_create() + kp1, des1 = orb.detectAndCompute(img1, None) + kp2, des2 = orb.detectAndCompute(img2, None) + + # 提取并计算特征点 + bf = cv2.BFMatcher(cv2.NORM_HAMMING) + + # knn筛选结果 + matches = bf.knnMatch(des1, trainDescriptors=des2, k=2) + + # 查看最大匹配点数目 + good = [m for (m, n) in matches if m.distance < 0.75 * n.distance] + # print(len(good)) + # print(len(matches)) + similary = float(len(good))/len(matches) + print("(ORB算法)两张图片相似度为:%s" % similary) + return similary + + except: + print('无法计算两张图片相似度') + return '0' +if __name__ == '__main__': + name1='image/AI.jpg' + name2='image/AI3.jpg' + # similary 值为0-1之间,1表示相同 + similary = img_similarity(name1, name2) + print(similary) \ No newline at end of file diff --git a/vodsdk/test/水印/__init__.py b/vodsdk/test/水印/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/水印/same1.py b/vodsdk/test/水印/same1.py new file mode 100644 index 0000000..a79fa29 --- /dev/null +++ b/vodsdk/test/水印/same1.py @@ -0,0 +1,46 @@ +import cv2 +import os +from matplotlib import pyplot as plt + +def FLANN(): + + targetPath = 'AI.jpg' + trainingImage = cv2.imread(targetPath, flags=0) + + templatePath = 'image/' + icons = os.listdir(templatePath) + iconMatch= dict({'name': '未识别', 'value': 0}) + for icon in icons: + queryImage = cv2.imread(templatePath + icon, 0) + + sift = cv2.SIFT_create() + kp1, des1 = sift.detectAndCompute(queryImage, None) + kp2, des2 = sift.detectAndCompute(trainingImage, None) + + indexParams = dict(algorithm=0, trees=5) + searchParams = dict(checks=50) + flann = cv2.FlannBasedMatcher(indexParams,searchParams) + matches = flann.knnMatch(des1,des2,k=2) + + matchesMask = [[0,0] for i in range(len(matches))] + matchNumber = 0 + + for i,(m,n) in enumerate(matches): + if m.distance < 0.7 * n.distance: + matchesMask[i] = [1,0] + matchNumber = matchNumber+1 + + drawParams = dict(matchColor = (0,255,0), matchesMask = matchesMask[:50], flags = 0) + resultImage = cv2.drawMatchesKnn(queryImage,kp1,trainingImage,kp2,matches[:50],None,**drawParams) + + if matchNumber > iconMatch['value']: + iconMatch['name'] = icon.split('_')[0] + iconMatch['value'] = matchNumber + + return resultImage, iconMatch + +if __name__ == '__main__': + resultImage, res = FLANN() + # plt.imshow(resultImage) + # plt.show() + print(resultImage, res) diff --git a/vodsdk/test/水印/same2.py b/vodsdk/test/水印/same2.py new file mode 100644 index 0000000..7cec491 --- /dev/null +++ b/vodsdk/test/水印/same2.py @@ -0,0 +1,21 @@ +import cv2 + +target = cv2.imread("image/AI.jpg") + +template = cv2.imread("image/AI1.jpg") + +theight, twidth = template.shape[:2] + +result = cv2.matchTemplate(target,template,cv2.TM_CCOEFF_NORMED) +print(result) +cv2.normalize( result, result, 0, 1, cv2.NORM_MINMAX, -1 ) + +min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(result) +print(min_val, max_val, max_loc) +strmin_val = str(min_val) + +cv2.rectangle(target,min_loc,(min_loc[0]+twidth,min_loc[1]+theight),(0,0,225),2) + +# cv2.imshow("MatchResult----MatchingValue="+strmin_val,target) +# cv2.waitKey() +# cv2.destroyAllWindows() \ No newline at end of file diff --git a/vodsdk/test/水印/same3.py b/vodsdk/test/水印/same3.py new file mode 100644 index 0000000..e1009fd --- /dev/null +++ b/vodsdk/test/水印/same3.py @@ -0,0 +1,18 @@ +import os +import cv2 +# from skimage.measure import compare_ssim +# from skimage.metrics import _structural_similarity +from skimage.metrics import structural_similarity as ssim + + +if __name__ == '__main__': + img00 = cv2.imread('image/AI.jpg') + img10 = cv2.imread('image/AI3.jpg') + img0 = cv2.cvtColor(img00,cv2.COLOR_BGR2GRAY) # 将图像转换为灰度图 + img1 = cv2.cvtColor(img10,cv2.COLOR_BGR2GRAY) # 将图像转换为灰度图 + #进行结构性相似度判断 + # ssim_value = _structural_similarity.structural_similarity(img,img1,multichannel=True) + score= ssim(img0, img1) + print(score) + + diff --git a/vodsdk/test/水印/互信息.py b/vodsdk/test/水印/互信息.py new file mode 100644 index 0000000..00e3eb3 --- /dev/null +++ b/vodsdk/test/水印/互信息.py @@ -0,0 +1,8 @@ +from PIL import Image +from pixelmatch.contrib.PIL import pixelmatch +img_a = Image.open("../image/AI.jpg") +img_b = Image.open("../image/AI3.jpg") +img_diff = Image.new("RGBA", img_a.size) +# note how there is no need to specify dimensions +mismatch = pixelmatch(img_a, img_b, img_diff, includeAA=True) +print(mismatch) \ No newline at end of file diff --git a/vodsdk/test/水印/余弦相似度计算.py b/vodsdk/test/水印/余弦相似度计算.py new file mode 100644 index 0000000..9dcb445 --- /dev/null +++ b/vodsdk/test/水印/余弦相似度计算.py @@ -0,0 +1,97 @@ +## -*- coding: utf-8 -*- +# !/usr/bin/env python +# 余弦相似度计算 +import time + +import cv2 +from PIL import Image +from numpy import average, dot, linalg +# 对图片进行统一化处理 +def get_thum(image, size=(64, 64), greyscale=False): + # 利用image对图像大小重新设置, Image.ANTIALIAS为高质量的 + image = image.resize(size, Image.ANTIALIAS) + if greyscale: + # 将图片转换为L模式,其为灰度图,其每个像素用8个bit表示 + image = image.convert('L') + return image +# 计算图片的余弦距离 +def image_similarity_vectors_via_numpy(image1, image2): + image1 = get_thum(image1) + image2 = get_thum(image2) + images = [image1, image2] + vectors = [] + norms = [] + for image in images: + vector = [] + for pixel_tuple in image.getdata(): + vector.append(average(pixel_tuple)) + vectors.append(vector) + # linalg=linear(线性)+algebra(代数),norm则表示范数 + # 求图片的范数 + norms.append(linalg.norm(vector, 2)) + a, b = vectors + a_norm, b_norm = norms + # dot返回的是点积,对二维数组(矩阵)进行计算 + res = dot(a / a_norm, b / b_norm) + return res + + +#差值感知算法 +def dHash(image): + #缩放9*8 + image=cv2.resize(image,(9,8),interpolation=cv2.INTER_CUBIC) + #转换灰度图 + image=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) + # print(image.shape) + hash=[] + #每行前一个像素大于后一个像素为1,相反为0,生成哈希 + for i in range(8): + for j in range(8): + if image[i,j]>image[i,j+1]: + hash.append(1) + else: + hash.append(0) + return hash + +#计算汉明距离 +def Hamming_distance(hash1,hash2): + num = 0 + for index in range(len(hash1)): + if hash1[index] != hash2[index]: + num += 1 + return num + +if __name__ == '__main__': + # 把图片表示成一个向量,通过计算向量之间的余弦距离来表征两张图片的相似度 0.9760 + image1 = cv2.imread('../image/1.jpg') + image2 = cv2.imread('../image/2.jpg') + # image3 = cv2.imread('image/AI2.jpg') + # image4 = cv2.imread('image/AI3.jpg') + # image5 = cv2.imread('image/AI4.jpg') + # image6 = cv2.imread('a.jpg') + # image7 = cv2.imread('AI.jpg') + hash1 = dHash(image1) + hash2 = dHash(image2) + # hash3 = dHash(image3) + # hash4 = dHash(image4) + # hash5 = dHash(image5) + # hash6 = dHash(image6) + # hash7 = dHash(image7) + start = time.time() + dist = Hamming_distance(hash1, hash2) + #将距离转化为相似度 + similarity = 1 - dist * 1.0 / 64 + # print(dist) + print(similarity, time.time() - start) + # cosin = image_similarity_vectors_via_numpy(image1, image2) + # print('图片余弦相似度', cosin) + # cosin1 = image_similarity_vectors_via_numpy(image1, image3) + # print('图片余弦相似度', cosin1) + # cosin2 = image_similarity_vectors_via_numpy(image1, image4) + # print('图片余弦相似度', cosin2) + # cosin3 = image_similarity_vectors_via_numpy(image1, image5) + # print('图片余弦相似度', cosin3) + # cosin4 = image_similarity_vectors_via_numpy(image5, image6) + # print('图片余弦相似度', cosin4) + # cosin5 = image_similarity_vectors_via_numpy(image1, image6) + # print('图片余弦相似度', cosin5) \ No newline at end of file diff --git a/vodsdk/test/水印/视频添加图片水印1.py b/vodsdk/test/水印/视频添加图片水印1.py new file mode 100644 index 0000000..44de721 --- /dev/null +++ b/vodsdk/test/水印/视频添加图片水印1.py @@ -0,0 +1,46 @@ +import cv2 +import numpy as np + + +def watermark(src_path, mask_path, alpha=1): + # 读取原图 + img = src_path + # 获取原图高和宽度 + h, w = img.shape[0], img.shape[1] + # 读取LOG + mask = mask_path + if w > h: + rate = int(w * 0.1) / mask.shape[1] + else: + rate = int(h * 0.1) / mask.shape[0] + mask = cv2.resize(mask, None, fx=rate, fy=rate, interpolation=cv2.INTER_NEAREST) + mask_h, mask_w = mask.shape[0], mask.shape[1] + mask_channels = cv2.split(mask) + dst_channels = cv2.split(img) + b, g, r, a = cv2.split(mask) + + # 计算mask在图片的坐标 + ul_points = (int(h * 0.9), int(int(w / 2) - mask_w / 2)) + dr_points = (int(h * 0.9) + mask_h, int(int(w / 2) + mask_w / 2)) + for i in range(3): + dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] = dst_channels[i][ + ul_points[0]: dr_points[0], + ul_points[1]: dr_points[1]] * ( + 255.0 - a * alpha) / 255 + dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] += np.array( + mask_channels[i] * (a * alpha / 255), dtype=np.uint8) + dst_img = cv2.merge(dst_channels) + # cv2.imwrite(r'd:\1_1.jpg', dst_img) + return dst_img + +import time +# 导入我们将要使用的logo +logo = "logo.png" +img2 = "a.jpg" +time11 = time.time() +a = watermark(img2, logo) +time12 = time.time() +print(time12-time11) +cv2.imshow("Watermarked Image", a) +cv2.imwrite("watermarked.jpg", a) +cv2.waitKey(100000) diff --git a/vodsdk/test/水印/视频添加文字水印.py b/vodsdk/test/水印/视频添加文字水印.py new file mode 100644 index 0000000..3725767 --- /dev/null +++ b/vodsdk/test/水印/视频添加文字水印.py @@ -0,0 +1,18 @@ +import cv2 +import numpy as np +# 中文乱码,不支持中文 +img=cv2.imread("C:\\Users\\chenyukun\\Pictures\\Camera Roll\\a.jpg") # 导入我们需要添加水印的图片 +# RGB_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) +RGB_img = img +blank_img = np.zeros(shape=(RGB_img.shape[0],RGB_img.shape[1],3), dtype=np.uint8) +font = cv2.FONT_HERSHEY_SIMPLEX +# 添加水印的文字内容 +cv2.putText(blank_img,text='Learn Python',org=(40, 90), + fontFace=font,fontScale= 2, + color=(255,0,0),thickness=10,lineType=cv2.LINE_4) +blended = cv2.addWeighted(src1=RGB_img, alpha=0.7, + src2=blank_img, beta=1, gamma = 2) +cv2.imshow("Watermarked Image", blended) +cv2.imwrite("watermarked.jpg", blended) +cv2.waitKey(100000) +cv2.destroyAllWindows() \ No newline at end of file diff --git a/vodsdk/test/水印/视频添加文字水印1.py b/vodsdk/test/水印/视频添加文字水印1.py new file mode 100644 index 0000000..1eac175 --- /dev/null +++ b/vodsdk/test/水印/视频添加文字水印1.py @@ -0,0 +1,35 @@ +import cv2 +import numpy as np +from PIL import Image, ImageDraw, ImageFont +# PIL添加水印 +def cv2AddChineseText(img, text, position, textColor=(0, 255, 0), textSize=30): + if (isinstance(img, np.ndarray)): # 判断是否OpenCV图片类型 + img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) + # 创建一个可以在给定图像上绘图的对象 + draw = ImageDraw.Draw(img) + # 字体的格式 + fontStyle = ImageFont.truetype( + "../font/simsun.ttc", textSize, encoding="utf-8") + # 绘制文本 + draw.text(position, text, textColor, font=fontStyle) + # 转换回OpenCV格式 + return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR) + +img=cv2.imread("C:\\Users\\chenyukun\\Pictures\\Camera Roll\\a.jpg") # 导入我们需要添加水印的图片 +# RGB_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) +# RGB_img = img +# numpy.zeros(shape,dtype=float,order = 'C') +# np.zeros返回给定形状和类型的新数组,用0填充。 +# shape: int 或 int 的元组 +# dtype: 类型 +# uint8是专门用于存储各种图像的(包括RGB,灰度图像等),范围是从0–255 +# blank_img = np.zeros(shape=(RGB_img.shape[0],RGB_img.shape[1],3), dtype=np.uint8) +# font = cv2.FONT_HERSHEY_TRIPLEX +# 添加水印的文字内容 +# fontScale字体大小 +# cv2.putText(图片img,“文本内容”,(左下角坐标),字体,字体大小,(颜色),线条粗细,线条类型) +frame=cv2AddChineseText(img, "拓恒技术", (123, 123),(0, 255, 0), 30) +cv2.imshow("Watermarked Image", frame) +cv2.imwrite("watermarked.jpg", frame) +cv2.waitKey(100000) +cv2.destroyAllWindows() \ No newline at end of file diff --git a/vodsdk/test/水印/视频添加文字水印2.py b/vodsdk/test/水印/视频添加文字水印2.py new file mode 100644 index 0000000..6145f16 --- /dev/null +++ b/vodsdk/test/水印/视频添加文字水印2.py @@ -0,0 +1,3 @@ +from watermarker.marker import add_mark +add_mark(file="test1.jpg", out="add_mark_test1.jpg", + mark="Python", opacity=0.2, angle=30, space=30) \ No newline at end of file diff --git a/vodsdk/test/水印/视频添加文字水印3.py b/vodsdk/test/水印/视频添加文字水印3.py new file mode 100644 index 0000000..a9f5dd1 --- /dev/null +++ b/vodsdk/test/水印/视频添加文字水印3.py @@ -0,0 +1,114 @@ +import cv2 +from PIL import Image, ImageDraw, ImageFont + +################################# +# 给图片加上水印 +################################# + +class Water: + def __init__(self): + # 颜色对应http://www.yuangongju.com/color + self.color_dict = { + 'white':(255,255,255,255), + 'black':(0,0,0,255), + 'gray':(205,201,201,255), + 'red':(255,0,0,255), + 'yellow':(255,215,0,255), + 'blue':(0,0,170,255), + 'purple':(205,105,201,255), + 'green':(0,205,0,255) + } + + self.position_list = [1,2,3,4] + + def one_water(self, image, text, position=1, fontsize=20, fontcolor='black'): + """ + 普通照片水印 + params: + image:图片 + text:水印文字 + position:水印位置 + 1:左上 + 2:右上 + 3:右下 + 4:左下 + fontsize:字体大小 + fontcolor:字体颜色 + [white, black, gray, red, yellow, blue, purple, green] + """ + if position not in self.position_list: + position = 1 + + h, w = image.size[:2] + + keys = self.color_dict.keys() + if fontcolor not in keys: + fontcolor = 'black' + color = self.color_dict[fontcolor] + fnt = ImageFont.truetype('../font/simsun.ttc', fontsize) + + im = image.convert('RGBA') + mask = Image.new('RGBA', im.size, (0,0,0,0)) + + d = ImageDraw.Draw(mask) + + size_h, size_w = d.textsize(text, font=fnt) + + alpha = 5 + if position == 1: + weizhi = (0 + alpha, 0 + alpha) + elif position == 2: + weizhi = (h - size_h - alpha, 0 + alpha) + elif position == 3: + weizhi = (h - size_h - alpha, w - size_w - alpha) + else: + weizhi = (0 + alpha, w - size_w - alpha) + + # position 为左上角位置 + d.text(weizhi, text, font=fnt, fill=color) + out = Image.alpha_composite(im, mask) + return out + + def fill_water(self, image, text, fontsize): + """ + 半透明水印,布满整张图,并且自动旋转45° + params: + image:图片 + text:文字 + fontsize:文字大小 + """ + font = ImageFont.truetype('../font/simsun.ttc', fontsize) + + # 添加背景 + new_img = Image.new('RGBA', (image.size[0] * 3, image.size[1] * 3), (255, 255, 255, 255)) + new_img.paste(image, image.size) + + # 添加水印 + font_len = len(text) + rgba_image = new_img.convert('RGBA') + text_overlay = Image.new('RGBA', rgba_image.size, (0, 0, 0, 0)) + image_draw = ImageDraw.Draw(text_overlay) + + for i in range(0, rgba_image.size[0], font_len*40+100): + for j in range(0, rgba_image.size[1], 200): + # print(f'i:{i}, j:{j}, text:{text}, font:{font}') + image_draw.text((i, j), text, font=font, fill=(0, 0, 0, 50)) + text_overlay = text_overlay.rotate(-45) + image_with_text = Image.alpha_composite(rgba_image, text_overlay) + + image_with_text = image_with_text.crop((image.size[0], image.size[1], image.size[0] * 2, image.size[1] * 2)) + return image_with_text + + +if __name__ == '__main__': + img = Image.open("../a.jpg") + fontcolor = 'yellow' + + water = Water() + text = "hello world" + + fill_img = water.fill_water(img, text, fontsize=36) + # 一定要保存为png格式 + fill_img.save(u'aa.png') + + print('finish') \ No newline at end of file diff --git a/vodsdk/test/游戏/Food.py b/vodsdk/test/游戏/Food.py new file mode 100644 index 0000000..87bd5d9 --- /dev/null +++ b/vodsdk/test/游戏/Food.py @@ -0,0 +1,62 @@ +import pygame + +STEP = 44 + + +class Food(): + def __init__(self, x, y, surface): + self.x = x * STEP + self.y = y * STEP + self.surface = surface + self.image = pygame.image.load("food.png").convert() + + def draw(self): + self.surface.blit(self.image, (self.x, self.y)) + +class Snake(): + def __init__(self, x, y, surface): + self.x = [x*STEP] + self.y = [y*STEP] # 用两个列表来存储贪吃蛇每个节点的位置 + self.length = 1 # 贪吃蛇的长度 + self.direction = 0 # 0表示向右, 1表示向下, 2表示向左, 3表示向上 + self.image = pygame.image.load("snake.png").convert() # 加载蛇 + self.surface = surface + self.step = 44 # 运动步长 + self.updateCount = 0 # 更新次数 + + # 虽然有这么多节点,但是有length来控制界面上画出多少蛇的节点 + for i in range(1, 100): + self.x.append(-100) + self.y.append(-100) + + def draw(self): + for i in range(self.length): + self.surface.blit(self.image, (self.x[i],self.y[i])) + + def moveRight(self): + self.direction = 0 + + def moveLeft(self): + self.direction = 2 + + def moveUp(self): + self.direction = 3 + + def moveDown(self): + self.direction = 1 + + def update(self): + self.updateCount += 1 + if self.updateCount > 2: + for i in range(self.length-1, 0, -1): + self.x[i] = self.x[i-1] + self.y[i] = self.y[i-1] + if self.direction == 0: + self.x[0] = self.x[0] + self.step # 向右 + if self.direction == 1: + self.y[0] = self.y[0] + self.step # 向下 + if self.direction == 2: + self.x[0] = self.x[0] - self.step # 向左 + if self.direction == 3: + self.y[0] = self.y[0] - self.step # 向上 + self.updateCount = 0 diff --git a/vodsdk/test/游戏/SnakeGame.py b/vodsdk/test/游戏/SnakeGame.py new file mode 100644 index 0000000..40cfae8 --- /dev/null +++ b/vodsdk/test/游戏/SnakeGame.py @@ -0,0 +1,93 @@ +import random + +from pygame.locals import * +import pygame +import time + +from test.游戏.Food import Food, Snake, STEP + + +class SnakeGame(): + def __init__(self): + self.width = 800 + self.height = 600 + self._running = False + + + def init(self): + pygame.init() #初始化所有导入的pygame模块 + # 初始化一个准备显示的窗口或屏幕 + self._display_surf = pygame.display.set_mode((self.width,self.height), pygame.HWSURFACE) + self.food = Food(5, 5, self._display_surf) + self.snake = Snake(1, 1, self._display_surf) + self._running = True + + def run(self): + self.init() + while self._running: + pygame.event.pump() # 内部处理pygame事件处理程序 + self.listen_keybord() # 监听键盘上下左右键 + self.loop() + self.render() + time.sleep(0.05) + + def listen_keybord(self): + keys = pygame.key.get_pressed() + + if (keys[K_RIGHT]): + self.snake.moveRight() + + if (keys[K_LEFT]): + self.snake.moveLeft() + + if (keys[K_UP]): + self.snake.moveUp() + + if (keys[K_DOWN]): + self.snake.moveDown() + + if (keys[K_ESCAPE]): + self._running = False + + def render(self): + self._display_surf.fill((0, 0, 0)) # 游戏界面填充为黑色 + self.food.draw() # 画出食物 + self.snake.draw() # 画出蛇 + pygame.display.flip() # 刷新屏幕 + + + def loop(self): + self.snake.update() + self.eat() + self.faild_check() + + def faild_check(self): + # 检查是否吃到了自己 + for i in range(2,self.snake.length): + if self.isCollision(self.snake.x[0], self.snake.y[0], self.snake.x[i], self.snake.y[i],40): + print('吃到自己了') + exit(0) + + if self.snake.x[0] < 0 or self.snake.x[0] > self.width \ + or self.snake.y[0] < 0 or self.snake.y[0] > self.height: + print('出边界了') + exit(0) + + def eat(self): + if self.isCollision(self.food.x, self.food.y, self.snake.x[0], self.snake.y[0], 40): + self.food.x = random.randint(2, 9)*STEP + self.food.y = random.randint(2, 9)*STEP + self.snake.length += 1 # 蛇的长度加1 + + + + @staticmethod + def isCollision(x1, y1, x2, y2, bsize): + if x1 >= x2 and x1 <= x2 + bsize: + if y1 >= y2 and y1 <= y2 + bsize: + return True + return False + +if __name__ == '__main__': + snake = SnakeGame() + snake.run() \ No newline at end of file diff --git a/vodsdk/test/游戏/__init__.py b/vodsdk/test/游戏/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/游戏/__pycache__/Food.cpython-38.pyc b/vodsdk/test/游戏/__pycache__/Food.cpython-38.pyc new file mode 100644 index 0000000..7b7e5bb Binary files /dev/null and b/vodsdk/test/游戏/__pycache__/Food.cpython-38.pyc differ diff --git a/vodsdk/test/游戏/__pycache__/__init__.cpython-38.pyc b/vodsdk/test/游戏/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..4e8a265 Binary files /dev/null and b/vodsdk/test/游戏/__pycache__/__init__.cpython-38.pyc differ diff --git a/vodsdk/test/游戏/food.png b/vodsdk/test/游戏/food.png new file mode 100644 index 0000000..88c7eed Binary files /dev/null and b/vodsdk/test/游戏/food.png differ diff --git a/vodsdk/test/游戏/snake.png b/vodsdk/test/游戏/snake.png new file mode 100644 index 0000000..2f387e0 Binary files /dev/null and b/vodsdk/test/游戏/snake.png differ diff --git a/vodsdk/test/算法/__init__.py b/vodsdk/test/算法/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/算法/冒泡.py b/vodsdk/test/算法/冒泡.py new file mode 100644 index 0000000..3d99c98 --- /dev/null +++ b/vodsdk/test/算法/冒泡.py @@ -0,0 +1,20 @@ + +def pop_sort(lst): + for i in range(len(lst)-1, 0, -1): + move_max(lst, i) + + +def move_max(lst, max_index): + for i in range(max_index): + if lst[i] > lst[i+1]: + lst[i], lst[i+1] = lst[i+1], lst[i] + +if __name__ == '__main__': + lst = [4, 1, 7, 2, 3, 6] + # pop_sort(lst) + # print(lst) + for j in range(len(lst) - 1, 0, -1): + for i in j: + if lst[i] > lst[i+1]: + lst[i], lst[i+1] = lst[i+1], lst[i] + diff --git a/vodsdk/test/算法/插入.py b/vodsdk/test/算法/插入.py new file mode 100644 index 0000000..8b53829 --- /dev/null +++ b/vodsdk/test/算法/插入.py @@ -0,0 +1,21 @@ +def insert(lst, index): + if lst[index-1] < lst[index]: + return + + tmp = lst[index] + tmp_index = index + while tmp_index > 0 and lst[tmp_index-1] > tmp: + lst[tmp_index] = lst[tmp_index-1] + tmp_index -= 1 + lst[tmp_index] = tmp + + +def insert_sort(lst): + for i in range(1, len(lst)): + insert(lst, i) + + +if __name__ == '__main__': + lst = [1, 6, 2, 7, 5] + insert_sort(lst) + print(lst) \ No newline at end of file diff --git a/vodsdk/test/算法/选择.py b/vodsdk/test/算法/选择.py new file mode 100644 index 0000000..35f7aa7 --- /dev/null +++ b/vodsdk/test/算法/选择.py @@ -0,0 +1,21 @@ +""" +假设有一个序列,a[0],a[1],a[2]...a[n]现在,对它进行排序。我们先从0这个位置到n这个位置找出最小值,然后将这个最小值与a[0]交换, +然后呢,a[1]到a[n]就是我们接下来要排序的序列 +我们可以从1这个位置到n这个位置找出最小值,然后将这个最小值与a[1]交换,之后,a[2]到a[n]就是我们接下来要排序的序列 +每一次,我们都从序列中找出一个最小值,然后把它与序列的第一个元素交换位置,这样下去,待排序的元素就会越来越少,直到最后一个 +""" + + +def select_sort(lst): + for i in range(len(lst)): + min = i + for j in range(min, len(lst)): + # 寻找min 到len(lst)-1 这个范围内的最小值 + if lst[min] > lst[j]: + min = j + lst[i], lst[min] = lst[min], lst[i] + + +lst = [2, 6, 1, 8, 2, 4, 9] +select_sort(lst) +print(lst) diff --git a/vodsdk/test/类型标注/__init__.py b/vodsdk/test/类型标注/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/类型标注/test.py b/vodsdk/test/类型标注/test.py new file mode 100644 index 0000000..043c7ac --- /dev/null +++ b/vodsdk/test/类型标注/test.py @@ -0,0 +1,18 @@ + +from typing import Optional, Union, Any, Set + + +a: int = 8 +b: bool = True +c: str = 'ok' +d: Optional[Union[int, float]] = None +e: float = 9.8 +f: bytes = b'32' + +d = 5 +d = 9.8 +d = None + +s: Set[int] = {1, 2, '3'} +for ss in s: + print(ss) \ No newline at end of file diff --git a/vodsdk/test/类型标注/test1.py b/vodsdk/test/类型标注/test1.py new file mode 100644 index 0000000..1e85ec1 --- /dev/null +++ b/vodsdk/test/类型标注/test1.py @@ -0,0 +1,29 @@ +from typing import TypeVar, Generic, List + + +T = TypeVar('T') + + +class Stack(Generic[T]): + def __init__(self): + self.data: List[T] = [] + + def push(self, item: T): + self.data.append(item) + + def pop(self) -> T: + return self.data.pop(-1) + + def top(self) -> T: + return self.data[-1] + + def size(self) -> int: + return len(self.data) + + def is_empty(self) -> bool: + return len(self.data) == 0 + +stack = Stack[int]() +stack.push('3') +stack.push('5') +print(stack.pop()) diff --git a/vodsdk/test/线程/Test.py b/vodsdk/test/线程/Test.py new file mode 100644 index 0000000..e4fce2e --- /dev/null +++ b/vodsdk/test/线程/Test.py @@ -0,0 +1,61 @@ +# -*- coding: utf-8 -*- +import threading +import time +from concurrent.futures import ThreadPoolExecutor, ALL_COMPLETED, wait + + +class Test(object): + def __init__(self): + # threading.Thread.__init__(self) + self._sName = "machao" + + def process(self): + #args是关键字参数,需要加上名字,写成args=(self,) + th1 = threading.Thread(target=self.buildList, args=()) + th1.start() + th1.join() + + def buildList(self): + while True: + print("start") + print(self._sName) + self._sName = "1111111" + time.sleep(3) +def bb(): + print("!1111111111") + +def aa(aa): + print(aa) + time.sleep(5) + return "1111" + + +# test = Test() +# test.process() +# print(3//2) +# with ThreadPoolExecutor(max_workers=10) as t: +# aa = t.submit(aa, "aaa") +# results = wait([aa], timeout=60, return_when=ALL_COMPLETED) +# completed_futures = results.done +# for f in completed_futures: +# if f.exception(): +# raise f.exception() +# else: +# print(f"Task {f.result()} succeeded") +def test1(message): + while True: + time.sleep(1) + print(message) + +message = {"a": "1", "b": "2", "c": "3"} + +aa = message +print(aa is message) +message = None +print(aa) +print(message) +# with ThreadPoolExecutor(max_workers=10) as t: +# t.submit(test1, message) +# print("1111111111111111111111111111111") +# del message +# print("aaa", message) \ No newline at end of file diff --git a/vodsdk/test/线程/Test1.py b/vodsdk/test/线程/Test1.py new file mode 100644 index 0000000..aed2903 --- /dev/null +++ b/vodsdk/test/线程/Test1.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +import time +from multiprocessing import Queue + +def get_no_block_queue(queue): + try: + return queue.get(block=False) + except Exception: + return None + +def clear_queue(queue, is_close=False): + while True: + if queue.empty() or queue.qsize() == 0: + if is_close: + queue.close() + break + r = get_no_block_queue(queue) + del r + +aa = Queue(10) +aa.put("111") +aa.put("111") +aa.cancel_join_thread() +time.sleep(2) +clear_queue(aa, is_close=True) +clear_queue(aa, is_close=True) +print("111111") \ No newline at end of file diff --git a/vodsdk/test/装饰器/装饰器.py b/vodsdk/test/装饰器/装饰器.py new file mode 100644 index 0000000..9c6a5e0 --- /dev/null +++ b/vodsdk/test/装饰器/装饰器.py @@ -0,0 +1,18 @@ +import functools + + +def log(text): + def decorator(func): + @functools.wraps(func) + def wrapper(*args, **kw): + print('%s %s():' % (text, func.__name__)) + return func(*args, **kw) + return wrapper + return decorator + +@log('execute') +def now(): + print('2015-3-25') + +now = log('execute')(now) +print(now.__name__) \ No newline at end of file diff --git a/vodsdk/test/设计模式/__init__.py b/vodsdk/test/设计模式/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/设计模式/单例/__init__.py b/vodsdk/test/设计模式/单例/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/设计模式/单例/__pycache__/single.cpython-38.pyc b/vodsdk/test/设计模式/单例/__pycache__/single.cpython-38.pyc new file mode 100644 index 0000000..451a7be Binary files /dev/null and b/vodsdk/test/设计模式/单例/__pycache__/single.cpython-38.pyc differ diff --git a/vodsdk/test/设计模式/单例/demo2.py b/vodsdk/test/设计模式/单例/demo2.py new file mode 100644 index 0000000..4457e30 --- /dev/null +++ b/vodsdk/test/设计模式/单例/demo2.py @@ -0,0 +1,24 @@ +# -*- coding: utf-8 -*- +from threading import RLock + +class SingletonType(type): + single_lock = RLock() + + def __call__(cls, *args, **kwargs): # 创建cls的对象时候调用 + with SingletonType.single_lock: + if not hasattr(cls, "_instance"): + cls._instance = super(SingletonType, cls).__call__(*args, **kwargs) # 创建cls的对象 + + return cls._instance + + +class Singleton(metaclass=SingletonType): + def __init__(self, name): + self.name = name + + +single_1 = Singleton('第1次创建') +single_2 = Singleton('第2次创建') + +print(single_1.name, single_2.name) # 第1次创建 第1次创建 +print(single_1 is single_2) \ No newline at end of file diff --git a/vodsdk/test/设计模式/单例/demo3.py b/vodsdk/test/设计模式/单例/demo3.py new file mode 100644 index 0000000..658575c --- /dev/null +++ b/vodsdk/test/设计模式/单例/demo3.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +from threading import RLock +single_lock = RLock() + +def Singleton(cls): + instance = {} + + def _singleton_wrapper(*args, **kargs): + with single_lock: + if cls not in instance: + instance[cls] = cls(*args, **kargs) + return instance[cls] + + return _singleton_wrapper + + +@Singleton +class SingletonTest(object): + def __init__(self, name): + self.name = name + + +slt_1 = SingletonTest('第1次创建') +print(slt_1.name) +slt_2 = SingletonTest('第2次创建') +print(slt_1.name, slt_2.name) + +print(slt_1 is slt_2) diff --git a/vodsdk/test/设计模式/单例/demo4.py b/vodsdk/test/设计模式/单例/demo4.py new file mode 100644 index 0000000..21f9aaa --- /dev/null +++ b/vodsdk/test/设计模式/单例/demo4.py @@ -0,0 +1,18 @@ +from threading import RLock +class Singleton(object): + single_lock = RLock() + + def __init__(self, name): + self.name = name + + @classmethod + def instance(cls, *args, **kwargs): + with Singleton.single_lock: + if not hasattr(Singleton, "_instance"): + Singleton._instance = Singleton(*args, **kwargs) + return Singleton._instance + +single_1 = Singleton.instance('第1次创建') +single_2 = Singleton.instance('第2次创建') + +print(single_1 is single_2) # True \ No newline at end of file diff --git a/vodsdk/test/设计模式/单例/demo5.py b/vodsdk/test/设计模式/单例/demo5.py new file mode 100644 index 0000000..c1052c7 --- /dev/null +++ b/vodsdk/test/设计模式/单例/demo5.py @@ -0,0 +1,22 @@ +from threading import RLock + +class Singleton(object): + single_lock = RLock() + + def __init__(self, name): + if hasattr(self, 'name'): + return + self.name = name + + def __new__(cls, *args, **kwargs): + with Singleton.single_lock: + if not hasattr(Singleton, "_instance"): + Singleton._instance = object.__new__(cls) + + return Singleton._instance + +single_1 = Singleton('第1次创建') +single_2 = Singleton('第2次创建') + +print(single_1.name, single_2.name) # 第2次创建 第2次创建 +print(single_1 is single_2) # True \ No newline at end of file diff --git a/vodsdk/test/设计模式/单例/single.py b/vodsdk/test/设计模式/单例/single.py new file mode 100644 index 0000000..16aae96 --- /dev/null +++ b/vodsdk/test/设计模式/单例/single.py @@ -0,0 +1,15 @@ + + +class DbSingleton(): + def __init__(self, host, port, username, password): + self.host = host + self.port = port + self.username = username + self.password = password + self.pool = None # 连接池 + + def connect(self): + print("建立连接") + + +db_singleton = DbSingleton('host', 'port', 'username', 'password') \ No newline at end of file diff --git a/vodsdk/test/设计模式/单例/test.py b/vodsdk/test/设计模式/单例/test.py new file mode 100644 index 0000000..89f104f --- /dev/null +++ b/vodsdk/test/设计模式/单例/test.py @@ -0,0 +1,7 @@ + +from single import db_singleton + +if __name__ == '__main__': + print(id(db_singleton)) + print(id(db_singleton)) + print(id(db_singleton)) \ No newline at end of file diff --git a/vodsdk/test/设计模式/简单工厂模式/__init__.py b/vodsdk/test/设计模式/简单工厂模式/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/设计模式/简单工厂模式/demo.py b/vodsdk/test/设计模式/简单工厂模式/demo.py new file mode 100644 index 0000000..db78dc8 --- /dev/null +++ b/vodsdk/test/设计模式/简单工厂模式/demo.py @@ -0,0 +1,36 @@ +from abc import ABC, abstractmethod + + +class Fruit(ABC): + def __init__(self, name): + self.name = name + + @abstractmethod + def make_juice(self): + pass + + +class Apple(Fruit): + def make_juice(self): + print(f"制作{self.name}汁") + + +class Grape(Fruit): + def make_juice(self): + print(f"制作{self.name}酒") + + +class FruitFactory(): + @classmethod + def create_fruit(cls, name): + if name == 'apple': + return Apple('苹果') + elif name == 'grape': + return Grape("葡萄") + + +fruit1 = FruitFactory.create_fruit('apple') +fruit1.make_juice() + +fruit2 = FruitFactory.create_fruit('grape') +fruit2.make_juice() \ No newline at end of file diff --git a/vodsdk/test/设计模式/简单工厂模式/demo1.py b/vodsdk/test/设计模式/简单工厂模式/demo1.py new file mode 100644 index 0000000..4c2ddc2 --- /dev/null +++ b/vodsdk/test/设计模式/简单工厂模式/demo1.py @@ -0,0 +1,44 @@ +from abc import ABC, abstractmethod + + +class Fruit(ABC): + def __init__(self, name): + self.name = name + + @abstractmethod + def make_juice(self): + pass + + +class Apple(Fruit): + def make_juice(self): + print(f"制作{self.name}汁") + + +class Grape(Fruit): + def make_juice(self): + print(f"制作{self.name}酒") + + +class AbcFruitFactory(ABC): + @abstractmethod + def create_fruit(self): + pass + + +class AppleFactory(AbcFruitFactory): + def create_fruit(self): + return Apple('苹果') + + +class OrangeFactory(AbcFruitFactory): + def create_fruit(self): + return Grape('葡萄') + + +fruit1 = AppleFactory().create_fruit() +fruit1.make_juice() # 制作苹果汁 + + +fruit2 = OrangeFactory().create_fruit() +fruit2.make_juice() \ No newline at end of file diff --git a/vodsdk/test/语法/__init__.py b/vodsdk/test/语法/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/语法/datetime/__init__.py b/vodsdk/test/语法/datetime/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/语法/datetime/test.py b/vodsdk/test/语法/datetime/test.py new file mode 100644 index 0000000..9d8b583 --- /dev/null +++ b/vodsdk/test/语法/datetime/test.py @@ -0,0 +1,106 @@ +import datetime +import time + +# # 今天的日期 +# print("今天的日期是:", datetime.date.today()) +# +# print("使用时间戳创建日期", datetime.date.fromtimestamp(1234567896)) +# +# print("使用公历序数创建的日期:", datetime.date.fromordinal(1)) +# +# today = datetime.date(year=2020,month=8,day=31) # 使用参数创建日期 +# +# print('date对象的年份:', today.year) +# +# print('date对象的月份:', today.month) +# +# print('date对象的日:', today.day) +# +# print("date对象的struct_time结构为:",today.timetuple()) +# +# print("返回当前公历日期的序数:",today.toordinal()) # 与fromordinal函数作用相反 +# +# print("当前日期为星期(其中:周一对应0):{}".format(today.weekday())) +# +# print("当前日期为星期(其中:周一对应1):{}".format(today.isoweekday())) +# +# print("当前日期的年份、第几周、周几(其中返回为元组):",today.isocalendar()) +# +# print("以ISO 8601格式‘YYYY-MM-DD’返回date的字符串形式:",today.isoformat()) +# +# print("返回一个表示日期的字符串(其格式如:Mon Aug 31 00:00:00 2020):",today.ctime()) +# +# print("指定格式为:",today.strftime("%Y/%m/%d")) +# +# print("替换后的日期为:",today.replace(2019,9,29)) +# +# create_time = datetime.time(hour=11,minute=18,second=31) # 使用参数创建日期 +# +# print('create_time对象的小时为:', create_time.hour) +# +# print('create_time对象的分钟为:', create_time.minute) +# +# print('create_time对象的秒数为:', create_time.second) +# +# print("返回create_time的字符串形式:",create_time.isoformat()) +# +# print("指定格式为:",create_time.strftime("%H/%M/%S")) +# +# print("替换后的时间为:",create_time.replace(20,9,29)) +# +# print("现在的时间是:",datetime.datetime.today()) +# +# print("返回现在的时间是:",datetime.datetime.now()) +# +# print("当前UTC日期和时间是:",datetime.datetime.utcnow()) +# +# print("对应时间戳的日期和时间是:",datetime.datetime.fromtimestamp(1234567896)) +# +# print("对应UTC时间戳的日期和时间是:",datetime.datetime.utcfromtimestamp(1234567896)) +# +# print("公历序列对应的日期和时间是:",datetime.datetime.fromordinal(1)) +# +# print("日期和时间的合体为:",datetime.datetime.combine(datetime.date(2020, 8, 31), datetime.time(12, 12, 12))) +# +# now = datetime.datetime(2020,8,31,12,10,10) +# +# print("年为:",now.year) +# +# print("月为:",now.month) +# +# print("日为:",now.day) +# +# print("小时为:",now.hour) +# +# print("分钟为:",now.minute) +# +# print("秒数为:",now.second) +# +# print('当前日期为:', now.date() ) +# +# print('当前时间:', now.time() ) +# +# print("返回struct_time为",now.timetuple()) # 和date一样 +# +# print("返回UTC的struct_time为",now.utctimetuple()) +# +# print("返回的公历序列数为:",now.toordinal()) # 和date一样 +# +# print("返回标准日期格式为:",now.isoformat()) # 和date一样 +# +# print("返回的周几(1表示周一):",now.isoweekday()) # 和date一样 +# +# print("返回的周几(0表示周一):",now.weekday()) # 和date一样 +# +# print("now.isocalendar():", now.isocalendar()) # 和date一样 +# +# print("now.ctime():",now.ctime()) # 和date一样 +# +# print("格式化时间为:",now.strftime('%Y/%m/%d %H:%M:%S')) # 把日期按照format指定的格式进行格式化 +# +# print(datetime.datetime.strptime("2020/12/29 8:8:00",'%Y/%m/%d %H:%M:%S')) + +current_time = 1577761708 +date_time = datetime.datetime.fromtimestamp(current_time) +print(date_time) +print(time.localtime()) \ No newline at end of file diff --git a/vodsdk/test/语法/for/__init__.py b/vodsdk/test/语法/for/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/语法/for/demo.py b/vodsdk/test/语法/for/demo.py new file mode 100644 index 0000000..15d6bf0 --- /dev/null +++ b/vodsdk/test/语法/for/demo.py @@ -0,0 +1,43 @@ + +magicians = ['alice', 'david', 'carolina'] +for magician in magicians: + print(magician) + +print(0b1101010) + +value = int('1101010', 2) +print(value) # 106 + +value = int('125', 8) +print(value) # 85 + +value = int('3f2a1', 16) +print(value) # 258721 + +print(bin(106)) # 0b1101010 十进制转二进制 +print(oct(85)) # 0o125 十进制转八进制 +print(hex(258721)) # 0x3f2a1 十进制转十六进制 + +text = '1aa2' +print(text.split('a')) + +# 1. 将字符串 "abcd" 转成大写 +print("abcd".upper()) +# 2. 计算字符串 "cd" 在 字符串 "abcd"中出现的位置 +print("abcd".index('cd')) +print("abcd".find('cd')) +# 3. 字符串 "a,b,c,d" ,请用逗号分割字符串,分割后的结果是什么类型的? +print("a,b,c,d".split(',')) +# 4. "{name}喜欢{fruit}".format(name="李雷") 执行会出错,请修改代码让其正确执行 +print("{name}喜欢{fruit}".format(name="李雷", fruit='水果')) +# 5. string = "Python is good", 请将字符串里的Python替换成 python,并输出替换后的结果 +print("Python is good".replace("Python", "python")) +# 6. 有一个字符串 string = "python修炼第一期.html",请写程序从这个字符串里获得.html前面的部分,要用尽可能多的方式来做这个事情 +print("python修炼第一期.html".split('.')[0]) +# 7. 如何获取字符串的长度? +# 8. "this is a book",请将字符串里的book替换成apple +# 9. "this is a book", 请用程序判断该字符串是否以this开头 +# 10. "this is a book", 请用程序判断该字符串是否以apple结尾 +# 11. "This IS a book", 请将字符串里的大写字符转成小写字符 +# 12. "This IS a book", 请将字符串里的小写字符,转成大写字符 +# 13. "this is a book\n", 字符串的末尾有一个回车符,请将其删除 \ No newline at end of file diff --git a/vodsdk/test/语法/list/__init__.py b/vodsdk/test/语法/list/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/语法/list/demo.py b/vodsdk/test/语法/list/demo.py new file mode 100644 index 0000000..c263a8f --- /dev/null +++ b/vodsdk/test/语法/list/demo.py @@ -0,0 +1,34 @@ +bicycles = ['trek', 'cannondale', 'redline', 'specialized'] +print(bicycles) +print(bicycles[0]) +print(bicycles[0].title()) +print(bicycles[-1]) + +motorcycles = ['honda', 'yamaha', 'suzuki'] +print(motorcycles) +motorcycles[0] = 'ducati' +print(motorcycles) +motorcycles.append('ducati') +print(motorcycles) +motorcycles.insert(0, 'ducati') +print(motorcycles) +del motorcycles[0] +print(motorcycles) +popped_motorcycle = motorcycles.pop() +print(motorcycles) +print(popped_motorcycle) + +# 使用方法 sort()对列表进行永久性排序 +cars = ['bmw', 'audi', 'toyota', 'subaru'] +cars.sort() +print(cars) +cars.sort(reverse=True) +print(cars) + +# 使用函数 sorted()对列表进行临时排序 +cars = ['bmw', 'audi', 'toyota', 'subaru'] +print(cars) +print(sorted(cars)) +print(sorted(cars, reverse=True)) +print(cars.reverse()) +print(len(cars)) \ No newline at end of file diff --git a/vodsdk/test/语法/statistics_test/__init__.py b/vodsdk/test/语法/statistics_test/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/语法/statistics_test/test.py b/vodsdk/test/语法/statistics_test/test.py new file mode 100644 index 0000000..8d06314 --- /dev/null +++ b/vodsdk/test/语法/statistics_test/test.py @@ -0,0 +1,16 @@ +import statistics + +lst = [1, 4, 5, 7, 1, 3, 6, 9, 19] + +print(statistics.mean(lst)) # 算数平均值 +print(statistics.harmonic_mean(lst)) # 调和平均值 +print(statistics.median(lst)) # 中位数 +print(statistics.median_low(lst)) # 数据的第一个中位数(总数为偶数时有两个中位数) +print(statistics.median_high(lst)) # 数据的第二个中位数 +print(statistics.median_grouped(lst)) # 分组数据的中位数的均值 +print(statistics.mode(lst)) # 离散数据的模式, 数据中最常见的值 + +print(statistics.pstdev(lst)) # 数据总体的标准差 +print(statistics.pvariance(lst)) # 数据总体的方差 +print(statistics.stdev(lst)) # 数据样本的标准差 +print(statistics.variance(lst)) # 数据样本的方差 \ No newline at end of file diff --git a/vodsdk/test/语法/time/__init__.py b/vodsdk/test/语法/time/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/语法/time/test.py b/vodsdk/test/语法/time/test.py new file mode 100644 index 0000000..6679d15 --- /dev/null +++ b/vodsdk/test/语法/time/test.py @@ -0,0 +1,42 @@ +import time + +# 获取当前时间戳 1685344329.938672 +print(time.time()) + +# 获取当前时间,表示为计算机可处理的时间格式 +print(time.gmtime()) + +# 时间格式化:将时间以合理的方式展示出来 +print(time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime())) +print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))) +print(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) +# +print(time.strptime("2023-05-29 07:21:07", "%Y-%m-%d %H:%M:%S")) + +# 返回一个CPU级别的精确时间计数值, 单位为秒, 由于这个计算值七点不确定,连续调用差值才有意义 +print(time.perf_counter()) + +# 获取当前时间 +print(time.localtime(time.time())) +print(time.localtime()) + +# 接受时间元组并返回一个可读的形式为"Tue Dec 11 18:07:14 2008"(2008年12月11日 周二18时07分14秒)的24个字符的字符串。 +print(time.asctime(time.localtime(time.time()))) +print(time.asctime(time.localtime())) +# 获取当前时间并以易读方式表示,返回字符串 +print(time.ctime()) # Mon May 29 15:16:00 2023 + +# 返回格林威治西部的夏令时地区的偏移秒数。如果该地区在格林威治东部会返回负值(如西欧,包括英国)。对夏令时启用地区才能使用。 +print(time.altzone) + +# +start = time.perf_counter() +start1 = time.process_time() +time.sleep(1) +end = time.perf_counter() +end1 = time.process_time() +print(end - start) +print(end1 - start1) + +# 接受时间对象并返回时间戳(1970纪元后经过的浮点秒数) +print(time.mktime(time.localtime())) diff --git a/vodsdk/test/语法/全局变量.py b/vodsdk/test/语法/全局变量.py new file mode 100644 index 0000000..e51a94a --- /dev/null +++ b/vodsdk/test/语法/全局变量.py @@ -0,0 +1,27 @@ + +def get_mathematical_score(): + return 90 + + +def get_english_score(): + return 95 + + +def get_history_score(): + return 98 + + +def get_score_by_course(course): + """ + 根据课程获取考试分数 + :param course: + :return: + """ + global_dict = globals() + print(global_dict) + func_name = 'get_{course}_score'.format(course=course) + func = global_dict.get(func_name) + return func() + + +print(get_score_by_course('history')) \ No newline at end of file diff --git a/vodsdk/test/语法/全局变量1.py b/vodsdk/test/语法/全局变量1.py new file mode 100644 index 0000000..4cd9eb7 --- /dev/null +++ b/vodsdk/test/语法/全局变量1.py @@ -0,0 +1,51 @@ +def func_dispatch(func): + registry = {} + + def dispatch(key_word): + return registry.get(key_word, registry[object]) + + def register(key_word, func=None): + if func is None: + return lambda f: register(key_word, f) + + registry[key_word] = func + return func + + def wrapper(*args, **kw): + return dispatch(args[0])(*args, **kw) + + registry[object] = func + wrapper.register = register + return wrapper + + +@func_dispatch +def score_dispath(course): + return 0 + + +@score_dispath.register('mathematical') +def get_mathematical_score(course): + return 90 + + +@score_dispath.register('english') +def get_english_score(course): + return 95 + + +@score_dispath.register('history') +def get_history_score(course): + return 98 + + +def get_score_by_course(course): + """ + 根据课程获取考试分数 + :param course: + :return: + """ + return score_dispath(course) + + +print(get_score_by_course('mathematical')) \ No newline at end of file diff --git a/vodsdk/test/语法/回调.py b/vodsdk/test/语法/回调.py new file mode 100644 index 0000000..e7ca18b --- /dev/null +++ b/vodsdk/test/语法/回调.py @@ -0,0 +1,39 @@ +class TestClass(object): + def __init__(self): + self.fun = 0 + + def decorator(self, fun): + #通过fun变量实现对传入函数的回调 + self.fun = fun + #仅注册回调函数,将原函数返回,不执行原函数工鞥呢,不改变原函数功能 + return fun + + def decorator1(self, type): + def wrapper(func): + if type == 'A': + self.fun_A = func + if type == 'B': + self.fun_B = func + return func + return wrapper + +test = TestClass() + +#将decorator_test函数传入test的decorator函数,并执行decorator函数 +@test.decorator +def decorator_test(): + print('this is decorator_test') + +@test.decorator1('A') +def decorator_test(): + print('this is decorator_test A') + +@test.decorator1('B') +def decorator_test(): + print('this is decorator_test B') + +#通过test的fun变量回调decorator_test函数 +test.fun(); + +test.fun_A (); +test.fun_B (); diff --git a/vodsdk/test/语法/装饰器/__init__.py b/vodsdk/test/语法/装饰器/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/读写/__init__.py b/vodsdk/test/读写/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/读写/csv_test.py b/vodsdk/test/读写/csv_test.py new file mode 100644 index 0000000..ef46e6a --- /dev/null +++ b/vodsdk/test/读写/csv_test.py @@ -0,0 +1,29 @@ + +import csv + +import numpy as np + +# with open("data.csv") as f: +# csv_reader = csv.reader(f) +# for row in csv_reader: +# print(row) +# +# import pandas as pd +# df = pd.read_csv("data.csv", encoding="utf-8") +# print(df) +# df_array = np.array(df) # 将pandas读取的数据转化为array +# df_list = df_array.tolist() # 将数组转化为list +# print(df_list) +# x = df[['name', 'age']] +# print(x) +# y = df[['name']] +# print(y) +# def aa(): +# num=3 +# while True: +# if num==3: +# return +# print("aaaaaaaaaa") +# +# aa() +# print("11111111") diff --git a/vodsdk/test/读写/data.csv b/vodsdk/test/读写/data.csv new file mode 100644 index 0000000..0fa4903 --- /dev/null +++ b/vodsdk/test/读写/data.csv @@ -0,0 +1,4 @@ +name,age +1,1 +2,2 +3,3 diff --git a/vodsdk/test/读写/demo.py b/vodsdk/test/读写/demo.py new file mode 100644 index 0000000..8d59536 --- /dev/null +++ b/vodsdk/test/读写/demo.py @@ -0,0 +1,71 @@ +# """ +# 模式 描述 +# r 以只读的形式打开文件,文件的指针在开头 +# r+ 读写,文件指针在开头 +# rb 以二进制的形式,只读文件指针在开头 +# w 只写,文件不存在,则创建新的,存在则覆盖,指针在开头 +# w+ 读写,文件不存在,则创建新的,存在则覆盖,指针在开头 +# wb 只写,以二进制的形式 +# a 追加模式,文件指针在结尾 +# a+ 读写,不存在则创建,存在直接追加 +# ab 以二进制形式追加 +# +# 1. close(): 关闭文件---非常重要 +# 2. read([count]): 读取文件中的内容 count:字节数量 +# 3. readlines(): 读取所有内容,打包成列表 +# 4. readline(): 读取一行数据,追加读取,读取过的不能再次读取 +# 5. seek(offset,[from]): 修改指针的位置:从from位置移动了offset个字节, +# from:0则表示从起始位置,1则表示从当前位置开始,2则表示从末尾开始 +# offset:要移动的字节数 +# 6. write(): 向文件中写入内容 +# """ +import json +import sys +import time +import traceback +from collections import namedtuple +from queue import Queue + +import yaml + +# +# import yaml +# +# +# # 写文件 +# # with open("hello.txt", 'w') as f: +# # f.write("hello world") +# import pandas as pd +# # 读文件 +ss = time.time() +# with open(r"D:\tuoheng\codenew\tuoheng_alg\config\dsp_dev_service.yml",'r', encoding='utf-8') as f: +# data = yaml.safe_load(f) +with open(r"D:\tuoheng\codenew\tuoheng_alg\test\读写\dsp_application.json", 'r', encoding='utf-8') as f: + a = json.loads(f.read()) + print(a) +print(time.time()-ss) +# # try: +# # aa = Queue(1) +# # aa.put(1, timeout=2) +# # aa.put(2, block=True, timeout=5) +# # except Exception as e: +# # traceback_str = traceback.format_exc() +# # print("aaaaaaaaaaaaaa", traceback_str) +# import time +# class a(): +# def __init__(self, value): +# self.value = value +# +# def test(self): +# num = 0 +# aa = self.value +# while True: +# num += 1 +# bb = aa +# if num > 10000000: +# break +# ss = time.time() +# a("1111").test() +# print(time.time()-ss) +envs = ('dev', 'test', 'prod') +print('dev1' in envs) \ No newline at end of file diff --git a/vodsdk/test/读写/dsp_application.json b/vodsdk/test/读写/dsp_application.json new file mode 100644 index 0000000..a47b21d --- /dev/null +++ b/vodsdk/test/读写/dsp_application.json @@ -0,0 +1,234 @@ +{ + "dsp": {"active": "dev"}, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + } +, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + }, + "kafka": { + "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" + } + } +} diff --git a/vodsdk/test/读写/hello.txt b/vodsdk/test/读写/hello.txt new file mode 100644 index 0000000..95d09f2 --- /dev/null +++ b/vodsdk/test/读写/hello.txt @@ -0,0 +1 @@ +hello world \ No newline at end of file diff --git a/vodsdk/test/路径/Test.py b/vodsdk/test/路径/Test.py new file mode 100644 index 0000000..8236e69 --- /dev/null +++ b/vodsdk/test/路径/Test.py @@ -0,0 +1,16 @@ +# import os +# import sys +# +# from util import RWUtils, LogUtils +# from loguru import logger +# print(os.getcwd()) +# +# print(os.path.relpath(__file__)) +# base_dir = os.path.dirname(os.path.realpath(sys.argv[0])) +# content = YmlUtils.getConfigs(base_dir + "/../../") +# LogUtils.init_log(content) +# +# try: +# 2/0 +# except Exception as e: +# logger.exception("异常信息:{}", e) diff --git a/vodsdk/test/路径/__init__.py b/vodsdk/test/路径/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/进程/__init__.py b/vodsdk/test/进程/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/test/进程/test.py b/vodsdk/test/进程/test.py new file mode 100644 index 0000000..cdad406 --- /dev/null +++ b/vodsdk/test/进程/test.py @@ -0,0 +1,34 @@ +import time +from concurrent.futures import ProcessPoolExecutor + +a = 0 + + +def aa(): + global a + # print("aaaaaaaa", a) + time.sleep(3) + a += 1 + +def bb(): + global a + print(a) + +if __name__ == "__main__": + with ProcessPoolExecutor(max_workers=3) as t: + t.submit(aa) + t.submit(bb) + t.submit(aa) + t.submit(bb) + t.submit(aa) + t.submit(bb) + t.submit(aa) + t.submit(bb) + t.submit(aa) + t.submit(bb) + t.submit(aa) + t.submit(bb) + t.submit(aa) + t.submit(bb) + t.submit(aa) + diff --git a/vodsdk/test/进程/test1.py b/vodsdk/test/进程/test1.py new file mode 100644 index 0000000..f151cc9 --- /dev/null +++ b/vodsdk/test/进程/test1.py @@ -0,0 +1,89 @@ +import time +from multiprocessing import Process, Queue + + +def get_no_block_queue(queue): + try: + return queue.get(block=False) + except Exception: + return None + + +class B(Process): + def __init__(self, a, b, c, d): + super().__init__() + self.a = a + self.b = b + self.c = c + self.d = d + + def run(self): + self.a.put("11111111111") + self.b.put("11111111111") + self.c.put("11111111111") + self.d.put("11111111111") + time.sleep(3) + +class D(Process): + def __init__(self, a, b, c, d): + super().__init__() + self.a = a + self.b = b + self.c = c + self.d = d + + def run(self): + self.a.put("11111111111") + self.b.put("11111111111") + self.c.put("11111111111") + self.d.put("11111111111") + time.sleep(3) + + +class C(Process): + def __init__(self, a, b, c, d): + super().__init__() + self.a = a + self.b = b + self.c = c + self.d = d + + def run(self): + self.a.put("1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111") + self.b.put("1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111") + self.c.put("1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111") + self.d.put("1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111") + self.d.cancel_join_thread() + time.sleep(3) + + +class A(Process): + def __init__(self): + super().__init__() + self.a = Queue() + self.b = Queue() + self.c = Queue() + self.d = Queue() + + def run(self): + b = B(self.a, self.b, self.c, self.d) + b.daemon = True + b.start() + c = C(self.a, self.b, self.c, self.d) + c.daemon = True + c.start() + d = D(self.a, self.b, self.c, self.d) + d.daemon = True + d.start() + while True: + time.sleep(1) + print("11111111111111") + #b.join() + print("222222222222222222") + #c.join() + print("333333333333333333") + + +if __name__ == "__main__": + aa = A() + aa.start() diff --git a/vodsdk/test/集合/test.py b/vodsdk/test/集合/test.py new file mode 100644 index 0000000..0b54dd5 --- /dev/null +++ b/vodsdk/test/集合/test.py @@ -0,0 +1,26 @@ +list1 = [1, 2, 3, 4] +list2 = [1,2,4] +if set(list2) == set(list1): + print("1111111") +else: + print("222222") + +import numpy as np + +# list1 = [1, 2, 3, 4] +# tl = np.asarray([1, 2], np.float32) +# box = np.asarray([tl], np.int32) +# print(tl)c +# print(box[0][1]) +import cv2 +# ai_video_file = cv2.VideoWriter(r"C:\Users\chenyukun\Desktop\fsdownload\aa.mp4", cv2.VideoWriter_fourcc(*'mp4v'), 25, +# (1920,1080)) +# # ai_video_file.set(cv2.VIDEOWRITER_PROP_BITRATE, 4000) +# ai_video_file.set(cv2.CAP_PROP_BITRATE, 4000) +# ai_video_file.set(cv2.VIDEOWRITER_PROP_QUALITY, 80) +# print(help(cv2.VideoWriter.set)) +# print(dir(cv2)) +# print(help(cv2)) + +print(bool(0)) +print(False) \ No newline at end of file diff --git a/vodsdk/util/AliyunSdk.py b/vodsdk/util/AliyunSdk.py new file mode 100644 index 0000000..3671b4e --- /dev/null +++ b/vodsdk/util/AliyunSdk.py @@ -0,0 +1,150 @@ +# -*- coding: utf-8 -*- +from json import loads +from os.path import join +from traceback import format_exc + +import oss2 +import time + +from aliyunsdkvod.request.v20170321.GetPlayInfoRequest import GetPlayInfoRequest +from loguru import logger + +from common.YmlConstant import aliyun_yml_path +from exception.CustomerException import ServiceException +from enums.ExceptionEnum import ExceptionType +from aliyunsdkcore.client import AcsClient +from aliyunsdkvod.request.v20170321 import GetPlayInfoRequest + +from util.RWUtils import getConfigs +from vodsdk.AliyunVodUploader import AliyunVodUploader +from vodsdk.UploadVideoRequest import UploadVideoRequest + + +class AliyunOssSdk: + + __slots__ = ('bucket', '__request_id', '__config') + + def __init__(self, *args): + base_dir, env, self.__request_id = args + self.bucket = None + self.__config = getConfigs(join(base_dir, aliyun_yml_path % env)) + self.get_oss_bucket() + + def get_oss_bucket(self): + if self.bucket is None: + auth = oss2.Auth(self.__config["access_key"], self.__config["access_secret"]) + self.bucket = oss2.Bucket(auth, self.__config["oss"]["endpoint"], + self.__config["oss"]["bucket"], + connect_timeout=self.__config["oss"]["connect_timeout"]) + + def put_object(self, updatePath, fileByte): + request_id = self.__request_id + logger.info("开始上传文件到oss, requestId:{}", request_id) + max_retries = 3 + retry_count = 0 + while True: + try: + self.get_oss_bucket() + self.bucket.put_object(updatePath, fileByte) + logger.info("上传文件到oss成功! requestId:{},{}".format( request_id, updatePath)) + return updatePath + break + except Exception as e: + retry_count += 1 + time.sleep(1) + self.bucket = None + logger.info("上传文件到oss失败, 重试次数:{}, requestId:{}", retry_count, request_id) + if retry_count > max_retries: + logger.error("上传文件到oss重试失败:{}, requestId:{}", format_exc(), request_id) + raise e + + +class ThAliyunVodSdk: + + __slots__ = ('__config', '__request_id') + + def __init__(self, base_dir, env, request_id): + self.__request_id = request_id + self.__config = getConfigs(join(base_dir, aliyun_yml_path % env)) + + def init_vod_client(self, accessKeyId, accessKeySecret): + regionId = self.__config["vod"]["ecsRegionId"] + return AcsClient(accessKeyId, accessKeySecret, regionId, auto_retry=True, max_retry_time=3, timeout=30) + + def get_play_info(self, videoId): + logger.info("开始获取视频地址,videoId:{}, requestId:{}", videoId, self.__request_id) + clt = self.init_vod_client(self.__config["access_key"], self.__config["access_secret"]) + start = time.time() + retry_num = 0 + while True: + try: + request: GetPlayInfoRequest = GetPlayInfoRequest.GetPlayInfoRequest() + request.set_accept_format('JSON') + request.set_VideoId(videoId) + request.set_AuthTimeout(3600 * 5) + response = loads(clt.do_action_with_exception(request)) + play_url = response["PlayInfoList"]["PlayInfo"][0]["PlayURL"] + logger.info("获取视频地址成功,视频地址: {}, requestId: {}", play_url, self.__request_id) + return play_url + except Exception as e: + logger.info("获取视频地址失败,5秒后重试, requestId: {}", self.__request_id) + retry_num += 1 + time.sleep(5) + current_time = time.time() + if "HTTP Status: 403" not in str(e) and retry_num > 12: + logger.error("获取视频地址失败: {}, requestId: {}", format_exc(), self.__request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + if "HTTP Status: 403" in str(e) and ("UploadFail" in str(e) or "TranscodeFail" in str(e) or + "ProduceFail" in str(e)): + logger.error("获取视频地址失败: {}, requestId: {}", format_exc(), self.__request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + diff_time = current_time - start + if diff_time > 60 * 60 * 5: + logger.error("获取视频地址失败超时异常: {},超时时间:{}, requestId: {}", format_exc(), + diff_time, self.__request_id) + raise ServiceException(ExceptionType.GET_VIDEO_URL_TIMEOUT_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_TIMEOUT_EXCEPTION.value[1]) + + def upload_local_video(self, filePath, file_title): + logger.info("开始执行vod视频上传, filePath: {}, requestId: {}", filePath, self.__request_id) + uploader = AliyunVodUploader(self.__config["access_key"], self.__config["access_secret"], self.__request_id) + uploadVideoRequest: UploadVideoRequest = UploadVideoRequest(filePath, file_title) + logger.info("视频分类:{}, requestId:{}", self.__config["vod"]["cateId"], self.__request_id) + uploadVideoRequest.setCateId(self.__config["vod"]["cateId"]) + # 可以设置视频封面,如果是本地或网络图片可使用UploadImageRequest上传图片到视频点播,获取到ImageURL + # ImageURL示例:https://example.com/sample-****.jpg + # uploadVideoRequest.setCoverURL('') + # 标签 + # uploadVideoRequest.setTags('tag1,tag2') + MAX_RETRIES = 3 + retry_count = 0 + while True: + try: + result = uploader.uploadLocalVideo(uploadVideoRequest) + logger.info("vod视频上传成功, videoId:{}, requestId:{}", result.get("VideoId"), self.__request_id) + return result.get("VideoId") + except Exception: + retry_count += 1 + time.sleep(1) + uploader = AliyunVodUploader(self.__config["access_key"], self.__config["access_secret"], + self.__request_id) + uploadVideoRequest: UploadVideoRequest = UploadVideoRequest(filePath, file_title) + uploadVideoRequest.setCateId(self.__config["vod"]["cateId"]) + logger.error("vod视频上传失败:{},重试次数:{}, requestId:{}", format_exc(), retry_count, + self.__request_id) + if retry_count >= MAX_RETRIES: + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + + def get_play_url(self, filePath, file_title): + videoId = self.upload_local_video(filePath, file_title) + if videoId is None or len(videoId) == 0: + raise ServiceException(ExceptionType.GET_VIDEO_URL_EXCEPTION.value[0], + ExceptionType.GET_VIDEO_URL_EXCEPTION.value[1]) + return self.get_play_info(videoId) + +# if __name__ == "__main__": +# aa = ThAliyunVodSdk('/home/th/tuo_heng/dev/tuoheng_alg', 'dev', "1") +# print(aa.get_play_info('6928821035b171ee9f3b6632b68f0102')) diff --git a/vodsdk/util/CpuUtils.py b/vodsdk/util/CpuUtils.py new file mode 100644 index 0000000..eee06c4 --- /dev/null +++ b/vodsdk/util/CpuUtils.py @@ -0,0 +1,78 @@ +from os.path import dirname +from traceback import format_exc + +import psutil +from loguru import logger + +from enums.ExceptionEnum import ExceptionType +from exception.CustomerException import ServiceException + + +def check_cpu(base_dir, requestId=None): + path = dirname(base_dir) + cpu_use = psutil.cpu_percent() + cpu_mem = psutil.virtual_memory().percent + cpu_swap = psutil.swap_memory().percent + cpu_disk = psutil.disk_usage(path).percent + if float(cpu_use) > 70 or float(cpu_mem) > 70 or cpu_swap > 85 or cpu_disk > 90: + if requestId: + logger.info("""############################################################################################### + CPU 使用率:{}, 内存使用:{}, SWAP内存使用率:{}, 服务磁盘使用率:{}, requestId:{} + ###############################################################################################""", + cpu_use, cpu_mem, cpu_swap, cpu_disk, requestId) + else: + logger.info("""############################################################################################### + CPU 使用率:{}, 内存使用:{}, SWAP内存使用率:{}, 服务磁盘使用率:{} + ###############################################################################################""", + cpu_use, cpu_mem, cpu_swap, cpu_disk) + raise ServiceException(ExceptionType.NO_RESOURCES.value[0], + ExceptionType.NO_RESOURCES.value[1]) + + +def print_cpu_ex_status(base_dir, requestId=None): + result = False + try: + path = dirname(base_dir) + cpu_use = psutil.cpu_percent() + cpu_mem = psutil.virtual_memory().percent + cpu_swap = psutil.swap_memory().percent + cpu_disk = psutil.disk_usage(path).percent + if float(cpu_use) > 70 or float(cpu_mem) > 70 or cpu_swap > 85 or cpu_disk > 90: + result = True + if requestId: + logger.info("""############################################################################################### + CPU 使用率:{}, 内存使用:{}, SWAP内存使用率:{}, 服务磁盘使用率:{}, requestId:{} + ###############################################################################################""", + cpu_use, cpu_mem, cpu_swap, cpu_disk, requestId) + else: + logger.info("""############################################################################################### + CPU 使用率:{}, 内存使用:{}, SWAP内存使用率:{}, 服务磁盘使用率:{} + ###############################################################################################""", + cpu_use, cpu_mem, cpu_swap, cpu_disk) + except Exception: + logger.error("打印cpu状态异常: {}", format_exc()) + return result + + +def print_cpu_status(base_dir=None, requestId=None,lineNum=None): + if base_dir: + path = dirname(base_dir) + if not lineNum: lineNum='未定义' + cpu_use = psutil.cpu_percent() + cpu_mem = psutil.virtual_memory().percent + cpu_swap = psutil.swap_memory().percent + cpu_lj = psutil.cpu_count() # 逻辑cpu个数 + cpu_wl = psutil.cpu_count(logical=False) # 物理cpu个数 + if base_dir: + cpu_disk = psutil.disk_usage(path).percent + else: cpu_disk="未统计" + if requestId: + logger.info("""############################################################################################ + 行号:{} CPU 使用率:{}, 内存使用:{}, SWAP内存使用率:{}, 逻辑个数:{}, 物理个数:{}, 服务磁盘使用率:{}, requestId:{} + ###############################################################################################""", lineNum,cpu_use, + cpu_mem, cpu_swap, cpu_lj, cpu_wl, cpu_disk, requestId) + else: + logger.info("""############################################################################################### + 行号:{} CPU 使用率:{}, 内存使用:{}, SWAP内存使用率:{}, 逻辑个数:{}, 物理个数:{}, 服务磁盘使用率:{} + ###############################################################################################""",lineNum ,cpu_use, + cpu_mem, cpu_swap, cpu_lj, cpu_wl, cpu_disk) \ No newline at end of file diff --git a/vodsdk/util/Cv2Utils.py b/vodsdk/util/Cv2Utils.py new file mode 100644 index 0000000..af2800c --- /dev/null +++ b/vodsdk/util/Cv2Utils.py @@ -0,0 +1,1095 @@ +# -*- coding: utf-8 -*- +from json import loads +from time import time +from traceback import format_exc + +import cv2 +import subprocess as sp + +import numpy as np +from loguru import logger +from common import Constant +from exception.CustomerException import ServiceException +from enums.ExceptionEnum import ExceptionType + + +class Cv2Util: + __slots__ = [ + 'pullUrl', + 'pushUrl', + 'orFilePath', + 'aiFilePath', + 'p', + 'or_video_file', + 'ai_video_file', + 'fps', + 'width', + 'height', + 'wh', + 'h', + 'w', + 'all_frames', + 'bit_rate', + 'pull_p', + 'requestId', + 'p_push_retry_num', + 'isGpu', + 'read_w_h', + 'context', + 'p_push_time' + ] + + def __init__(self, pullUrl=None, pushUrl=None, orFilePath=None, aiFilePath=None, requestId=None, context=None, + gpu_ids=None): + self.pullUrl = pullUrl + self.pushUrl = pushUrl + self.orFilePath = orFilePath + self.aiFilePath = aiFilePath + self.p = None + self.or_video_file = None + self.ai_video_file = None + self.fps = None + self.width = None + self.height = None + self.wh = None + self.h = None + self.w = None + self.all_frames = None + self.bit_rate = None + self.pull_p = None + self.requestId = requestId + self.p_push_time = 0 + self.p_push_retry_num = 0 + self.isGpu = False + self.read_w_h = None + self.context = context + if gpu_ids is not None and len(gpu_ids) > 0: + self.isGpu = True + + def getFrameConfig(self, fps, width, height): + if self.fps is None or self.width != width or self.height != height: + self.fps = fps + self.width = width + self.height = height + if width > Constant.width: + self.h = int(self.height // 2) + self.w = int(self.width // 2) + else: + self.h = int(self.height) + self.w = int(self.width) + + def clear_video_info(self): + self.fps = None + self.width = None + self.height = None + + ''' + 获取视频信息 + ''' + + def get_video_info(self): + try: + if self.pullUrl is None or len(self.pullUrl) == 0: + logger.error("拉流地址不能为空, requestId:{}", self.requestId) + raise ServiceException(ExceptionType.PULL_STREAM_URL_EXCEPTION.value[0], + ExceptionType.PULL_STREAM_URL_EXCEPTION.value[1]) + args = ['ffprobe', '-show_format', '-show_streams', '-of', 'json', self.pullUrl] + p = sp.Popen(args, stdout=sp.PIPE, stderr=sp.PIPE) + out, err = p.communicate(timeout=20) + if p.returncode != 0: + raise Exception("未获取视频信息!!!!!requestId:" + self.requestId) + probe = loads(out.decode('utf-8')) + if probe is None or probe.get("streams") is None: + raise Exception("未获取视频信息!!!!!requestId:" + self.requestId) + # 视频大小 + # format = probe['format'] + # size = int(format['size'])/1024/1024 + video_stream = next((stream for stream in probe['streams'] if stream.get('codec_type') == 'video'), None) + if video_stream is None: + raise Exception("未获取视频信息!!!!!requestId:" + self.requestId) + width = video_stream.get('width') + height = video_stream.get('height') + nb_frames = video_stream.get('nb_frames') + fps = video_stream.get('r_frame_rate') + # duration = video_stream.get('duration') + # bit_rate = video_stream.get('bit_rate') + if width is not None and int(width) != 0 and height is not None and int(height) != 0: + self.width = int(width) + self.height = int(height) + self.wh = self.width * self.height * 3 + if width > Constant.width: + self.h = int(self.height // 2) + self.w = int(self.width // 2) + else: + self.h = int(self.height) + self.w = int(self.width) + if nb_frames: + self.all_frames = int(nb_frames) + up, down = str(fps).split('/') + self.fps = int(eval(up) / eval(down)) + if self.fps > 30: + logger.info("获取视频FPS大于30帧, FPS:{}, requestId:{}", self.fps, self.requestId) + self.fps = 30 + if self.fps < 25: + logger.info("获取视频FPS小于25帧, FPS:{}, requestId:{}", self.fps, self.requestId) + self.fps = 25 + # if duration: + # self.duration = float(video_stream['duration']) + # self.bit_rate = int(bit_rate) / 1000 + logger.info("视频信息, width:{}|height:{}|fps:{}|all_frames:{}, requestId:{}", + self.width, self.height, self.fps, self.all_frames, self.requestId) + except ServiceException as s: + logger.error("获取视频信息异常: {}, requestId:{}", s.msg, self.requestId) + self.clear_video_info() + raise s + except Exception: + logger.error("获取视频信息异常:{}, requestId:{}", format_exc(), self.requestId) + self.clear_video_info() + + ''' + 录屏任务获取视频信息 + ''' + + def get_recording_video_info(self): + try: + video_info = 'ffprobe -show_format -show_streams -of json %s' % self.pullUrl + 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("未获取视频信息!!!!!requestId:" + self.requestId) + probe = loads(out.decode('utf-8')) + if probe is None or probe.get("streams") is None: + raise Exception("未获取视频信息!!!!!requestId:" + self.requestId) + video_stream = next((stream for stream in probe['streams'] if stream.get('codec_type') == 'video'), None) + if video_stream is None: + raise Exception("未获取视频信息!!!!!requestId:" + self.requestId) + width = video_stream.get('width') + height = video_stream.get('height') + nb_frames = video_stream.get('nb_frames') + fps = video_stream.get('r_frame_rate') + if width and int(width) > 0: + self.width = int(width) + if height and int(height) > 0: + self.height = int(height) + if self.width and self.height: + self.wh = int(width * height * 3) + self.read_w_h = ([self.height, self.width, 3]) + if nb_frames and int(nb_frames) > 0: + self.all_frames = int(nb_frames) + if fps: + up, down = str(fps).split('/') + self.fps = int(eval(up) / eval(down)) + logger.info("视频信息, width:{}|height:{}|fps:{}|all_frames:{}, requestId:{}", self.width, + self.height, self.fps, self.all_frames, self.requestId) + except ServiceException as s: + logger.error("获取视频信息异常: {}, requestId:{}", s.msg, self.requestId) + self.clear_video_info() + raise s + except Exception: + logger.error("获取视频信息异常:{}, requestId:{}", format_exc(), self.requestId) + self.clear_video_info() + + def getRecordingFrameConfig(self, fps, width, height): + self.fps = fps + self.width = width + self.height = height + + ''' + 录屏拉取视频 + ''' + + def recording_pull_p(self): + try: + # 如果视频信息不存在, 不初始化拉流 + if self.checkconfig(): + return + # 如果已经初始化, 不再初始化 + if self.pull_p: + return + command = ['ffmpeg -re', '-y', '-an' + # '-hide_banner', + ] + if self.pullUrl.startswith('rtsp://'): + command.extend(['-rtsp_transport', 'tcp']) + if self.isGpu: + command.extend(['-hwaccel', 'cuda']) + command.extend(['-i', self.pullUrl, + '-f', 'rawvideo', + '-pix_fmt', 'bgr24', + '-r', '25', + '-']) + self.pull_p = sp.Popen(command, stdout=sp.PIPE) + except ServiceException as s: + logger.exception("构建拉流管道异常: {}, requestId:{}", s.msg, self.requestId) + self.clear_video_info() + if self.pull_p: + logger.info("重试, 关闭拉流管道, requestId:{}", self.requestId) + self.pull_p.stdout.close() + self.pull_p.terminate() + self.pull_p.wait() + self.pull_p = None + raise s + except Exception as e: + logger.error("构建拉流管道异常:{}, requestId:{}", e, self.requestId) + self.clear_video_info() + if self.pull_p: + logger.info("重试, 关闭拉流管道, requestId:{}", self.requestId) + self.pull_p.stdout.close() + self.pull_p.terminate() + self.pull_p.wait() + self.pull_p = None + + def recording_read(self): + result = None + try: + self.recording_pull_p() + in_bytes = self.pull_p.stdout.read(self.wh) + if in_bytes is not None and len(in_bytes) > 0: + try: + result = np.frombuffer(in_bytes, np.uint8).reshape(self.read_w_h) + except Exception: + logger.error("视频格式异常:{}, requestId:{}", format_exc(), self.requestId) + raise ServiceException(ExceptionType.VIDEO_RESOLUTION_EXCEPTION.value[0], + ExceptionType.VIDEO_RESOLUTION_EXCEPTION.value[1]) + except ServiceException as s: + if self.pull_p: + logger.info("重试, 关闭拉流管道, requestId:{}", self.requestId) + self.pull_p.stdout.close() + self.pull_p.terminate() + self.pull_p.wait() + self.pull_p = None + raise s + except Exception: + logger.error("读流异常:{}, requestId:{}", format_exc(), self.requestId) + if self.pull_p: + logger.info("重试, 关闭拉流管道, requestId:{}", self.requestId) + self.pull_p.stdout.close() + self.pull_p.terminate() + self.pull_p.wait() + self.pull_p = None + return result + + ''' + 拉取视频 + ''' + + def build_pull_p(self): + try: + command = ['ffmpeg'] + if self.pullUrl.startswith("rtsp://"): + command.extend(['-rtsp_transport', 'tcp']) + command.extend(['-re', + '-y', + '-an', + # '-hwaccel', 'cuda', cuvid + '-c:v', 'h264_cuvid', + # '-resize', self.wah, + '-i', self.pullUrl, + '-f', 'rawvideo', + '-pix_fmt', 'bgr24', + '-r', '25', + '-']) + self.pull_p = sp.Popen(command, stdout=sp.PIPE) + except ServiceException as s: + logger.exception("构建拉流管道异常: {}, requestId:{}", s.msg, self.requestId) + raise s + except Exception as e: + logger.error("构建拉流管道异常:{}, requestId:{}", format_exc(), self.requestId) + self.clear_video_info() + if self.pull_p: + logger.info("重试, 关闭拉流管道, requestId:{}", self.requestId) + self.pull_p.stdout.close() + self.pull_p.terminate() + self.pull_p.wait() + self.pull_p = None + + def checkconfig(self): + if self.width is None or self.height is None or self.fps is None: + return True + return False + + def read(self): + result = None + try: + if self.pull_p is None: + self.build_pull_p() + in_bytes = self.pull_p.stdout.read(self.wh) + if in_bytes is not None and len(in_bytes) > 0: + try: + result = (np.frombuffer(in_bytes, np.uint8).reshape([self.height, self.width, 3])) + # img = (np.frombuffer(in_bytes, np.uint8)).reshape((self.h, self.w)) + except Exception as ei: + logger.error("视频格式异常:{}, requestId:{}", format_exc(), self.requestId) + raise ServiceException(ExceptionType.VIDEO_RESOLUTION_EXCEPTION.value[0], + ExceptionType.VIDEO_RESOLUTION_EXCEPTION.value[1]) + # result = cv2.cvtColor(img, cv2.COLOR_YUV2BGR_NV12) + # result = cv2.cvtColor(result, cv2.COLOR_RGB2BGR) + if self.width > Constant.width: + result = cv2.resize(result, (self.w, self.h), interpolation=cv2.INTER_LINEAR) + except ServiceException as s: + raise s + except Exception as e: + self.clear_video_info() + if self.pull_p: + logger.info("关闭拉流管道, requestId:{}", self.requestId) + self.pull_p.stdout.close() + self.pull_p.terminate() + self.pull_p.wait() + self.pull_p = None + logger.error("读流异常:{}, requestId:{}", format_exc(), self.requestId) + return result + + def close(self): + self.clear_video_info() + if self.pull_p: + if self.pull_p.stdout: + self.pull_p.stdout.close() + self.pull_p.terminate() + self.pull_p.wait() + self.pull_p = None + logger.info("关闭拉流管道完成, requestId:{}", self.requestId) + if self.p: + if self.p.stdin: + self.p.stdin.close() + self.p.terminate() + self.p.wait() + self.p = None + # self.p.communicate() + # self.p.kill() + logger.info("关闭管道完成, requestId:{}", self.requestId) + if self.or_video_file: + self.or_video_file.release() + self.or_video_file = None + logger.info("关闭原视频写入流完成, requestId:{}", self.requestId) + if self.ai_video_file: + self.ai_video_file.release() + self.ai_video_file = None + logger.info("关闭AI视频写入流完成, requestId:{}", self.requestId) + + # 构建 cv2 + # def build_cv2(self): + # try: + # if self.cap is not None: + # logger.info("重试, 关闭cap, requestId:{}", self.requestId) + # self.cap.release() + # if self.p is not None: + # logger.info("重试, 关闭管道, requestId:{}", self.requestId) + # self.p.stdin.close() + # self.p.terminate() + # self.p.wait() + # if self.pullUrl is None: + # logger.error("拉流地址不能为空, requestId:{}", self.requestId) + # raise ServiceException(ExceptionType.PULL_STREAM_URL_EXCEPTION.value[0], + # ExceptionType.PULL_STREAM_URL_EXCEPTION.value[1]) + # if self.pushUrl is None: + # logger.error("推流地址不能为空, requestId:{}", self.requestId) + # raise ServiceException(ExceptionType.PUSH_STREAM_URL_EXCEPTION.value[0], + # ExceptionType.PUSH_STREAM_URL_EXCEPTION.value[1]) + # self.cap = cv2.VideoCapture(self.pullUrl) + # if self.fps is None or self.fps == 0: + # self.fps = int(self.cap.get(cv2.CAP_PROP_FPS)) + # if self.width is None or self.width == 0: + # self.width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH)) + # if self.height is None or self.height == 0: + # self.height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) + # command = ['/usr/bin/ffmpeg', + # # '-y', # 不经过确认,输出时直接覆盖同名文件。 + # '-f', 'rawvideo', + # '-vcodec', 'rawvideo', + # '-pix_fmt', 'bgr24', # 显示可用的像素格式 + # # '-s', "{}x{}".format(self.width * 2, self.height), + # '-s', "{}x{}".format(int(self.width), int(self.height/2)), + # # '-r', str(15), + # '-i', '-', # 指定输入文件 + # '-g', '25', + # '-b:v', '3000k', + # '-tune', 'zerolatency', # 加速编码速度 + # '-c:v', 'libx264', # 指定视频编码器 + # '-sc_threshold', '0', + # '-pix_fmt', 'yuv420p', + # '-an', + # '-preset', 'ultrafast', # 指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, + # # superfast, veryfast, faster, fast, medium, slow, slower, veryslow。 + # '-f', 'flv', + # self.pushUrl] + # # 管道配置 + # logger.info("fps:{}|height:{}|width:{}|requestId:{}", self.fps, self.height, self.width, self.requestId) + # self.p = sp.Popen(command, stdin=sp.PIPE) + # except ServiceException as s: + # logger.exception("构建cv2异常: {}, requestId:{}", s, self.requestId) + # raise s + # except Exception as e: + # logger.exception("初始化cv2异常:{}, requestId:{}", e, self.requestId) + + # 构建 cv2 + def build_p(self): + try: + if self.pushUrl is None or len(self.pushUrl) == 0: + logger.error("推流地址不能为空, requestId:{}", self.requestId) + raise ServiceException(ExceptionType.PUSH_STREAM_URL_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_URL_EXCEPTION.value[1]) + command = ['ffmpeg', + # '-loglevel', 'debug', + '-re', + '-y', + "-an", + '-f', 'rawvideo', + '-vcodec', 'rawvideo', + '-pix_fmt', 'bgr24', + '-thread_queue_size', '1024', + '-s', "{}x{}".format(self.w * 2, self.h), + '-i', '-', # 指定输入文件 + '-r', str(25), + '-g', str(25), + '-maxrate', '6000k', + # '-profile:v', 'high', + '-b:v', '5000k', + # '-crf', '18', + # '-rc:v', 'vbr', + # '-cq:v', '25', + # '-qmin', '25', + # '-qmax', '25', + '-c:v', 'h264_nvenc', # + '-bufsize', '5000k', + # '-c:v', 'libx264', # 指定视频编码器 + # '-tune', 'zerolatency', # 加速编码速度 + # '-sc_threshold', '0', + '-pix_fmt', 'yuv420p', + # '-flvflags', 'no_duration_filesize', + # '-preset', 'fast', # 指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, + '-preset', 'p6', # 指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, + '-tune', 'll', + '-f', 'flv', + self.pushUrl] + logger.info("fps:{}|height:{}|width:{}|requestId:{}", self.fps, self.height, self.width, + self.requestId) + self.p = sp.Popen(command, stdin=sp.PIPE, shell=False) + except ServiceException as s: + if self.p: + if self.p.stdin: + self.p.stdin.close() + self.p.terminate() + self.p.wait() + logger.exception("构建p管道异常: {}, requestId:{}", s.msg, self.requestId) + raise s + except Exception as e: + if self.p: + if self.p.stdin: + self.p.stdin.close() + self.p.terminate() + self.p.wait() + logger.error("初始化p管道异常:{}, requestId:{}", format_exc(), self.requestId) + + def push_stream(self, frame): + current_retry_num = 0 + while True: + try: + if self.p is None: + self.build_p() + self.p.stdin.write(frame.tostring()) + break + except ServiceException as s: + raise s + except Exception as ex: + if self.p_push_time == 0: + self.p_push_time = time.time() + if time.time() - self.p_push_time < 2: + self.p_push_retry_num += 1 + self.p_push_time = time.time() + if time.time() - self.p_push_time > 60: + self.p_push_retry_num = 0 + self.p_push_time = time.time() + logger.error("推流管道异常:{}, requestId: {}", format_exc(), self.requestId) + if self.p: + try: + if self.p.stdin: + self.p.stdin.close() + self.p.terminate() + self.p.wait() + except: + logger.error("推流管道异常:{}, requestId: {}", format_exc(), self.requestId) + self.p = None + current_retry_num += 1 + if self.p_push_retry_num > 100: + logger.error("推流进管道异常:{}, requestId: {}", format_exc(), self.requestId) + raise ServiceException(ExceptionType.PUSH_STREAMING_CHANNEL_IS_OCCUPIED.value[0], + ExceptionType.PUSH_STREAMING_CHANNEL_IS_OCCUPIED.value[1]) + if current_retry_num > 3: + logger.error("推流进管道异常:{}, requestId: {}", format_exc(), self.requestId) + raise ServiceException(ExceptionType.PUSH_STREAM_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_EXCEPTION.value[1]) + + def build_or_write(self): + try: + if self.orFilePath is not None and self.or_video_file is None: + self.or_video_file = cv2.VideoWriter(self.orFilePath, cv2.VideoWriter_fourcc(*'mp4v'), 25, + (self.w, self.h)) + # self.or_video_file.set(cv2.CAP_PROP_BITRATE, 5000) + if self.or_video_file is None: + logger.error("or_video_file为空, requestId:{}", self.requestId) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + except ServiceException as s: + if self.or_video_file: + self.or_video_file.release() + self.or_video_file = None + logger.error("构建OR文件写对象异常: {}, requestId:{}", s.msg, self.requestId) + raise s + except Exception as e: + if self.or_video_file: + self.or_video_file.release() + self.or_video_file = None + logger.error("构建OR文件写对象异常: {}, requestId:{}", format_exc(), self.requestId) + raise e + except: + if self.or_video_file: + self.or_video_file.release() + self.or_video_file = None + logger.exception("构建OR文件写对象异常:{}, requestId:{}", format_exc(), self.requestId) + raise Exception("构建OR文件写对象异常") + + def build_ai_write(self): + try: + if self.aiFilePath is not None and self.ai_video_file is None: + self.ai_video_file = cv2.VideoWriter(self.aiFilePath, cv2.VideoWriter_fourcc(*'mp4v'), 25, + (self.w * 2, self.h)) + # self.ai_video_file.set(cv2.CAP_PROP_BITRATE, 5000) + if self.ai_video_file is None: + logger.error("ai_video_file为空, requestId:{}", self.requestId) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + except ServiceException as s: + if self.ai_video_file: + self.ai_video_file.release() + self.ai_video_file = None + logger.error("构建AI文件写对象异常: {}, requestId:{}", s.msg, self.requestId) + raise s + except Exception as e: + if self.ai_video_file: + self.ai_video_file.release() + self.ai_video_file = None + logger.error("构建AI文件写对象异常: {}, requestId:{}", format_exc(), self.requestId) + raise e + except: + if self.ai_video_file: + self.ai_video_file.release() + self.ai_video_file = None + logger.error("构建AI文件写对象异常:{}, requestId:{}", format_exc(), self.requestId) + raise Exception("构建AI文件写对象异常") + + def video_or_write(self, frame): + ai_retry_num = 0 + while True: + try: + if self.or_video_file is None: + self.build_or_write() + self.or_video_file.write(frame) + break + except ServiceException as s: + raise s + except Exception as ex: + if ai_retry_num > 3: + logger.error("重新写入原视频视频到本地, 重试失败:{}, requestId: {}", format_exc(), + self.requestId) + raise ex + finally: + ai_retry_num += 1 + + def video_ai_write(self, frame): + ai_retry_num = 0 + while True: + try: + if self.ai_video_file is None: + self.build_ai_write() + self.ai_video_file.write(frame) + break + except ServiceException as s: + raise s + except Exception as ex: + if ai_retry_num > 3: + logger.exception("重新写入分析后的视频到本地,重试失败:{}, requestId: {}", format_exc(), + self.requestId) + raise ex + finally: + ai_retry_num += 1 + + def video_merge(self, frame1, frame2): + # frameLeft = cv2.resize(frame1, (int(self.width / 2), int(self.height / 2)), interpolation=cv2.INTER_LINEAR) + # frameRight = cv2.resize(frame2, (int(self.width / 2), int(self.height / 2)), interpolation=cv2.INTER_LINEAR) + # frame_merge = np.hstack((frameLeft, frameRight)) + frame_merge = np.hstack((frame1, frame2)) + return frame_merge + + def getP(self): + if self.p is None: + logger.error("获取管道为空, requestId:{}", self.requestId) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + return self.p + + def getOrVideoFile(self): + if self.or_video_file is None: + logger.error("获取原视频写入对象为空, requestId:{}", self.requestId) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + return self.or_video_file + + def getAiVideoFile(self): + if self.ai_video_file is None: + logger.error("获取AI视频写入对象为空, requestId:{}", self.requestId) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + return self.ai_video_file + + +def check_video_stream(width, height): + if width is None or height is None: + return True + return False + + +def build_video_info(pull_url, requestId): + try: + if pull_url is None or len(pull_url) == 0: + logger.error("拉流地址不能为空, requestId:{}", requestId) + raise ServiceException(ExceptionType.PULL_STREAM_URL_EXCEPTION.value[0], + ExceptionType.PULL_STREAM_URL_EXCEPTION.value[1]) + pp = sp.Popen(['ffprobe', '-show_format', '-show_streams', '-of', 'json', pull_url], stdout=sp.PIPE, + stderr=sp.PIPE) + out, err = pp.communicate(timeout=18) + if pp.returncode != 0: + logger.error("获取视频信息失败: {}, requestId:{}", err.decode('utf-8'), requestId) + raise Exception("未获取视频信息!!!!") + probe = loads(out.decode('utf-8')) + video_stream = next((stream for stream in probe['streams'] if stream.get('codec_type') == 'video'), None) + if video_stream is None: + raise Exception("未获取视频信息!!!!") + width_new, height_new = video_stream.get('width'), video_stream.get('height') + nb_frames = video_stream.get('nb_frames', 0) + duration = video_stream.get('duration') + if duration is not None and float(duration) != float(0): + nb_frames = int(float(duration) * 25) + if width_new is not None and int(width_new) != 0 and height_new is not None and int(height_new) != 0: + height_o = int(height_new) + width, height = int(width_new), height_o * 3 // 2 + width_height_3 = width * height + all_frames = int(nb_frames) + w_2, h_2 = width, height_o + if width > Constant.width: + w_2, h_2 = width // 2, height_o // 2 + logger.info("视频信息, width:{}|height:{}|all_frames:{}, requestId:{}", width, height_o, all_frames, + requestId) + return width, height, width_height_3, all_frames, w_2, h_2 + raise Exception("未获取视频信息!!!!") + except ServiceException as s: + logger.error("获取视频信息异常: {}, requestId:{}", s.msg, requestId) + raise s + except Exception: + logger.error("获取视频信息异常:{}, requestId:{}", format_exc(), requestId) + return None, None, None, 0, None, None + + +def build_video_info2(pull_url, requestId): + try: + pp = sp.Popen(['ffprobe', '-show_format', '-show_streams', '-of', 'json', pull_url], stdout=sp.PIPE, + stderr=sp.PIPE) + out, err = pp.communicate(timeout=17) + if pp.returncode != 0: + logger.error("获取视频信息失败: {}, requestId:{}", err.decode('utf-8'), requestId) + raise Exception("未获取视频信息!!!!") + probe = loads(out.decode('utf-8')) + video_stream = next((stream for stream in probe['streams'] if stream.get('codec_type') == 'video'), None) + if video_stream is None: + raise Exception("未获取视频信息!!!!") + width_new, height_new = video_stream.get('width'), video_stream.get('height') + nb_frames = video_stream.get('nb_frames', 0) + # fps = video_stream.get('r_frame_rate') + duration = video_stream.get('duration') + if duration is not None and float(duration) != float(0): + nb_frames = int(float(duration) * 25) + # bit_rate = video_stream.get('bit_rate') + if width_new is not None and int(width_new) != 0 and height_new is not None and int(height_new) != 0: + width_o, height_o = int(width_new), int(height_new) + # width_height_3 = width * height * 3 + width_height_3 = width_o * height_o * 3 // 2 + width, height, all_frames = width_o, height_o * 3 // 2, int(nb_frames) + w, h = width_o, height_o + if width > Constant.width: + w, h = width_o // 2, height_o // 2 + # up, down = str(fps).split('/') + # self.fps = int(eval(up) / eval(down)) + # if duration: + # self.duration = float(video_stream['duration']) + # self.bit_rate = int(bit_rate) / 1000 + logger.info("视频信息, width:{}|height:{}|all_frames:{}, requestId:{}", width_o, height_o, all_frames, + requestId) + return width, height, width_height_3, all_frames, w, h + raise Exception("未获取视频信息!!!!") + except ServiceException as s: + logger.error("获取视频信息异常: {}, requestId:{}", s.msg, requestId) + raise s + except Exception: + logger.error("获取视频信息异常:{}, requestId:{}", format_exc(), requestId) + return None, None, None, 0, None, None + + +def start_pull_p(pull_url, requestId): + try: + command = ['ffmpeg'] + if pull_url.startswith("rtsp://"): + command.extend(['-timeout', '20000000', '-rtsp_transport', 'tcp']) + if pull_url.startswith("http") or pull_url.startswith("rtmp"): + command.extend(['-rw_timeout', '20000000']) + command.extend(['-re', + '-y', + '-an', + # '-hwaccel', 'cuda', cuvid + '-c:v', 'h264_cuvid', + # '-resize', self.wah, + '-i', pull_url, + '-f', 'rawvideo', + # '-pix_fmt', 'bgr24', + '-r', '25', + '-']) + return sp.Popen(command, stdout=sp.PIPE) + except ServiceException as s: + logger.error("构建拉流管道异常: {}, requestId:{}", s.msg, requestId) + raise s + except Exception as e: + logger.error("构建拉流管道异常:{}, requestId:{}", format_exc(), requestId) + raise e + + +def clear_pull_p(pull_p, requestId): + try: + if pull_p and pull_p.poll() is None: + logger.info("关闭拉流管道, requestId:{}", requestId) + if pull_p.stdout: + pull_p.stdout.close() + pull_p.terminate() + pull_p.wait(timeout=30) + logger.info("拉流管道已关闭, requestId:{}", requestId) + except Exception as e: + logger.error("关闭拉流管道异常: {}, requestId:{}", format_exc(), requestId) + if pull_p and pull_p.poll() is None: + pull_p.kill() + pull_p.wait(timeout=30) + raise e + + +def pull_read_video_stream(pull_p, pull_url, width, height, width_height_3, w_2, h_2, requestId): + result = None + try: + if pull_p is None: + pull_p = start_pull_p(pull_url, requestId) + in_bytes = pull_p.stdout.read(width_height_3) + if in_bytes is not None and len(in_bytes) > 0: + try: + # result = (np.frombuffer(in_bytes, np.uint8).reshape([height * 3 // 2, width, 3])) + result = (np.frombuffer(in_bytes, np.uint8)).reshape((height, width)) + result = cv2.cvtColor(result, cv2.COLOR_YUV2BGR_NV12) + # result = cv2.cvtColor(result, cv2.COLOR_RGB2BGR) + if width > Constant.width: + result = cv2.resize(result, (w_2, h_2), interpolation=cv2.INTER_LINEAR) + except Exception: + logger.error("视频格式异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.VIDEO_RESOLUTION_EXCEPTION.value[0], + ExceptionType.VIDEO_RESOLUTION_EXCEPTION.value[1]) + except ServiceException as s: + clear_pull_p(pull_p, requestId) + raise s + except Exception: + clear_pull_p(pull_p, requestId) + pull_p, width, height = None, None, None + logger.error("读流异常:{}, requestId:{}", format_exc(), requestId) + return result, pull_p, width, height + + +def pull_read_video_stream2(pull_p, pull_url, width, height, width_height_3, w, h, requestId): + result = None + try: + if pull_p is None: + pull_p = start_pull_p(pull_url, requestId) + in_bytes = pull_p.stdout.read(width_height_3) + if in_bytes is not None and len(in_bytes) > 0: + try: + result = (np.frombuffer(in_bytes, np.uint8)).reshape((height, width)) + result = cv2.cvtColor(result, cv2.COLOR_YUV2BGR_NV12) + if width > Constant.width: + result = cv2.resize(result, (w, h), interpolation=cv2.INTER_LINEAR) + except Exception: + logger.error("视频格式异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.VIDEO_RESOLUTION_EXCEPTION.value[0], + ExceptionType.VIDEO_RESOLUTION_EXCEPTION.value[1]) + except ServiceException as s: + clear_pull_p(pull_p, requestId) + raise s + except Exception: + clear_pull_p(pull_p, requestId) + pull_p, width, height = None, None, None + logger.error("读流异常:{}, requestId:{}", format_exc(), requestId) + return result, pull_p, width, height + + +def video_conjuncing(frame1, frame2): + # frameLeft = cv2.resize(frame1, (int(self.width / 2), int(self.height / 2)), interpolation=cv2.INTER_LINEAR) + # frameRight = cv2.resize(frame2, (int(self.width / 2), int(self.height / 2)), interpolation=cv2.INTER_LINEAR) + # frame_merge = np.hstack((frameLeft, frameRight)) + frame_merge = np.hstack((frame1, frame2)) + return frame_merge + + +def build_push_p(push_url, width, height, requestId): + push_p = None + try: + if push_url is None or len(push_url) == 0: + logger.error("推流地址不能为空, requestId:{}", requestId) + raise ServiceException(ExceptionType.PUSH_STREAM_URL_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_URL_EXCEPTION.value[1]) + command = ['ffmpeg', + # '-loglevel', 'debug', + # '-re', + '-y', + "-an", + '-f', 'rawvideo', + '-vcodec', 'rawvideo', + '-pix_fmt', 'bgr24', + '-thread_queue_size', '1024', + '-s', "{}x{}".format(width, height), + '-i', '-', # 指定输入文件 + '-r', str(25), + '-g', str(25), + '-maxrate', '6000k', + # '-profile:v', 'high', + '-b:v', '4000k', + # '-crf', '18', + # '-rc:v', 'vbr', + # '-cq:v', '25', + # '-qmin', '25', + # '-qmax', '25', + '-c:v', 'h264_nvenc', # + '-bufsize', '4000k', + # '-c:v', 'libx264', # 指定视频编码器 + # '-tune', 'zerolatency', # 加速编码速度 + # '-sc_threshold', '0', + # '-rc', 'cbr_ld_hq', + # '-zerolatency', '1', + '-pix_fmt', 'yuv420p', + # '-flvflags', 'no_duration_filesize', + # '-preset', 'fast', # 指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, + '-preset', 'p6', # 指定输出的视频质量,会影响文件的生成速度,有以下几个可用的值 ultrafast, + '-tune', 'll', + '-f', 'flv', + push_url] + logger.info("height:{}|width:{}|requestId:{}", height, width, requestId) + push_p = sp.Popen(command, stdin=sp.PIPE, shell=False) + return push_p + except ServiceException as s: + if push_p: + if push_p.stdin: + push_p.stdin.close() + push_p.terminate() + push_p.wait() + logger.error("构建p管道异常: {}, requestId:{}", s.msg, requestId) + raise s + except Exception as e: + if push_p: + if push_p.stdin: + push_p.stdin.close() + push_p.terminate() + push_p.wait() + logger.error("初始化p管道异常:{}, requestId:{}", format_exc(), requestId) + raise e + + +def push_video_stream(frame, push_p, push_url, p_push_status, requestId): + """ + :param frame: 当前视频帧 + :param push_p: 推流管道 + :param push_url: 推流地址 + :param p_push_status: 控制异常控制 + :param requestId: 请求id + :return: 推流管道 + """ + st = time() + try: + if push_p is None: + height, width = frame.shape[0:2] + push_p = build_push_p(push_url, width, height, requestId) + push_p.stdin.write(frame.tostring()) + return push_p + except ServiceException as s: + clear_push_p(push_p, requestId) + raise s + except Exception: + et = time() - st + logger.error("推流异常使用时间:{}, requestId: {}", et, requestId) + if et > 20: + logger.error("推流进管道异常:{}, requestId: {}", format_exc(), requestId) + raise ServiceException(ExceptionType.PUSH_STREAMING_CHANNEL_IS_OCCUPIED.value[0], + ExceptionType.PUSH_STREAMING_CHANNEL_IS_OCCUPIED.value[1]) + if p_push_status[0] == 0: + p_push_status[0] = time() + p_push_status[1] += 1 + elif time() - p_push_status[0] <= 60: + p_push_status[1] += 1 + p_push_status[0] = time() + elif time() - p_push_status[0] > 60: + p_push_status[1] = 1 + p_push_status[0] = time() + logger.error("推流管道异常:{}, requestId: {}", format_exc(), requestId) + clear_push_p(push_p, requestId) + if p_push_status[1] > 5: + logger.error("推流进管道异常:{}, requestId: {}", format_exc(), requestId) + raise ServiceException(ExceptionType.PUSH_STREAMING_CHANNEL_IS_OCCUPIED.value[0], + ExceptionType.PUSH_STREAMING_CHANNEL_IS_OCCUPIED.value[1]) + return None + + +def clear_push_p(push_p, requestId): + if push_p: + try: + if push_p.stdin: + push_p.stdin.close() + push_p.terminate() + push_p.wait() + except Exception: + logger.error("推流管道异常:{}, requestId: {}", format_exc(), requestId) + + +def close_or_write_stream(or_video_file, requestId): + try: + if or_video_file: + or_video_file.release() + except Exception: + logger.info("关闭原视频写流管道异常:{}, requestId:{}", format_exc(), requestId) + + +def close_ai_write_stream(ai_video_file, requestId): + try: + if ai_video_file: + ai_video_file.release() + except Exception: + logger.info("关闭AI视频写流管道异常:{}, requestId:{}", format_exc(), requestId) + + +def close_all_p(push_p, or_video_file, ai_video_file, requestId): + logger.info("开始停止推流、写流管道!requestId:{}", requestId) + clear_push_p(push_p, requestId) + close_or_write_stream(or_video_file, requestId) + close_ai_write_stream(ai_video_file, requestId) + logger.info("停止推流、写流管道完成!requestId:{}", requestId) + + +def build_or_video(orFilePath, width, height, requestId): + or_video_file = None + try: + or_video_file = cv2.VideoWriter(orFilePath, cv2.VideoWriter_fourcc(*'mp4v'), 25, (width, height)) + if or_video_file is None: + logger.error("or_video_file为空, requestId:{}", requestId) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + return or_video_file + except ServiceException as s: + if or_video_file: + or_video_file.release() + logger.error("构建OR文件写对象异常: {}, requestId:{}", s.msg, requestId) + raise s + except Exception as e: + if or_video_file: + or_video_file.release() + logger.error("构建OR文件写对象异常: {}, requestId:{}", format_exc(), requestId) + raise e + + +def write_or_video(frame, orFilePath, or_video_file, or_write_status, requestId): + """ + :param frame: 当时视频帧 + :param orFilePath: 原视频名称 + :param or_video_file: 原视频本地写流对象 + :param or_write_status: 原视频写流状态检查 [0, 0] 第一个参数时间,第二个参数重试的次数 + :param requestId: 请求id + :return: 原视频本地写流对象 + :desc 如果写流失败了, 不重试, 丢弃本次视频帧 + """ + try: + if or_video_file is None: + height, width = frame.shape[0], frame.shape[1] + or_video_file = build_or_video(orFilePath, width, height, requestId) + or_video_file.write(frame) + return or_video_file + except ServiceException as s: + if or_video_file: + or_video_file.release() + raise s + except Exception as ex: + # 当第一次写视频帧到本地失败, 更新or_write_status的时间和重试次数 + if or_write_status[0] == 0: + or_write_status[0] = time() + or_write_status[1] += 1 + # 1分钟内失败重试次数更新, 1分钟中容忍小于5次的失败次数 + elif time() - or_write_status[0] <= 60: + or_write_status[1] += 1 + or_write_status[0] = time() + # 大于1分钟初始化检查数组 + elif time() - or_write_status[0] > 60: + or_write_status[1] = 1 + or_write_status[0] = time() + if or_write_status[1] > 5: + if or_video_file: + or_video_file.release() + logger.error("重新写入原视频视频到本地, 重试失败:{}, requestId: {}", format_exc(), requestId) + raise ex + return or_video_file + + +def build_ai_video(aiFilePath, width, height, requestId): + ai_video_file = None + try: + ai_video_file = cv2.VideoWriter(aiFilePath, cv2.VideoWriter_fourcc(*'mp4v'), 25, (width, height)) + if ai_video_file is None: + logger.error("ai_video_file为空, requestId:{}", requestId) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + return ai_video_file + except ServiceException as s: + if ai_video_file: + ai_video_file.release() + logger.error("构建AI文件写对象异常: {}, requestId:{}", s.msg, requestId) + raise s + except Exception as e: + if ai_video_file: + ai_video_file.release() + logger.error("构建AI文件写对象异常: {}, requestId:{}", format_exc(), requestId) + raise e + + +def write_ai_video(frame, aiFilePath, ai_video_file, ai_write_status, requestId): + try: + if ai_video_file is None: + height, width = frame.shape[0], frame.shape[1] + ai_video_file = build_ai_video(aiFilePath, width, height, requestId) + ai_video_file.write(frame) + return ai_video_file + except ServiceException as s: + if ai_video_file: + ai_video_file.release() + raise s + except Exception as ex: + if ai_write_status[0] == 0: + ai_write_status[0] = time() + ai_write_status[1] += 1 + # 大于1分钟初始化检查数组 + elif time() - ai_write_status[0] > 60: + ai_write_status[1] = 1 + ai_write_status[0] = time() + # 1分钟内失败重试次数更新, 1分钟中容忍小于5次的失败次数 + elif time() - ai_write_status[0] <= 60: + ai_write_status[1] += 1 + ai_write_status[0] = time() + if ai_write_status[1] > 5: + if ai_video_file: + ai_video_file.release() + logger.error("重新写入分析后的视频到本地,重试失败:{}, requestId: {}", format_exc(), requestId) + raise ex + return ai_video_file diff --git a/vodsdk/util/FileUtils.py b/vodsdk/util/FileUtils.py new file mode 100644 index 0000000..9446319 --- /dev/null +++ b/vodsdk/util/FileUtils.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +from os import makedirs +from os.path import exists + +from loguru import logger + +''' + 文件处理工具类 +''' + + +def create_dir_not_exist(file_path): + if not exists(file_path): + logger.info("开始创建文件夹: {}", file_path) + makedirs(file_path) + logger.info("文件夹创建完成 {}", file_path) diff --git a/vodsdk/util/GPUtils.py b/vodsdk/util/GPUtils.py new file mode 100644 index 0000000..ec528ce --- /dev/null +++ b/vodsdk/util/GPUtils.py @@ -0,0 +1,107 @@ +# -*- coding: utf-8 -*- +from traceback import format_exc + +from GPUtil import getAvailable, getGPUs +from loguru import logger +from torch.cuda import is_available + +from enums.ExceptionEnum import ExceptionType +from exception.CustomerException import ServiceException + + +# order- 确定返回可用 GPU 设备 ID 的顺序。order应指定为以下字符串之一: +# 'first'- 按升序排列可用的 GPU 设备 ID(默认) +# 'last'- 按 id 降序排列可用的 GPU 设备 id +# 'random'- 随机订购可用的 GPU 设备 ID +# 'load'- 按负载递增排序可用的 GPU 设备 ID +# 'memory'- 通过升序内存使用来排序可用的 GPU 设备 ID +# limit- 将返回的 GPU 设备 ID 数量限制为指定数量。必须是正整数。(默认 = 1) +# maxLoad- 被认为可用的 GPU 的最大当前相对负载。负载大于 的 GPUmaxLoad不会返回。(默认 = 0.5) +# maxMemory- 被视为可用的 GPU 的最大当前相对内存使用量。maxMemory不返回当前内存使用量大于的 GPU 。(默认 = 0.5) +# includeNan- 真/假标志,指示是否包括负载或内存使用为 NaN 的 GPU(指示无法检索使用情况)。(默认 = 假) +# excludeID- ID 列表,应从可用 GPU 列表中排除。见GPU类描述。(默认 = []) +# excludeUUIDexcludeID-除了它使用 UUID 之外,其他相同。(默认 = []) +# 输出 +# deviceIDs - 所有可用 GPU 设备 ID 的列表。如果当前负载和内存使用量分别小于maxLoad和maxMemory,则认为 GPU 可用。该列表是根据 排序的order。返回的设备 ID 的最大数量由 限制limit。 +def get_gpu_ids(): + deviceIDs = getAvailable(maxLoad=0.80, maxMemory=0.80) + return deviceIDs + + +def get_all_gpu_ids(): + return getGPUs() + + +def get_first_gpu_name(): + gps = get_all_gpu_ids() + if len(gps) == 0: + raise ServiceException(ExceptionType.NO_GPU_RESOURCES.value[0], + ExceptionType.NO_GPU_RESOURCES.value[1]) + return gps[0].name + + +def check_gpu_resource(requestId=None): + gpu_ids = get_gpu_ids() + if len(gpu_ids) == 0 or 0 not in gpu_ids: + print_gpu_status(requestId) + raise ServiceException(ExceptionType.NO_RESOURCES.value[0], + ExceptionType.NO_RESOURCES.value[1]) + return gpu_ids + + +def print_gpu_ex_status(requestId=None): + result = False + try: + gpu_ids = get_gpu_ids() + if len(gpu_ids) == 0 or 0 not in gpu_ids: + result = True + print_gpu_status(requestId) + except Exception: + logger.error("打印gpu状态异常: {}", format_exc()) + return result +def select_best_server(servers): + best_server_info = None + lowest_memory_usage = float('inf') # 初始化为无穷大 + + for ip, server_info in servers.items(): + gpu_list = server_info['GPU'] + for gpu in gpu_list: + if gpu['ID'] == 0: + memory_used = gpu['Memory Used'] + memory_total = gpu['Memory Total'] + memory_usage = (memory_used / memory_total) * 100 # 计算显存使用率 + + if memory_usage < lowest_memory_usage: + lowest_memory_usage = memory_usage + best_server_info = { + 'hostname': server_info['System']['Platform Node'], + 'IP': server_info['System']['Local IP Address'], + 'gpuId': gpu['ID'] + } + + return best_server_info + +def print_gpu_status(requestId=None): + try: + GPUs = get_all_gpu_ids() + if len(GPUs) == 0: + return + for gpu in GPUs: + if requestId: + logger.info("""############################################################################################ + GPU ID:{}, GPU 名称:{}, 负载率:{}, 内存使用率:{}, 总内存:{}, 占用内存:{}, 空闲内存:{}, requestId:{} + ############################################################################################""", gpu.id, + gpu.name, gpu.load * 100, gpu.memoryUtil * 100, gpu.memoryTotal, gpu.memoryUsed, gpu.memoryFree, + requestId) + else: + logger.info("""############################################################################################ + GPU ID:{}, GPU 名称:{}, 负载率:{}, 内存使用率:{}, 总内存:{}, 占用内存:{}, 空闲内存:{} + ############################################################################################""", gpu.id, + gpu.name, gpu.load * 100, gpu.memoryUtil * 100, gpu.memoryTotal, gpu.memoryUsed, gpu.memoryFree) + except Exception: + logger.error("打印gpu状态异常: {}", format_exc()) + + +def check_cude_is_available(): + if not is_available(): + raise Exception("cuda不在活动状态, 请检测显卡驱动是否正常!!!!") diff --git a/vodsdk/util/ImageUtils.py b/vodsdk/util/ImageUtils.py new file mode 100644 index 0000000..4854f49 --- /dev/null +++ b/vodsdk/util/ImageUtils.py @@ -0,0 +1,391 @@ +# -*- coding: utf-8 -*- +from io import BytesIO +from traceback import format_exc + +import cv2 +import requests +from PIL import Image, ImageDraw, ImageFont +import numpy as np +from loguru import logger + +from enums.ExceptionEnum import ExceptionType +from exception.CustomerException import ServiceException + +''' + 文字水印 +''' + + +class TextWaterMark(): + def __init__(self): + self.color_dict = { + # R G B + # 网址查看:https://tool.oschina.net/commons?type=3 + # 网址查看:http://tools.jb51.net/static/colorpicker/ + 'white': (255, 255, 255, 255), + 'black': (0, 0, 0, 255), + 'gray': (205, 201, 201, 255), + 'red': (255, 0, 0, 255), + 'yellow': (255, 215, 0, 255), + 'blue': (0, 0, 170, 255), + 'purple': (205, 105, 201, 255), + 'green': (0, 205, 0, 255) + } + self.position_list = [1, 2, 3, 4] + + """ + 普通照片水印 + params: + image:图片 + text:水印文字 + position:水印位置 + 1:左上 + 2:右上 + 3:右下 + 4:左下 + fontface: 字体 + fontsize:字体大小 + fontcolor:字体颜色 + [white, black, gray, red, yellow, blue, purple, green] + """ + + def common_water(self, image, text, position=1, fontface='../font/simsun.ttc', fontsize=20, fontcolor='black'): + flag = False + if isinstance(image, np.ndarray): # 判断是否OpenCV图片类型 + flag = True + image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGRA2RGBA)) + if position not in self.position_list: + position = 1 + w, h = image.size[:2] + keys = self.color_dict.keys() + if fontcolor not in keys: + fontcolor = 'black' + color = self.color_dict[fontcolor] + fnt = ImageFont.truetype(fontface, fontsize) + im = image.convert('RGBA') + mask = Image.new('RGBA', im.size, (0, 0, 0, 0)) + d = ImageDraw.Draw(mask) + size_w, size_h = d.textsize(text, font=fnt) + if position == 1: + weizhi = (w * 0.1, h * 0.1) + elif position == 2: + weizhi = (w * 0.9 - size_w, h * 0.1) + elif position == 3: + weizhi = (w * 0.9 - size_w, h * 0.9 - size_h) + else: + weizhi = (w * 0.1, h * 0.9 - size_h) + # position 为左上角位置 + d.text(weizhi, text, font=fnt, fill=color) + out = Image.alpha_composite(im, mask) + if flag: + out = cv2.cvtColor(np.asarray(out), cv2.COLOR_BGRA2RGBA) + return out + + """ + 半透明水印,布满整张图,并且自动旋转45° + params: + image:图片 + text:文字 + fontsize:文字大小 + """ + + def fill_water(self, image, text, fontsize): + flag = False + if isinstance(image, np.ndarray): # 判断是否OpenCV图片类型 + flag = True + image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGRA2RGBA)) + font = ImageFont.truetype('../font/simsun.ttc', fontsize) + # 添加背景 + new_img = Image.new('RGBA', (image.size[0] * 3, image.size[1] * 3), (255, 255, 255, 255)) + new_img.paste(image, image.size) + + # 添加水印 + font_len = len(text) + rgba_image = new_img.convert('RGBA') + text_overlay = Image.new('RGBA', rgba_image.size, (0, 0, 0, 0)) + image_draw = ImageDraw.Draw(text_overlay) + + for i in range(0, rgba_image.size[0], font_len * 40 + 100): + for j in range(0, rgba_image.size[1], 200): + # print(f'i:{i}, j:{j}, text:{text}, font:{font}') + image_draw.text((i, j), text, font=font, fill=(0, 0, 0, 50)) + text_overlay = text_overlay.rotate(-45) + image_with_text = Image.alpha_composite(rgba_image, text_overlay) + + image_with_text = image_with_text.crop((image.size[0], image.size[1], image.size[0] * 2, image.size[1] * 2)) + if flag: + image_with_text = cv2.cvtColor(np.asarray(image_with_text), cv2.COLOR_BGRA2RGBA) + return image_with_text + + +class PictureWaterMark: + __slots__ = ('logo', '__requestId') + + def __init__(self, logo=None, requestId=None): + self.__requestId = requestId + self.logo = logo + if requestId is None: + self.__requestId = '1' + if logo is None: + self.logo = cv2.imread("./image/logo.png", -1) + + # def common_water(self, image, logo): + # width, height = image.shape[1], image.shape[0] + # mark_width, mark_height = logo.shape[1], logo.shape[0] + # rate = int(width * 0.2) / mark_width + # logo_new = cv2.resize(logo, None, fx=rate, fy=rate, interpolation=cv2.INTER_NEAREST) + # position = (int(width * 0.95 - logo_new.shape[1]), int(height * 0.95 - logo_new.shape[0])) + # b = Image.new('RGBA', (width, height), (0, 0, 0, 0)) # 创建新图像:透明' + # a = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) + # watermark = Image.fromarray(cv2.cvtColor(logo_new, cv2.COLOR_BGRA2RGBA)) + # # 图片旋转 + # # watermark = watermark.rotate(45) + # b.paste(a, (0, 0)) + # b.paste(watermark, position, mask=watermark) + # return cv2.cvtColor(np.asarray(b), cv2.COLOR_BGR2RGB) + + def common_water_1(self, image, logo, alpha=1): + try: + h, w = image.shape[0], image.shape[1] + # if w >= h: + rate = int(w * 0.1) / logo.shape[1] + # else: + # rate = int(h * 0.1) / logo.shape[0] + mask = cv2.resize(logo, None, fx=rate, fy=rate, interpolation=cv2.INTER_NEAREST) + mask_h, mask_w = mask.shape[0], mask.shape[1] + mask_channels = cv2.split(mask) + dst_channels = cv2.split(image) + # b, g, r, a = cv2.split(mask) + # 计算mask在图片的坐标 + # if w >= h: + ul_points = (int(h * 0.95) - mask_h, int(w - h * 0.05 - mask_w)) + dr_points = (int(h * 0.95), int(w - h * 0.05)) + # else: + # ul_points = (int(h * 0.95) - mask_h, int(w - h * 0.05 - mask_w)) + # dr_points = (int(h * 0.95), int(w - h * 0.05)) + for i in range(3): + dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] = dst_channels[i][ + ul_points[0]: dr_points[0], + ul_points[1]: dr_points[ + 1]] * ( + 255.0 - mask_channels[ + 3] * alpha) / 255 + dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] += np.array( + mask_channels[i] * (mask_channels[3] * alpha / 255), dtype=np.uint8) + dst_img = cv2.merge(dst_channels) + return dst_img + except Exception: + logger.error("加水印异常:{}, requestId:{}", format_exc(), self.__requestId) + return image + + +def add_water_pic(image, logo, requestId, alpha=1): + try: + h, w = image.shape[0], image.shape[1] + # if w >= h: + rate = int(w * 0.1) / logo.shape[1] + # else: + # rate = int(h * 0.1) / logo.shape[0] + mask = cv2.resize(logo, None, fx=rate, fy=rate, interpolation=cv2.INTER_NEAREST) + mask_h, mask_w = mask.shape[0], mask.shape[1] + mask_channels = cv2.split(mask) + dst_channels = cv2.split(image) + # b, g, r, a = cv2.split(mask) + # 计算mask在图片的坐标 + # if w >= h: + ul_points = (int(h * 0.95) - mask_h, int(w - h * 0.05 - mask_w)) + dr_points = (int(h * 0.95), int(w - h * 0.05)) + # else: + # ul_points = (int(h * 0.95) - mask_h, int(w - h * 0.05 - mask_w)) + # dr_points = (int(h * 0.95), int(w - h * 0.05)) + for i in range(3): + dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] = dst_channels[i][ + ul_points[0]: dr_points[0], + ul_points[1]: dr_points[ + 1]] * ( + 255.0 - mask_channels[ + 3] * alpha) / 255 + dst_channels[i][ul_points[0]: dr_points[0], ul_points[1]: dr_points[1]] += np.array( + mask_channels[i] * (mask_channels[3] * alpha / 255), dtype=np.uint8) + dst_img = cv2.merge(dst_channels) + return dst_img + except Exception: + logger.error("加水印异常:{}, requestId:{}", format_exc(), requestId) + return image + + +# 差值感知算法 +def dHash(image): + # 缩放9*8 + image = cv2.resize(image, (9, 8), interpolation=cv2.INTER_CUBIC) + # 转换灰度图 + image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) + # print(image.shape) + hash = [] + # 每行前一个像素大于后一个像素为1,相反为0,生成哈希 + for i in range(8): + for j in range(8): + if image[i, j] > image[i, j + 1]: + hash.append(1) + else: + hash.append(0) + return hash + + +# 计算汉明距离 +def Hamming_distance(hash1, hash2): + num = 0 + for index in range(len(hash1)): + if hash1[index] != hash2[index]: + num += 1 + return num + + +def url2Array(url, enable_ex=True): + try: + response = requests.get(url) + image = Image.open(BytesIO(response.content)) + image1 = np.array(image) + img_bgr = cv2.cvtColor(image1, cv2.COLOR_RGB2BGR) + return img_bgr + except Exception: + logger.exception("url地址请求异常: {}", format_exc()) + if enable_ex: + raise ServiceException(ExceptionType.URL_ADDRESS_ACCESS_FAILED.value[0], + ExceptionType.URL_ADDRESS_ACCESS_FAILED.value[1]) + return None + + +def url2Content(url): + response = requests.get(url) + return response.content + + +def url2Image(url): + response = requests.get(url) + image = Image.open(BytesIO(response.content)) + image1 = np.array(image) + img_bgr = cv2.cvtColor(image1, cv2.COLOR_RGB2BGR) + img = Image.fromarray(img_bgr) + return img + + +def url2Byte(url): + response = requests.get(url) + return BytesIO(response.content) + + +def markRectangle(url, text, textCoordinate, imageLeftUpCoordinate, imageRightDownCoordinate, color): + img = url2Array(url) + # ( 蓝, 绿, 红) + # 红色 (0, 0, 255) + # 洋红色 (255, 0, 255) + # 青色 (255, 255, 0) + # 黑色 (0, 0, 0) + # 蓝色 (255, 0, 0) + # 绿色 (0, 255, 0) + # 黄色 (0, 255, 255) # 不考虑 + cv2.putText(img, text, textCoordinate, cv2.FONT_HERSHEY_SIMPLEX, 1.0, color, 1, cv2.LINE_AA) + # rectangle 坐标的参数格式为左上角(x1, y1),右下角(x2, y2), 颜色 , 粗细 + cv2.rectangle(img, imageLeftUpCoordinate, imageRightDownCoordinate, color, 2) + return img + + +# def draw_painting_joint(img, xywh, score=0.5, color=None, +# font={'line_thickness': None, 'boxLine_thickness': None, 'fontSize': None}): +# imh, imw, imc = img.shape +# tl = font['line_thickness'] or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 +# box_tl = font['boxLine_thickness'] or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1 # 根据图像的尺寸计算出适合用于绘制图像边框的线宽。 +# c1, c2 = (int(xywh[0]), int(xywh[1])), (int(xywh[2]), int(xywh[3])) +# cv2.rectangle(img, c1, c2, color, thickness=box_tl, lineType=cv2.LINE_AA) +# +# label = ' %.2f' % (score) +# tf = max(tl, 1) # font thickness +# fontScale = font['fontSize'] or tl * 0.33 +# t_size = cv2.getTextSize(label, 0, fontScale=fontScale, thickness=tf)[0] +# cv2.rectangle(img, (int(box[0]) + lw, int(box[1])), c2, color, -1, cv2.LINE_AA) # filled +# cv2.putText(img, label, (c1[0] + lw, c1[1] - (lh - t_size[1]) // 2), 0, fontScale, [225, 255, 255], thickness=tf, +# lineType=cv2.LINE_AA) +# # print('#####line224 fontScale:',fontScale,' thickness:',tf,' line_thickness:',font['line_thickness'],' boxLine thickness:',box_tl) +# return img + + +def img_pad(img, size, pad_value=[114, 114, 114]): + ###填充成固定尺寸 + H, W, _ = img.shape + r = max(H / size[0], W / size[1]) + img_r = cv2.resize(img, (int(W / r), int(H / r))) + tb = size[0] - img_r.shape[0] + lr = size[1] - img_r.shape[1] + top = int(tb / 2) + bottom = tb - top + left = int(lr / 2) + right = lr - left + pad_image = cv2.copyMakeBorder(img_r, top, bottom, left, right, cv2.BORDER_CONSTANT, value=pad_value) + return pad_image, (top, left, r) + + +def letterbox(img, new_shape=(640, 640), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True, stride=32): + # 调整图像大小和填充图像,同时满足步幅多重约束 + shape = img.shape[:2] # current shape [height, width] 当前形状 [高度、宽度] + if isinstance(new_shape, int): + new_shape = (new_shape, new_shape) + + # Scale ratio (new / old) 缩放比例(新/旧) + r = min(new_shape[0] / shape[0], new_shape[1] / shape[1]) + if not scaleup: # 仅缩减,不纵向扩展(为了更好的测试 mAP) + r = min(r, 1.0) + + ratio = r, r # width, height ratios 宽度、高度比 + new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r)) + dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1] # wh padding + if auto: # 最小矩形 + dw, dh = np.mod(dw, stride), np.mod(dh, stride) # wh padding + elif scaleFill: # stretch + dw, dh = 0.0, 0.0 + new_unpad = (new_shape[1], new_shape[0]) + ratio = new_shape[1] / shape[1], new_shape[0] / shape[0] # width, height ratios + + dw /= 2 # divide padding into 2 sides + dh /= 2 + + if shape[::-1] != new_unpad: # resize + img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR) + top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1)) + left, right = int(round(dw - 0.1)), int(round(dw + 0.1)) + img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color) # add border + return img, ratio, (dw, dh) + +# if __name__ == '__main__': +# # img = cv2.imread("../test/a.jpg", -1) +# # fontcolor = 'yellow' +# # +# # water = TextWaterMark() +# # text = "hello world" +# # +# # # fill_img = water.common_water(img, text, position=4, fontface='../font/庞门正道标题体2.0增强版.ttf', fontsize=20, fontcolor='black') +# # fill_img = water.fill_water(img, text, 20) +# # # 一定要保存为png格式 +# # cv2.imshow('result', fill_img) +# # cv2.waitKey(111111110) +# # print('finish') +# pic = PictureWaterMark() +# image = cv2.imread("a.jpg") +# logo = cv2.imread("../image/logo.png", -1) +# # print(image, logo) +# start = time.time() +# frame = pic.common_water(image, logo) +# print(time.time() - start) +# start1 = time.time() +# frame1 = pic.common_water_1(image, logo) +# # cv2.imwrite("watermarked.jpg", frame1) +# print(time.time() - start1) +# # cap = cv2.VideoCapture("../data/111111.mp4") +# # logo = cv2.imread("../image/logo.png", -1) +# # while True: +# # is_opened, frame = cap.read() +# # frame = pic.common_water(frame, logo) +# # cv2.imshow('frame', frame) +# # cv2.waitKey(1) # 等待输入任何按键 +# # # 关闭 +# # cap.release() diff --git a/vodsdk/util/ImgBaiduSdk.py b/vodsdk/util/ImgBaiduSdk.py new file mode 100644 index 0000000..6ebf0a2 --- /dev/null +++ b/vodsdk/util/ImgBaiduSdk.py @@ -0,0 +1,295 @@ +# -*- coding: utf-8 -*- +import time +import traceback +from os.path import join + +from aip import AipImageClassify, AipBodyAnalysis +from loguru import logger + +from common.YmlConstant import baidu_yml_path +from enums.BaiduSdkEnum import BAIDUERRORDATA +from enums.ExceptionEnum import ExceptionType +from exception.CustomerException import ServiceException +from util.ImageUtils import url2Content +from util.RWUtils import getConfigs + + +class AipImageClassifyClient: + + __slots__ = ('__client', '__config') + + def __init__(self, base_dir, env): + self.__client = None + self.__config = getConfigs(join(base_dir, baidu_yml_path % env)) + self.init_client() + # self.lock = Lock() + + def init_client(self): + if self.__client is None: + self.__client = AipImageClassify(str(self.__config["vehicle"]["APP_ID"]), + self.__config["vehicle"]["API_KEY"], + self.__config["vehicle"]["SECRET_KEY"]) + + ''' + 车辆检测 + ''' + + def vehicleDetectUrl(self, url, request_id, options={}): + self.init_client() + # try: + # self.lock.acquire() + reply_num = 0 + reply_value = None + while True: + try: + options["show"] = "true" + res_image = self.__client.vehicleDetectUrl(url, options) + error_code = res_image.get("error_code") + if error_code: + enum = BAIDUERRORDATA.get(error_code) + # 如果异常编码未知, 返回空值 + if enum is None: + logger.error("百度云车辆检测异常!error_code:{}, request_id: {}", error_code, request_id) + return None + # 重试指定次数后,还是异常,输出统一内部异常 + if enum.value[3] == 0: + if reply_value is None: + reply_value = enum.value[4] + logger.error("百度云车辆检测异常!error_code:{}, error_msg:{}, reply_num:{}, request_id: {}", + enum.value[0], enum.value[2], reply_num, request_id) + raise Exception() + # 重试指定次数后,还是异常,输出对应的异常 + if enum.value[3] == 1: + if reply_value is None: + reply_value = enum.value[4] + raise ServiceException(str(enum.value[0]), enum.value[2]) + # 重试指定次数后,还是异常,输出空 + if enum.value[3] == 2: + if reply_value is None: + reply_value = enum.value[4] + if reply_num >= reply_value: + return None + raise Exception() + return res_image + except Exception as e: + time.sleep(1) + reply_num += 1 + self.init_client() + if reply_num > reply_value: + if isinstance(e, ServiceException): + raise ServiceException(e.code, e.msg) + logger.error("车辆检测识别失败: {}, request_id: {}", traceback.format_exc(), request_id) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + # except Exception as ee: + # logger.exception("车辆检测加锁异常: {}, request_id: {}", ee, request_id) + # raise ServiceException(ExceptionType.UNIVERSAL_TEXT_RECOGNITION_FAILED.value[0], + # ExceptionType.UNIVERSAL_TEXT_RECOGNITION_FAILED.value[1]) + # finally: + # self.lock.release() + + ''' + 车辆检测 + ''' + + def vehicleDetect(self, iamge, request_id, options={}): + self.init_client() + # try: + # self.lock.acquire() + reply_num = 0 + reply_value = None + while True: + try: + options["show"] = "true" + res_image = self.__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:{}, request_id: {}", error_code, request_id) + return None + # 重试指定次数后,还是异常,输出统一内部异常 + if enum.value[3] == 0: + if reply_value is None: + reply_value = enum.value[4] + logger.error("百度云车辆检测异常!error_code:{}, error_msg:{}, reply_num:{}, request_id: {}", + enum.value[0], enum.value[2], reply_num, request_id) + raise Exception() + # 重试指定次数后,还是异常,输出对应的异常 + if enum.value[3] == 1: + if reply_value is None: + reply_value = enum.value[4] + raise ServiceException(str(enum.value[0]), enum.value[2]) + # 重试指定次数后,还是异常,输出空 + if enum.value[3] == 2: + if reply_value is None: + reply_value = enum.value[4] + if reply_num >= reply_value: + return None + raise Exception() + return res_image + except Exception as e: + time.sleep(1) + reply_num += 1 + self.init_client() + if reply_num > reply_value: + if isinstance(e, ServiceException): + raise ServiceException(e.code, e.msg) + logger.error("车辆检测识别失败: {}, request_id: {}", traceback.format_exc(), request_id) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + + +class AipBodyAnalysisClient: + + __slots__ = ('__config', '__client') + + def __init__(self, base_dir, env): + self.__client = None + self.__config = getConfigs(join(base_dir, baidu_yml_path % env)) + self.init_client() + # self.lock = Lock() + + def init_client(self): + if self.__client is None: + self.__client = AipBodyAnalysis(str(self.__config["person"]["APP_ID"]), self.__config["person"]["API_KEY"], + self.__config["person"]["SECRET_KEY"]) + + ''' + 人体检测与属性识别 + ''' + + def bodyAttr(self, url, request_id, options={}): + self.init_client() + image = self.readImage(url, request_id) + # try: + # self.lock.acquire() + reply_num = 0 + reply_value = None + while True: + try: + options["show"] = "true" + res_image = self.__client.bodyAttr(image, options) + error_code = res_image.get("error_code") + if error_code: + enum = BAIDUERRORDATA.get(error_code) + # 如果异常编码未知, 返回空值 + if enum is None: + logger.error("百度云人体检测与属性识别异常!error_code:{}, request_id: {}", error_code, request_id) + return None + # 重试指定次数后,还是异常,输出统一内部异常 + if enum.value[3] == 0: + if reply_value is None: + reply_value = enum.value[4] + logger.error("百度云人体检测与属性识别异常!error_code:{}, error_msg:{}, reply_num:{}, request_id: {}", + enum.value[0], enum.value[2], reply_num, request_id) + raise Exception() + # 重试指定次数后,还是异常,输出对应的异常 + if enum.value[3] == 1: + if reply_value is None: + reply_value = enum.value[4] + raise ServiceException(str(enum.value[0]), enum.value[2]) + # 重试指定次数后,还是异常,输出空 + if enum.value[3] == 2: + if reply_value is None: + reply_value = enum.value[4] + if reply_num >= reply_value: + return None + raise Exception() + return res_image + except Exception as e: + time.sleep(0.5) + reply_num += 1 + self.init_client() + if reply_num > reply_value: + if isinstance(e, ServiceException): + raise ServiceException(e.code, e.msg) + logger.error("人体检测与属性识别失败: {}, request_id: {}", traceback.format_exc(), request_id) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + # except Exception as ee: + # logger.exception("车辆检测加锁异常: {}, request_id: {}", ee, request_id) + # raise ServiceException(ExceptionType.UNIVERSAL_TEXT_RECOGNITION_FAILED.value[0], + # ExceptionType.UNIVERSAL_TEXT_RECOGNITION_FAILED.value[1]) + # finally: + # self.lock.release() + + ''' + 人流量统计 + ''' + + def bodyNum(self, url, request_id, options={}): + self.init_client() + image = self.readImage(url, request_id) + # try: + # self.lock.acquire() + reply_num = 0 + reply_value = None + while True: + try: + options["show"] = "true" + res_image = self.__client.bodyNum(image, options) + error_code = res_image.get("error_code") + if error_code: + enum = BAIDUERRORDATA.get(error_code) + # 如果异常编码未知, 返回空值 + if enum is None: + logger.error("百度云人流量统计异常!error_code:{}, request_id: {}", error_code, request_id) + return None + # 重试指定次数后,还是异常,输出统一内部异常 + if enum.value[3] == 0: + if reply_value is None: + reply_value = enum.value[4] + logger.error("百度云人流量统计异常!error_code:{}, error_msg:{}, reply_num:{}, request_id: {}", + enum.value[0], enum.value[2], reply_num, request_id) + raise Exception() + # 重试指定次数后,还是异常,输出对应的异常 + if enum.value[3] == 1: + if reply_value is None: + reply_value = enum.value[4] + raise ServiceException(str(enum.value[0]), enum.value[2]) + # 重试指定次数后,还是异常,输出空 + if enum.value[3] == 2: + if reply_value is None: + reply_value = enum.value[4] + if reply_num >= reply_value: + return None + raise Exception() + return res_image + except Exception as e: + time.sleep(0.5) + reply_num += 1 + self.init_client() + if reply_num > reply_value: + if isinstance(e, ServiceException): + raise ServiceException(e.code, e.msg) + logger.exception("人流量统计失败: {}, request_id: {}", traceback.format_exc(), request_id) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + # except Exception as ee: + # logger.exception("车辆检测加锁异常: {}, request_id: {}", ee, request_id) + # raise ServiceException(ExceptionType.UNIVERSAL_TEXT_RECOGNITION_FAILED.value[0], + # ExceptionType.UNIVERSAL_TEXT_RECOGNITION_FAILED.value[1]) + # finally: + # self.lock.release() + + def readImage(self, url, request_id): + try: + return url2Content(url) + except Exception as e: + logger.error("读取图片异常!url: {}, request_id: {}, 异常信息:{}", url, request_id, traceback.format_exc()) + raise ServiceException(ExceptionType.READ_IAMGE_URL_EXCEPTION.value[0], + ExceptionType.READ_IAMGE_URL_EXCEPTION.value[1]) + +# if __name__ == '__main__': +# with open(r"D:\work\alg_new\tuoheng_alg\dsp_dev_service.yml", "r", encoding='utf-8') as f: +# file_content = f.read() +# content = yaml.load(file_content, yaml.FullLoader) +# aipImageClassifyClient = AipImageClassifyClient(content) +# aipBodyAnalysisClient = AipBodyAnalysisClient(content) +# url = "https://pic.52112.com/180623/JPG-180623-12/c4cyivkxEh_small.jpg" +# # result = aipImageClassifyClient.vehicleDetectUrl(url, "1111111") +# result = aipBodyAnalysisClient.bodyNum(url, "1111111") +# iamge = base64.b64decode(result.get("image")) +# print(iamge) diff --git a/vodsdk/util/KafkaUtils.py b/vodsdk/util/KafkaUtils.py new file mode 100644 index 0000000..b8e83c7 --- /dev/null +++ b/vodsdk/util/KafkaUtils.py @@ -0,0 +1,167 @@ +# -*- coding: utf-8 -*- +import time +from json import dumps, loads +from traceback import format_exc + +from kafka import KafkaProducer, KafkaConsumer, TopicPartition, OffsetAndMetadata +from loguru import logger + + +# 生产者 +class CustomerKafkaProducer: + __slots__ = ( + '__configs', + 'customerProducer', + '__bootstrap_servers' + ) + + def __init__(self, kafka_config): + self.__configs = kafka_config["producer"] + self.__bootstrap_servers = kafka_config["bootstrap_servers"] + self.customerProducer = None + self.get_producer() + + # 获取kafka生产者 + def get_producer(self): + if self.customerProducer is None: + logger.info("配置kafka生产者!") + self.customerProducer = KafkaProducer( + bootstrap_servers=self.__bootstrap_servers, + acks=self.__configs["acks"], + retries=self.__configs["retries"], + linger_ms=self.__configs["linger_ms"], + retry_backoff_ms=self.__configs["retry_backoff_ms"], + max_in_flight_requests_per_connection=self.__configs["max_in_flight_requests_per_connection"], + key_serializer=lambda m: dumps(m).encode("utf-8"), + value_serializer=lambda m: dumps(m).encode("utf-8")) + + # mode 模式1:异步发送 2:同步发送 + # def on_send_success(record_metadata): 成功回调 + # def on_send_error(exc): 失败回调 + def sender(self, topic, key, message, mode=1, customer_send_success=None, customer_send_error=None): + retry_send_num = 0 + while True: + try: + self.get_producer() + logger.info("kafka发送信息,topic:{}|key:{}|message:{}|mode:{}|requestId:{}", topic, key, message, mode, + message.get("request_id")) + if mode == 1: + if not customer_send_success: + customer_send_success = CustomerKafkaProducer.on_send_success + if not customer_send_error: + customer_send_error = CustomerKafkaProducer.on_send_error + self.customerProducer.send(topic=topic, key=key, value=message) \ + .add_callback(customer_send_success, message.get("request_id")) \ + .add_errback(customer_send_error, message.get("request_id")) + if mode == 2: + try: + self.customerProducer.send(topic=topic, key=key, value=message).get(timeout=30) + logger.info("kafka同步发送信息成功, requestId:{}", message.get("request_id")) + except Exception as ke: + logger.error("kafka同步发送消息异常: {}, requestId:{}", format_exc(), + message.get("request_id")) + raise ke + break + except Exception as e: + retry_send_num += 1 + logger.error("kafka发送消息异常, 开始重试, 当前重试次数:{} requestId:{}", retry_send_num, + message.get("request_id")) + time.sleep(1) + self.customerProducer = None + if retry_send_num > 3: + logger.error("kafka发送消息重试失败: {}, requestId:{}", format_exc(), + message.get("request_id")) + raise e + + def close_producer(self): + self.customerProducer.flush() + self.customerProducer.close() + logger.info("kafka生产者关闭完成!") + + @staticmethod + def on_send_success(requestId, record_metadata): + logger.info("kafka异步发送信息成功,topic:{}|partition:{}|offset:{}|requestId:{}", record_metadata.topic, + record_metadata.partition, record_metadata.offset, requestId) + + @staticmethod + def on_send_error(requestId, exc): + logger.exception("kafka异步发送消息异常: {}, requestId:{}", exc, requestId) + + +# 生产者 +class CustomerKafkaConsumer: + __slots__ = ('__configs', 'customerConsumer', '__bootstrap_servers', '__topics') + + def __init__(self, kafka_config, topics=()): + logger.info("初始化消费者") + self.__configs = kafka_config["consumer"] + self.__bootstrap_servers = kafka_config["bootstrap_servers"] + self.customerConsumer = None + self.__topics = topics + self.subscribe() + logger.info("初始化消费者完成") + + def subscribe(self): + if self.customerConsumer is None: + logger.info("获取消费者!") + self.customerConsumer = KafkaConsumer( + bootstrap_servers=self.__bootstrap_servers, + # client_id=self.__configs[KAFKA_CLIENT_ID], + group_id=self.__configs["group_id"], + auto_offset_reset=self.__configs["auto_offset_reset"], + enable_auto_commit=bool(self.__configs["enable_auto_commit"]), + max_poll_records=self.__configs["max_poll_records"], + value_deserializer=lambda m: loads(m.decode("utf-8"))) + logger.info("kafka生产者订阅topic:{}", self.__topics) + # if self.topics is None or len(self.topics) == 0: + # logger.error("消费者订阅topic不能为空!") + # raise Exception("消费者订阅topic不能为空!") + # # 手动配置分区 + # customer_partition = [] + # for topic in self.topics: + # for p in self.content["kafka"][self.content["dsp"]["active"]][topic]["partition"]: + # customer_partition.append(TopicPartition(topic, p)) + # self.customerConsumer.assign(customer_partition) + # 自动配置 + self.customerConsumer.subscribe(topics=self.__topics) + logger.info("kafka生产者订阅topic完成") + + def poll(self): + msg = None + try: + self.subscribe() + msg = self.customerConsumer.poll() + except Exception: + self.customerConsumer = None + logger.error("消费者拉取消息异常: {}", format_exc()) + return msg + + def commit_offset(self, message, request_id,log=True): + retry_num = 0 + topic = message.topic + offset = message.offset + 1 + partition = message.partition + while True: + try: + self.subscribe() + if log: logger.info("消费者开始提交offset,topic:{}|offset:{}|partition:{}|requestId:{}", topic, offset, partition, + request_id) + tp = TopicPartition(topic=topic, partition=partition) + self.customerConsumer.commit(offsets={tp: (OffsetAndMetadata(offset, None))}) + if log: logger.info("消费者提交offset完成,topic:{}|offset:{}|partition:{}|requestId:{}", topic, offset, partition, + request_id) + break + except Exception: + self.customerConsumer = None + if log: logger.error("消费者提交offset异常: {}, 重试次数: {}, requestId:{}", format_exc(), retry_num, request_id) + time.sleep(1) + retry_num += 1 + if retry_num > 3: + if log : logger.error("消费者提交offset重试失败: {}, requestId:{}", format_exc(), request_id) + break + +# if __name__=="__main__": +# try: +# 1/0 +# except Exception as e: +# logger.exception("aaaaa:{} {}", e, "11111") diff --git a/vodsdk/util/LocationUtils.py b/vodsdk/util/LocationUtils.py new file mode 100644 index 0000000..d63c473 --- /dev/null +++ b/vodsdk/util/LocationUtils.py @@ -0,0 +1,156 @@ + +import os,math +import numpy as np + +# WGS-84经纬度转Web墨卡托 +def wgs_to_mercator(x, y): + y = 85.0511287798 if y > 85.0511287798 else y + y = -85.0511287798 if y < -85.0511287798 else y + + x2 = x * 20037508.34 / 180.0 + y2 = math.log(math.tan((90.0 + y) * math.pi / 360.0)) / (math.pi / 180.0) + + #print( ' y:',y, " before Log:",math.tan((90.0 + y) * math.pi / 360.0), ' log:' , math.log(math.tan((90.0 + y) * math.pi / 360.0))) + y2 = y2 * 20037508.34 / 180.0 + return x2, y2 +def mercator_to_wgs(x, y): + """ + 将墨卡托投影坐标转换为WGS-84经纬度坐标 + :param x: 墨卡托投影的X坐标 + :param y: 墨卡托投影的Y坐标 + :return: 经度(longitude)和纬度(latitude) + """ + # 地球半径(米) + R = 6378137.0 + # 墨卡托投影的X坐标转换为经度 + lon = x / R * 180.0 / math.pi + # 墨卡托投影的Y坐标转换为纬度 + lat = math.atan(math.sinh(y / R)) * 180.0 / math.pi + return lon, lat + + +def ImageCorToCamCor(p0,w=1920,h=1080): + x,y=p0[0:2] + return x-w/2.,(h-y)-h/2. + +def wgs84_to_gcj02(lat, lon): + """将 WGS-84 坐标转换为 GCJ-02 坐标 (高德地图坐标)""" + A = 6378245.0 # 长半轴 + EE = 0.00669342162296594323 # 偏心率平方 + if out_of_china(lat, lon): + return lat, lon # 如果在中国以外,直接返回 WGS-84 坐标 + + # 坐标转换 + dlat = transform_lat(lon - 105.0, lat - 35.0) + dlon = transform_lon(lon - 105.0, lat - 35.0) + radlat = lat / 180.0 * math.pi + magic = math.sin(radlat) + magic = 1 - EE * magic * magic + sqrt_magic = math.sqrt(magic) + dlat = (dlat * 180.0) / (A * (1 - EE) / (magic * sqrt_magic) * math.pi) + dlon = (dlon * 180.0) / (A / sqrt_magic * math.cos(radlat) * math.pi) + + mg_lat = lat + dlat + mg_lon = lon + dlon + + return mg_lat, mg_lon + +def out_of_china(lat, lon): + """检查坐标是否在中国以外""" + return lon < 72.004 or lon > 137.8347 or lat < 0.8293 or lat > 55.8271 + +def transform_lat(lon, lat): + """辅助函数: 进行纬度转换""" + ret = (-100.0 + 2.0 * lon + 3.0 * lat + 0.2 * lat * lat + + 0.1 * lon * lat + 0.2 * math.sqrt(abs(lon))) + ret += (20.0 * math.sin(6.0 * lon * PI) + 20.0 * math.sin(2.0 * lon * PI)) * 2.0 / 3.0 + ret += (20.0 * math.sin(lat * PI) + 40.0 * math.sin(lat / 3.0 * PI)) * 2.0 / 3.0 + ret += (160.0 * math.sin(lat / 12.0 * PI) + 320.0 * math.sin(lat * PI / 30.0)) * 2.0 / 3.0 + return ret + +def transform_lon(lon, lat): + """辅助函数: 进行经度转换""" + ret = (300.0 + lon + 2.0 * lat + 0.1 * lon * lon + + 0.1 * lon * lat + 0.1 * math.sqrt(abs(lon))) + ret += (20.0 * math.sin(6.0 * lon * PI) + 20.0 * math.sin(2.0 * lon * PI)) * 2.0 / 3.0 + ret += (20.0 * math.sin(lon * PI) + 40.0 * math.sin(lon / 3.0 * PI)) * 2.0 / 3.0 + ret += (150.0 * math.sin(lon / 12.0 * PI) + 300.0 * math.sin(lon / 30.0 * PI)) * 2.0 / 3.0 + return ret + +def cam2word(p0,pUAV,yaw,delta=1.55e-3 * 4056.0/1920,pitch=-45,f=4.5,camH=50e3,igW=1920,igH=1080): + + pitch = pitch/180.0*np.pi + sinp = np.sin(pitch );cosp= np.cos(pitch) + p0_new = ImageCorToCamCor(p0,igW,igH) + Xc0 = p0_new[0]*delta;Zc0 = p0_new[1]*delta; + + #(Zw0,Xw0)--相对于光心,X,Z并未校正到正东和正北。 + #f=4.5*f/24.00 + Zw0=camH*( -f*sinp + Zc0*cosp )/( f*cosp + Zc0*sinp)*1e-3 + Xw0= camH*Xc0/(f*cosp + Zc0*sinp)*1e-3 + #print(' %4.0f %4.0f %4.8f %4.8f %4.8f %4.8f f:%.2f'%( p0[0],p0[1], Xc0, Zc0,Xw0,Zw0,f ) ) + #yaw定义为拍摄方向,即图片的高方位(Z方向)偏离正北的方向,北偏东为正。 + yaw_rad = yaw/180.0*np.pi + siny=np.sin(yaw_rad);cosy=np.cos(yaw_rad) + Zx0_rot = Xw0*cosy + Zw0*siny + pUAV[0] + Zw0_rot = -Xw0*siny + Zw0*cosy + pUAV[1] + + + return Zx0_rot,Zw0_rot + +def location( point,igW,igH,PlanWgs84,PlanH,yaw,delta,pitch,focal,outFormat='wgs84'): + ''' + 输入图像中点的X,Y坐标,及无人机相关信息、相机相关信息,输出该点的Wgs84经纬度坐标 + point--点在图像上的坐标,左上角为(0,0),X方向为宽度方向,Y方向为高度方向 + igW--图像的宽度 + igH--图像的高度 + PlanWgs84--无人机的Wgs84坐标,(lon,lat),(经度,纬度) + PlanH--无人机拍照时的相对高度,用mm表示 + yaw--云台的yaw + delta--单个像素的长度值,用mm表示。 + pitch--无人的pitch + focal--真实焦距,用mm表示 + ''' + PlanX,PlanY = wgs_to_mercator(PlanWgs84[0],PlanWgs84[1]) + #print('location:',PlanX,PlanY) + #PlanX,PlanY--东西、南北方向的墨卡托投影坐标 + #print( 'line268:',point,PlanX,PlanY,yaw, delta,pitch,focal,PlanH,igW,igH ) + cor_world = cam2word( point,(PlanX,PlanY),yaw, delta,pitch,focal,PlanH,igW,igH) + cor_world = mercator_to_wgs(cor_world[0], cor_world[1]) + if outFormat=='GCJ02' or outFormat=='gcj02': + cor_world = wgs84_to_gcj02(cor_world[0], cor_world[1]) + + return cor_world + +def locate_byMqtt(box,igW,igH,camParas,outFormat='wgs84'): + #camParas--{'lon': 3479.8250608, 'lat': 3566.7630802, 'gpssingal': 4, 'satcount': 6896, 'alt': 3.256, 'hspeed': 86.0, 'vspeed': 4.447911, 'ysingal': 0, 'tsingal': 0, 'voltage': 24.971, 'flytime': 0, 'datetime': 1739315683895, 'yaw': 70.243252, 'roll': -0.89436062, 'pitch': 0.89897547, 'armed': 'false', 'mode': 'stabilize', 'distToHome': 7.132033, 'deviceid': 'THJSQ03A2302KSPYGJ2G', 'mileage': '0', 'altasl': 21.26, 'altasl2': -20.74, 'landing_target_x': 0, 'landing_target_y': 0, 'landing_target_z': 0} + #模型输出的点的格式是-[(486, 264), (505, 264), (505, 290), (486, 290)] + + box_np = np.array(box); + point = int(np.mean( box_np[:,0] )) , int(np.mean( box_np[:,1] )) + PlanWgs84 = (float(camParas['lon']),float(camParas['lat'])) # + PlanH = float(camParas['alt'])# + yaw = float(camParas['camerayaw']) + #delta = camParas[''] + delta = 1.55e-3 * 4056.0/1920 + pitch = float(camParas['camerapitch']) + #focal = camParas[''] + focal = 3.5 + + out = location( point,igW,igH,PlanWgs84,PlanH,yaw,delta,pitch,focal,outFormat='wgs84') + return out + +if __name__=="__main__": + srt="videos/DJI_20221220133918_0001_W_0.SRT" + videoUrl = "videos/DJI_20221220133918_0001_W.MP4" + imgOut= "videos/imgs" + fpbeg=17273;fpend=17830 + nums = list(range(fpbeg,fpend,16)) + #generateNewSRT(srt) + #captureImages(videoUrl,nums,imgOut) + + process(videoUrl,srt,nums,imW=1920,imH=1080,txtDir='videos/labels' ) + #draw_results() + + #rotate_example() + #rotate_example3() \ No newline at end of file diff --git a/vodsdk/util/LogUtils.py b/vodsdk/util/LogUtils.py new file mode 100644 index 0000000..4aefeb6 --- /dev/null +++ b/vodsdk/util/LogUtils.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +import sys +from os import makedirs +from os.path import join, exists +from loguru import logger +from util.RWUtils import getConfigs + + +# 初始化日志配置 +def init_log(base_dir, env): + log_config = getConfigs(join(base_dir, 'config/logger/dsp_%s_logger.yml' % env)) + # 判断日志文件是否存在,不存在创建 + base_path = join(base_dir, log_config.get("base_path")) + if not exists(base_path): + makedirs(base_path) + # 移除日志设置 + logger.remove(handler_id=None) + # 打印日志到文件 + if bool(log_config.get("enable_file_log")): + logger.add(join(base_path, log_config.get("log_name")), + rotation=log_config.get("rotation"), + retention=log_config.get("retention"), + format=log_config.get("log_fmt"), + level=log_config.get("level"), + enqueue=True, + encoding=log_config.get("encoding")) + # 控制台输出 + if bool(log_config.get("enable_stderr")): + logger.add(sys.stderr, + format=log_config.get("log_fmt"), + level=log_config.get("level"), + enqueue=True) diff --git a/vodsdk/util/MinioSdk.py b/vodsdk/util/MinioSdk.py new file mode 100644 index 0000000..591532b --- /dev/null +++ b/vodsdk/util/MinioSdk.py @@ -0,0 +1,121 @@ +# -*- coding: utf-8 -*- +from json import loads +from os.path import join,basename +from traceback import format_exc +import oss2 +import string,random,os +import time +from common.YmlConstant import minio_yml_path +from minio import Minio +from loguru import logger +from exception.CustomerException import ServiceException +from enums.ExceptionEnum import ExceptionType +from util.RWUtils import getConfigs +import filetype,cv2,io +import numpy as np + +class MinioSdk: + + __slots__ = ('minioClient', '__request_id', '__config') + + def __init__(self, *args): + base_dir, env, self.__request_id = args + self.minioClient = None + self.__config = getConfigs(join(base_dir, minio_yml_path % env)) + self.get_minioClient() + + def get_minioClient(self): + if self.minioClient is None: + self.minioClient = Minio( + endpoint=self.__config["endpoint"], + access_key=self.__config["access_key"], + secret_key=self.__config["secret_key"], + secure=self.__config["secure"] + ) + + def get_bucknetName_from_filename(self,localPath): + if isinstance(localPath,np.ndarray): + return self.__config["image_bucket"],'jpg' + ret = filetype.guess(localPath) + if 'video' in ret.mime: + return self.__config["video_bucket"],ret.mime + elif 'image' in ret.mime: + return self.__config["image_bucket"],ret.mime + else: + logger.warning("上传文件到格式不是图片,或者视频, requestId:{}", self.__request_id) + return self.__config["image_bucket"],'.oth' + def create_bucknet(self,bucketName): + if not self.minioClient.bucket_exists(bucketName): + self.minioClient.make_bucket(bucketName) + + def put_object(self, localPath, remotePath): + #localPath--本地文件路径,带有后缀---或者是字节流 + #remotePath--远程文件的名字,不带文件夹,不带后缀(为了与原OSS保持一致) + request_id = self.__request_id + logger.info("开始上传文件到oss, requestId:{}", request_id) + bucketName,mime = self.get_bucknetName_from_filename(localPath) + + self.create_bucknet(bucketName) + if '/' not in remotePath: + remoteUrl=join(request_id,remotePath ) + else: remoteUrl = remotePath + max_retries = 3 + retry_count = 0 + while True: + try: + self.get_minioClient() + + if isinstance(localPath,np.ndarray): + image_bytes = io.BytesIO(localPath) + #image_bytes = localPath.tobytes() + # 上传图片数据流 + ret = self.minioClient.put_object(bucketName, remoteUrl,image_bytes, len(localPath)) + else: + if 'video' in mime:# + newLocalpath = os.path.join( os.path.dirname(localPath), ''.join(random.sample(string.ascii_letters ,32))+'.mp4' ) + cmd1 = 'ffmpeg -i %s -vcodec libx264 -acodec copy %s'%(localPath, newLocalpath ) + os.system(cmd1 ) + cmd2 = 'mv %s %s'%(newLocalpath,localPath ) + os.system(cmd2 ) + ret = self.minioClient.fput_object(bucketName, remoteUrl,localPath,content_type=mime) + #print('-----line72: mime:',mime) + + #outurl='http://'+self.__config["endpoint"]+'/'+bucketName+'/'+remoteUrl + outurl=self.__config["domain"]+'/'+bucketName+'/'+remoteUrl + logger.info("上传文件到minio成功! requestId:{},bucketName:{},objectName:{},remoteUrl:{}", request_id,ret.bucket_name,ret.object_name,outurl) + return outurl + except Exception as e: + retry_count += 1 + time.sleep(1) + self.minioClient = None + logger.info("上传文件到minio失败, 重试次数:{}, requestId:{}", retry_count, request_id) + if retry_count > max_retries: + logger.error("上传文件到oss重试失败:{}, requestId:{}", format_exc(), request_id) + raise e + +if __name__ == "__main__": + + base_dir, env, request_id = '/home/th/WJ/test/tuoheng_alg','test','1122334455667788' + #localPath = '/home/th/WJ/data/XunHe/ai_online.mp4' + localPath = '/home/th/WJ/data/XunHe/ai_online_avc1.mp4' + #localPath = '/home/th/WJ/DSP2/AIdemo2/images/cityRoad/DJI_0019_142.jpg' + + + remotePath='or.mp4' + minioSdk = MinioSdk(base_dir, env, request_id ) + + ##上传cv2编码后的图像np数组 + #image_array = cv2.imread( localPath ) + #_, localPath = cv2.imencode('.jpg', image_array) + + + minioSdk.put_object(localPath, remotePath) + + + + #http://minio.t-aaron.com:9000/image/1122334455667788/or_.oth + + #http://minio.t-aaron.com:9000/image/messageId/t2.jpg + #messageId/t2.jpg' + + # print(aa.get_play_info('6928821035b171ee9f3b6632b68f0102')) diff --git a/vodsdk/util/ModelUtils.py b/vodsdk/util/ModelUtils.py new file mode 100644 index 0000000..26c7086 --- /dev/null +++ b/vodsdk/util/ModelUtils.py @@ -0,0 +1,644 @@ +# -*- coding: utf-8 -*- +import sys +from pickle import dumps, loads +from traceback import format_exc +import time + +import cv2 +from loguru import logger + +from common.Constant import COLOR +from enums.BaiduSdkEnum import VehicleEnum +from enums.ExceptionEnum import ExceptionType +from enums.ModelTypeEnum import ModelType, BAIDU_MODEL_TARGET_CONFIG +from exception.CustomerException import ServiceException +from util.ImgBaiduSdk import AipBodyAnalysisClient, AipImageClassifyClient +from util.PlotsUtils import get_label_arrays, get_label_array_dict +from util.TorchUtils import select_device + +sys.path.extend(['..', '../AIlib2']) +from AI import AI_process, AI_process_forest, get_postProcess_para, ocr_process, AI_process_N, AI_process_C +from stdc import stdcModel +from segutils.segmodel import SegModel +from models.experimental import attempt_load +from obbUtils.shipUtils import OBB_infer +from obbUtils.load_obb_model import load_model_decoder_OBB +import torch +import tensorrt as trt +from utilsK.jkmUtils import pre_process, post_process, get_return_data +from DMPR import DMPRModel +FONT_PATH = "../AIlib2/conf/platech.ttf" + + +# 河道模型、河道检测模型、交通模型、人员落水模型、城市违章公共模型 +class OneModel: + __slots__ = "model_conf" + + def __init__(self, device, allowedList=None, requestId=None, modeType=None, gpu_name=None, base_dir=None, env=None): + try: + logger.info("########################加载{}########################, requestId:{}", modeType.value[2], + requestId) + par = modeType.value[4](str(device), gpu_name) + mode, postPar, segPar = par.get('mode', 'others'), par.get('postPar'), par.get('segPar') + names = par['labelnames'] + postFile = par['postFile'] + rainbows = postFile["rainbows"] + new_device = select_device(par.get('device')) + half = new_device.type != 'cpu' + Detweights = par['Detweights'] + with open(Detweights, "rb") as f, trt.Runtime(trt.Logger(trt.Logger.ERROR)) as runtime: + model = runtime.deserialize_cuda_engine(f.read()) + par['segPar']['seg_nclass'] = par['seg_nclass'] + Segweights = par['Segweights'] + if Segweights: + if modeType.value[3] == 'cityMangement3': + segmodel = DMPRModel(weights=Segweights, par=par['segPar']) + else: + segmodel = stdcModel(weights=Segweights, par=par['segPar']) + else: + segmodel = None + objectPar = { + 'half': half, + 'device': new_device, + 'conf_thres': postFile["conf_thres"], + 'ovlap_thres_crossCategory': postFile.get("ovlap_thres_crossCategory"), + 'iou_thres': postFile["iou_thres"], + 'allowedList': [], + 'segRegionCnt': par['segRegionCnt'], + 'trtFlag_det': par['trtFlag_det'], + 'trtFlag_seg': par['trtFlag_seg'] + } + model_param = { + "model": model, + "segmodel": segmodel, + "objectPar": objectPar, + "segPar": segPar, + "mode": mode, + "postPar": postPar + } + self.model_conf = (modeType, model_param, allowedList, names, rainbows) + except Exception: + logger.error("模型加载异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) + +class cityManagementModel: + __slots__ = "model_conf" + + def __init__(self, device, allowedList=None, requestId=None, modeType=None, gpu_name=None, base_dir=None, env=None): + try: + logger.info("########################加载{}########################, requestId:{}", modeType.value[2], + requestId) + par = modeType.value[4](str(device), gpu_name) + postProcess = par['postProcess'] + names = par['labelnames'] + postFile = par['postFile'] + rainbows = postFile["rainbows"] + modelList=[ modelPar['model'](weights=modelPar['weight'],par=modelPar['par']) for modelPar in par['models'] ] + model_param = { + "modelList": modelList, + "postProcess": postProcess, + } + self.model_conf = (modeType, model_param, allowedList, names, rainbows) + except Exception: + logger.error("模型加载异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) + +def detSeg_demo2(args): + model_conf, frame, request_id = args + modelList, postProcess = model_conf[1]['modelList'], model_conf[1]['postProcess'] + try: + result = [[ None, None, AI_process_N([frame], modelList, postProcess)[0] ] ] # 为了让返回值适配统一的接口而写的shi + return result + except ServiceException as s: + raise s + except Exception: + # self.num += 1 + # cv2.imwrite('/home/th/tuo_heng/dev/img%s.jpg' % str(self.num), frame) + logger.error("算法模型分析异常:{}, requestId:{}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + + +def model_process(args): + model_conf, frame, request_id = args + model_param, names, rainbows = model_conf[1], model_conf[3], model_conf[4] + # modeType, model_param, allowedList, names, rainbows = model_conf + # segmodel, names, label_arraylist, rainbows, objectPar, font, segPar, mode, postPar, requestId = args + # model_param['digitFont'] = digitFont + # model_param['label_arraylist'] = label_arraylist + # model_param['font_config'] = font_config + try: + return AI_process([frame], model_param['model'], model_param['segmodel'], names, model_param['label_arraylist'], + rainbows, objectPar=model_param['objectPar'], font=model_param['digitFont'], + segPar=loads(dumps(model_param['segPar'])), mode=model_param['mode'], + postPar=model_param['postPar']) + except ServiceException as s: + raise s + except Exception: + # self.num += 1 + # cv2.imwrite('/home/th/tuo_heng/dev/img%s.jpg' % str(self.num), frame) + logger.error("算法模型分析异常:{}, requestId:{}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + + +# 森林模型、车辆模型、行人模型、烟火模型、 钓鱼模型、航道模型、乡村模型、城管模型公共模型 +class TwoModel: + __slots__ = "model_conf" + + def __init__(self, device1, allowedList=None, requestId=None, modeType=None, gpu_name=None, base_dir=None, + env=None): + s = time.time() + try: + logger.info("########################加载{}########################, requestId:{}", modeType.value[2], + requestId) + par = modeType.value[4](str(device1), gpu_name) + device = select_device(par.get('device')) + names = par['labelnames'] + half = device.type != 'cpu' + Detweights = par['Detweights'] + with open(Detweights, "rb") as f, trt.Runtime(trt.Logger(trt.Logger.ERROR)) as runtime: + model = runtime.deserialize_cuda_engine(f.read()) + segmodel = None + postFile = par['postFile'] + conf_thres = postFile["conf_thres"] + iou_thres = postFile["iou_thres"] + rainbows = postFile["rainbows"] + otc = postFile.get("ovlap_thres_crossCategory") + model_param = { + "model": model, + "segmodel": segmodel, + "half": half, + "device": device, + "conf_thres": conf_thres, + "iou_thres": iou_thres, + "trtFlag_det": par['trtFlag_det'], + "otc": otc + } + self.model_conf = (modeType, model_param, allowedList, names, rainbows) + except Exception: + logger.error("模型加载异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) + logger.info("模型初始化时间:{}, requestId:{}", time.time() - s, requestId) + + +def forest_process(args): + model_conf, frame, request_id = args + model_param, names, rainbows = model_conf[1], model_conf[3], model_conf[4] + try: + return AI_process_forest([frame], model_param['model'], model_param['segmodel'], names, + model_param['label_arraylist'], rainbows, model_param['half'], model_param['device'], + model_param['conf_thres'], model_param['iou_thres'], [], font=model_param['digitFont'], + trtFlag_det=model_param['trtFlag_det'], SecNms=model_param['otc']) + except ServiceException as s: + raise s + except Exception: + # self.num += 1 + # cv2.imwrite('/home/th/tuo_heng/dev/img%s.jpg' % str(self.num), frame) + logger.error("算法模型分析异常:{}, requestId:{}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + +class MultiModel: + __slots__ = "model_conf" + + def __init__(self, device1, allowedList=None, requestId=None, modeType=None, gpu_name=None, base_dir=None, + env=None): + s = time.time() + try: + logger.info("########################加载{}########################, requestId:{}", modeType.value[2], + requestId) + par = modeType.value[4](str(device1), gpu_name) + postProcess = par['postProcess'] + names = par['labelnames'] + postFile = par['postFile'] + rainbows = postFile["rainbows"] + modelList=[ modelPar['model'](weights=modelPar['weight'],par=modelPar['par']) for modelPar in par['models'] ] + model_param = { + "modelList": modelList, + "postProcess": postProcess, + } + self.model_conf = (modeType, model_param, allowedList, names, rainbows) + except Exception: + logger.error("模型加载异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) + logger.info("模型初始化时间:{}, requestId:{}", time.time() - s, requestId) + +def channel2_process(args): + model_conf, frame, request_id = args + modelList, postProcess = model_conf[1]['modelList'], model_conf[1]['postProcess'] + try: + start = time.time() + result = [[None, None, AI_process_C([frame], modelList, postProcess)[0]]] # 为了让返回值适配统一的接口而写的shi + # print("AI_process_C use time = {}".format(time.time()-start)) + return result + except ServiceException as s: + raise s + except Exception: + logger.error("算法模型分析异常:{}, requestId:{}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + +def get_label_arraylist(*args): + width, height, names, rainbows = args + # line = int(round(0.002 * (height + width) / 2) + 1) + line = max(1, int(round(width / 1920 * 3))) + label = ' 0.95' + tf = max(line - 1, 1) + fontScale = line * 0.33 + text_width, text_height = cv2.getTextSize(label, 0, fontScale=fontScale, thickness=tf)[0] + # fontsize = int(width / 1920 * 40) + numFontSize = float(format(width / 1920 * 1.1, '.1f')) + digitFont = {'line_thickness': line, + 'boxLine_thickness': line, + 'fontSize': numFontSize, + 'waterLineColor': (0, 255, 255), + 'segLineShow': False, + 'waterLineWidth': line, + 'wordSize': text_height, + 'label_location': 'leftTop'} + label_arraylist = get_label_arrays(names, rainbows, fontSize=text_height, fontPath=FONT_PATH) + return digitFont, label_arraylist, (line, text_width, text_height, fontScale, tf) + + +# 船只模型 +class ShipModel: + __slots__ = "model_conf" + + def __init__(self, device1, allowedList=None, requestId=None, modeType=None, gpu_name=None, base_dir=None, + env=None): + s = time.time() + try: + logger.info("########################加载{}########################, requestId:{}", modeType.value[2], + requestId) + par = modeType.value[4](str(device1), gpu_name) + model, decoder2 = load_model_decoder_OBB(par) + par['decoder'] = decoder2 + names = par['labelnames'] + rainbows = par['postFile']["rainbows"] + model_param = { + "model": model, + "par": par + } + self.model_conf = (modeType, model_param, allowedList, names, rainbows) + except Exception: + logger.exception("模型加载异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) + logger.info("模型初始化时间:{}, requestId:{}", time.time() - s, requestId) + + +def obb_process(args): + model_conf, frame, request_id = args + model_param = model_conf[1] + # font_config, frame, names, label_arrays, rainbows, model, par, requestId = args + try: + return OBB_infer(model_param["model"], frame, model_param["par"]) + except ServiceException as s: + raise s + except Exception: + # self.num += 1 + # cv2.imwrite('/home/th/tuo_heng/dev/img%s.jpg' % str(self.num), frame) + logger.error("算法模型分析异常:{}, requestId:{}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + + +# 车牌分割模型、健康码、行程码分割模型 +class IMModel: + __slots__ = "model_conf" + + def __init__(self, device, allowedList=None, requestId=None, modeType=None, gpu_name=None, base_dir=None, + env=None): + try: + logger.info("########################加载{}########################, requestId:{}", modeType.value[2], + requestId) + img_type = 'code' + if ModelType.PLATE_MODEL == modeType: + img_type = 'plate' + par = { + 'code': {'weights': '../AIlib2/weights/conf/jkm/health_yolov5s_v3.jit', 'img_type': 'code', 'nc': 10}, + 'plate': {'weights': '../AIlib2/weights/conf/jkm/plate_yolov5s_v3.jit', 'img_type': 'plate', 'nc': 1}, + 'conf_thres': 0.4, + 'iou_thres': 0.45, + 'device': 'cuda:%s' % device, + 'plate_dilate': (0.5, 0.3) + } + + new_device = torch.device(par['device']) + model = torch.jit.load(par[img_type]['weights']) + logger.info("########################加载 ../AIlib2/weights/conf/jkm/plate_yolov5s_v3.jit 成功 ########################, requestId:{}", + requestId) + self.model_conf = (modeType, allowedList, new_device, model, par, img_type) + except Exception: + logger.error("模型加载异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) + + +def im_process(args): + frame, device, model, par, img_type, requestId = args + try: + img, padInfos = pre_process(frame, device) + pred = model(img) + boxes = post_process(pred, padInfos, device, conf_thres=par['conf_thres'], + iou_thres=par['iou_thres'], nc=par[img_type]['nc']) # 后处理 + dataBack = get_return_data(frame, boxes, modelType=img_type, plate_dilate=par['plate_dilate']) + print('-------line351----:',dataBack) + return dataBack + except ServiceException as s: + raise s + except Exception: + logger.error("算法模型分析异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + + +# 百度AI图片识别模型 +class BaiduAiImageModel: + __slots__ = "model_conf" + + def __init__(self, device=None, allowedList=None, requestId=None, modeType=None, gpu_name=None, base_dir=None, + env=None): + try: + logger.info("########################加载{}########################, requestId:{}", modeType.value[2], + requestId) + # 人体检测与属性识别、 人流量统计客户端 + aipBodyAnalysisClient = AipBodyAnalysisClient(base_dir, env) + # 车辆检测检测客户端 + aipImageClassifyClient = AipImageClassifyClient(base_dir, env) + rainbows = COLOR + vehicle_names = [VehicleEnum.CAR.value[1], VehicleEnum.TRICYCLE.value[1], VehicleEnum.MOTORBIKE.value[1], + VehicleEnum.CARPLATE.value[1], VehicleEnum.TRUCK.value[1], VehicleEnum.BUS.value[1]] + person_names = ['人'] + self.model_conf = (modeType, aipImageClassifyClient, aipBodyAnalysisClient, allowedList, rainbows, + vehicle_names, person_names, requestId) + except Exception: + logger.exception("模型加载异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) + + +def get_baidu_label_arraylist(*args): + width, height, vehicle_names, person_names, rainbows = args + # line = int(round(0.002 * (height + width) / 2) + 1) + line = max(1, int(round(width / 1920 * 3) + 1)) + label = ' 0.97' + tf = max(line, 1) + fontScale = line * 0.33 + text_width, text_height = cv2.getTextSize(label, 0, fontScale=fontScale, thickness=tf)[0] + vehicle_label_arrays = get_label_arrays(vehicle_names, rainbows, fontSize=text_height, fontPath=FONT_PATH) + person_label_arrays = get_label_arrays(person_names, rainbows, fontSize=text_height, fontPath=FONT_PATH) + font_config = (line, text_width, text_height, fontScale, tf) + return vehicle_label_arrays, person_label_arrays, font_config + + +def baidu_process(args): + target, url, aipImageClassifyClient, aipBodyAnalysisClient, request_id = args + try: + # [target, url, aipImageClassifyClient, aipBodyAnalysisClient, requestId] + baiduEnum = BAIDU_MODEL_TARGET_CONFIG.get(target) + if baiduEnum is None: + raise ServiceException(ExceptionType.DETECTION_TARGET_TYPES_ARE_NOT_SUPPORTED.value[0], + ExceptionType.DETECTION_TARGET_TYPES_ARE_NOT_SUPPORTED.value[1] + + " target: " + target) + return baiduEnum.value[2](aipImageClassifyClient, aipBodyAnalysisClient, url, request_id) + except ServiceException as s: + raise s + except Exception: + logger.error("算法模型分析异常:{}, requestId:{}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + + +def one_label(width, height, model_conf): + # modeType, model_param, allowedList, names, rainbows = model_conf + names = model_conf[3] + rainbows = model_conf[4] + model_param = model_conf[1] + digitFont, label_arraylist, font_config = get_label_arraylist(width, height, names, rainbows) + model_param['digitFont'] = digitFont + model_param['label_arraylist'] = label_arraylist + model_param['font_config'] = font_config + +def dynamics_label(width, height, model_conf): + # modeType, model_param, allowedList, names, rainbows = model_conf + names = model_conf[3] + rainbows = model_conf[4] + model_param = model_conf[1] + digitFont, label_arraylist, font_config = get_label_arraylist(width, height, names, rainbows) + line = max(1, int(round(width / 1920 * 3))) + label = ' 0.95' + tf = max(line - 1, 1) + fontScale = line * 0.33 + _, text_height = cv2.getTextSize(label, 0, fontScale=fontScale, thickness=tf)[0] + label_dict = get_label_array_dict(rainbows, fontSize=text_height, fontPath=FONT_PATH) + model_param['digitFont'] = digitFont + model_param['label_arraylist'] = label_arraylist + model_param['font_config'] = font_config + model_param['label_dict'] = label_dict +def baidu_label(width, height, model_conf): + # modeType, aipImageClassifyClient, aipBodyAnalysisClient, allowedList, rainbows, + # vehicle_names, person_names, requestId + vehicle_names = model_conf[5] + person_names = model_conf[6] + rainbows = model_conf[4] + vehicle_label_arrays, person_label_arrays, font_config = get_baidu_label_arraylist(width, height, vehicle_names, + person_names, rainbows) + return vehicle_label_arrays, person_label_arrays, font_config + + +MODEL_CONFIG = { + # 加载河道模型 + ModelType.WATER_SURFACE_MODEL.value[1]: ( + lambda x, y, r, t, z, h: OneModel(x, y, r, ModelType.WATER_SURFACE_MODEL, t, z, h), + ModelType.WATER_SURFACE_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 加载森林模型 + # ModelType.FOREST_FARM_MODEL.value[1]: ( + # lambda x, y, r, t, z, h: TwoModel(x, y, r, ModelType.FOREST_FARM_MODEL, t, z, h), + # ModelType.FOREST_FARM_MODEL, + # lambda x, y, z: one_label(x, y, z), + # lambda x: forest_process(x) + # ), + ModelType.FOREST_FARM_MODEL.value[1]: ( + lambda x, y, r, t, z, h: cityManagementModel(x, y, r, ModelType.FOREST_FARM_MODEL, t, z, h), + ModelType.FOREST_FARM_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: detSeg_demo2(x) + ), + + # 加载交通模型 + ModelType.TRAFFIC_FARM_MODEL.value[1]: ( + lambda x, y, r, t, z, h: OneModel(x, y, r, ModelType.TRAFFIC_FARM_MODEL, t, z, h), + ModelType.TRAFFIC_FARM_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 加载防疫模型 + ModelType.EPIDEMIC_PREVENTION_MODEL.value[1]: ( + lambda x, y, r, t, z, h: IMModel(x, y, r, ModelType.EPIDEMIC_PREVENTION_MODEL, t, z, h), + ModelType.EPIDEMIC_PREVENTION_MODEL, + None, + lambda x: im_process(x)), + # 加载车牌模型 + ModelType.PLATE_MODEL.value[1]: ( + lambda x, y, r, t, z, h: IMModel(x, y, r, ModelType.PLATE_MODEL, t, z, h), + ModelType.PLATE_MODEL, + None, + lambda x: im_process(x)), + # 加载车辆模型 + ModelType.VEHICLE_MODEL.value[1]: ( + lambda x, y, r, t, z, h: TwoModel(x, y, r, ModelType.VEHICLE_MODEL, t, z, h), + ModelType.VEHICLE_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: forest_process(x) + ), + # 加载行人模型 + ModelType.PEDESTRIAN_MODEL.value[1]: ( + lambda x, y, r, t, z, h: TwoModel(x, y, r, ModelType.PEDESTRIAN_MODEL, t, z, h), + ModelType.PEDESTRIAN_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: forest_process(x)), + # 加载烟火模型 + ModelType.SMOGFIRE_MODEL.value[1]: ( + lambda x, y, r, t, z, h: TwoModel(x, y, r, ModelType.SMOGFIRE_MODEL, t, z, h), + ModelType.SMOGFIRE_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: forest_process(x)), + # 加载钓鱼游泳模型 + ModelType.ANGLERSWIMMER_MODEL.value[1]: ( + lambda x, y, r, t, z, h: TwoModel(x, y, r, ModelType.ANGLERSWIMMER_MODEL, t, z, h), + ModelType.ANGLERSWIMMER_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: forest_process(x)), + # 加载乡村模型 + ModelType.COUNTRYROAD_MODEL.value[1]: ( + lambda x, y, r, t, z, h: TwoModel(x, y, r, ModelType.COUNTRYROAD_MODEL, t, z, h), + ModelType.COUNTRYROAD_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: forest_process(x)), + # 加载船只模型 + ModelType.SHIP_MODEL.value[1]: ( + lambda x, y, r, t, z, h: ShipModel(x, y, r, ModelType.SHIP_MODEL, t, z, h), + ModelType.SHIP_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: obb_process(x)), + # 百度AI图片识别模型 + ModelType.BAIDU_MODEL.value[1]: ( + lambda x, y, r, t, z, h: BaiduAiImageModel(x, y, r, ModelType.BAIDU_MODEL, t, z, h), + ModelType.BAIDU_MODEL, + lambda x, y, z: baidu_label(x, y, z), + lambda x: baidu_process(x)), + # 航道模型 + ModelType.CHANNEL_EMERGENCY_MODEL.value[1]: ( + lambda x, y, r, t, z, h: TwoModel(x, y, r, ModelType.CHANNEL_EMERGENCY_MODEL, t, z, h), + ModelType.CHANNEL_EMERGENCY_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: forest_process(x)), + # 河道检测模型 + ModelType.RIVER2_MODEL.value[1]: ( + lambda x, y, r, t, z, h: OneModel(x, y, r, ModelType.RIVER2_MODEL, t, z, h), + ModelType.RIVER2_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x)), + # 城管模型 + ModelType.CITY_MANGEMENT_MODEL.value[1]: ( + lambda x, y, r, t, z, h: cityManagementModel(x, y, r, ModelType.CITY_MANGEMENT_MODEL, t, z, h), + ModelType.CITY_MANGEMENT_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: detSeg_demo2(x) + ), + # 人员落水模型 + ModelType.DROWING_MODEL.value[1]: ( + lambda x, y, r, t, z, h: OneModel(x, y, r, ModelType.DROWING_MODEL, t, z, h), + ModelType.DROWING_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 城市违章模型 + ModelType.NOPARKING_MODEL.value[1]: ( + lambda x, y, r, t, z, h: OneModel(x, y, r, ModelType.NOPARKING_MODEL, t, z, h), + ModelType.NOPARKING_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 车辆违停模型 + ModelType.ILLPARKING_MODEL.value[1]: ( + lambda x, y, r, t, z, h: OneModel(x, y, r, ModelType.ILLPARKING_MODEL, t, z, h), + ModelType.ILLPARKING_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 城市公路模型 + ModelType.CITYROAD_MODEL.value[1]: ( + lambda x, y, r, t, z, h: TwoModel(x, y, r, ModelType.CITYROAD_MODEL, t, z, h), + ModelType.CITYROAD_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: forest_process(x)), + # 加载坑槽模型 + ModelType.POTHOLE_MODEL.value[1]: ( + lambda x, y, r, t, z, h: TwoModel(x, y, r, ModelType.POTHOLE_MODEL, t, z, h), + ModelType.POTHOLE_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: forest_process(x) + ), + # 加载船只综合检测模型 + ModelType.CHANNEL2_MODEL.value[1]: ( + lambda x, y, r, t, z, h: MultiModel(x, y, r, ModelType.CHANNEL2_MODEL, t, z, h), + ModelType.CHANNEL2_MODEL, + lambda x, y, z: dynamics_label(x, y, z), + lambda x: channel2_process(x) + ), + # 河道检测模型 + ModelType.RIVERT_MODEL.value[1]: ( + lambda x, y, r, t, z, h: OneModel(x, y, r, ModelType.RIVERT_MODEL, t, z, h), + ModelType.RIVERT_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x)), + # 加载森林人群模型 + ModelType.FORESTCROWD_FARM_MODEL.value[1]: ( + lambda x, y, r, t, z, h: cityManagementModel(x, y, r, ModelType.FORESTCROWD_FARM_MODEL, t, z, h), + ModelType.FORESTCROWD_FARM_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: detSeg_demo2(x) + ), + # 加载交通模型 + ModelType.TRAFFICFORDSJ_FARM_MODEL.value[1]: ( + lambda x, y, r, t, z, h: OneModel(x, y, r, ModelType.TRAFFIC_FARM_MODEL, t, z, h), + ModelType.TRAFFIC_FARM_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 加载智慧工地模型 + ModelType.SMARTSITE_MODEL.value[1]: ( + lambda x, y, r, t, z, h: cityManagementModel(x, y, r, ModelType.SMARTSITE_MODEL, t, z, h), + ModelType.SMARTSITE_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: detSeg_demo2(x) + ), + + # 加载垃圾模型 + ModelType.RUBBISH_MODEL.value[1]: ( + lambda x, y, r, t, z, h: cityManagementModel(x, y, r, ModelType.RUBBISH_MODEL, t, z, h), + ModelType.RUBBISH_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: detSeg_demo2(x) + ), + + # 加载烟花模型 + ModelType.FIREWORK_MODEL.value[1]: ( + lambda x, y, r, t, z, h: cityManagementModel(x, y, r, ModelType.FIREWORK_MODEL, t, z, h), + ModelType.FIREWORK_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: detSeg_demo2(x) + ), + + +} diff --git a/vodsdk/util/ModelUtils2.py b/vodsdk/util/ModelUtils2.py new file mode 100644 index 0000000..67efcbb --- /dev/null +++ b/vodsdk/util/ModelUtils2.py @@ -0,0 +1,442 @@ +# -*- coding: utf-8 -*- +import sys +from json import dumps, loads +from traceback import format_exc + +import cv2 +from loguru import logger + +from common.Constant import COLOR +from enums.BaiduSdkEnum import VehicleEnum +from enums.ExceptionEnum import ExceptionType +from enums.ModelTypeEnum2 import ModelType2, BAIDU_MODEL_TARGET_CONFIG2 +from exception.CustomerException import ServiceException +from util.ImgBaiduSdk import AipBodyAnalysisClient, AipImageClassifyClient +from util.PlotsUtils import get_label_arrays +from util.TorchUtils import select_device +import time +import torch +import tensorrt as trt + +sys.path.extend(['..', '../AIlib2']) +from AI import AI_process, get_postProcess_para, get_postProcess_para_dic, AI_det_track, AI_det_track_batch, AI_det_track_batch_N +from stdc import stdcModel +from utilsK.jkmUtils import pre_process, post_process, get_return_data +from obbUtils.shipUtils import OBB_infer, OBB_tracker, draw_obb, OBB_tracker_batch +from obbUtils.load_obb_model import load_model_decoder_OBB +from trackUtils.sort import Sort +from trackUtils.sort_obb import OBB_Sort +from DMPR import DMPRModel + +FONT_PATH = "../AIlib2/conf/platech.ttf" + + +class Model: + __slots__ = "model_conf" + + def __init__(self, device, allowedList=None, requestId=None, modeType=None, gpu_name=None, base_dir=None, env=None): + try: + logger.info("########################加载{}########################, requestId:{}", modeType.value[2], + requestId) + par = modeType.value[4](str(device), gpu_name) + trackPar = par['trackPar'] + names = par['labelnames'] + detPostPar = par['postFile'] + rainbows = detPostPar["rainbows"] + #第一步加载模型 + modelList=[ modelPar['model'](weights=modelPar['weight'],par=modelPar['par']) for modelPar in par['models'] ] + #第二步准备跟踪参数 + trackPar=par['trackPar'] + sort_tracker = Sort(max_age=trackPar['sort_max_age'], + min_hits=trackPar['sort_min_hits'], + iou_threshold=trackPar['sort_iou_thresh']) + postProcess = par['postProcess'] + model_param = { + "modelList": modelList, + "postProcess": postProcess, + "sort_tracker": sort_tracker, + "trackPar": trackPar, + } + self.model_conf = (modeType, model_param, allowedList, names, rainbows) + except Exception: + logger.error("模型加载异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) + +def get_label_arraylist(*args): + width, height, names, rainbows = args + # line = int(round(0.002 * (height + width) / 2) + 1) + line = max(1, int(round(width / 1920 * 3))) + tf = max(line, 1) + fontScale = line * 0.33 + text_width, text_height = cv2.getTextSize(' 0.95', 0, fontScale=fontScale, thickness=tf)[0] + label_arraylist = get_label_arrays(names, rainbows, fontSize=text_height, fontPath=FONT_PATH) + return label_arraylist, (line, text_width, text_height, fontScale, tf) + + +""" +输入: + imgarray_list--图像列表 + iframe_list -- 帧号列表 + modelPar--模型参数,字典,modelPar={'det_Model':,'seg_Model':} + processPar--字典,存放检测相关参数,'half', 'device', 'conf_thres', 'iou_thres','trtFlag_det' + sort_tracker--对象,初始化的跟踪对象。为了保持一致,即使是单帧也要有。 + trackPar--跟踪参数,关键字包括:det_cnt,windowsize + segPar--None,分割模型相关参数。如果用不到,则为None +输入:retResults,timeInfos + retResults:list + retResults[0]--imgarray_list + retResults[1]--所有结果用numpy格式,所有的检测结果,包括8类,每列分别是x1, y1, x2, y2, conf, detclass,iframe,trackId + retResults[2]--所有结果用list表示,其中每一个元素为一个list,表示每一帧的检测结果,每一个结果是由多个list构成,每个list表示一个框,格式为[ cls , x0 ,y0 ,x1 ,y1 ,conf,ifrmae,trackId ],如 retResults[2][j][k]表示第j帧的第k个框。 +""" + + +def model_process(args): + # (modeType, model_param, allowedList, names, rainbows) + imgarray_list, iframe_list, model_param, request_id = args + try: + return AI_det_track_batch_N(imgarray_list, iframe_list, + model_param['modelList'], + model_param['postProcess'], + model_param['sort_tracker'], + model_param['trackPar']) + except ServiceException as s: + raise s + except Exception: + # self.num += 1 + # cv2.imwrite('/home/th/tuo_heng/dev/img%s.jpg' % str(self.num), frame) + logger.error("算法模型分析异常: {}, requestId: {}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + + +# 船只模型 +class ShipModel: + __slots__ = "model_conf" + + def __init__(self, device, allowedList=None, requestId=None, modeType=None, gpu_name=None, base_dir=None, env=None): + s = time.time() + try: + logger.info("########################加载船只模型########################, requestId:{}", requestId) + par = modeType.value[4](str(device), gpu_name) + obbModelPar = par['obbModelPar'] + model, decoder2 = load_model_decoder_OBB(obbModelPar) + obbModelPar['decoder'] = decoder2 + names = par['labelnames'] + rainbows = par['postFile']["rainbows"] + trackPar = par['trackPar'] + sort_tracker = OBB_Sort(max_age=trackPar['sort_max_age'], min_hits=trackPar['sort_min_hits'], + iou_threshold=trackPar['sort_iou_thresh']) + modelPar = {'obbmodel': model} + segPar = None + model_param = { + "modelPar": modelPar, + "obbModelPar": obbModelPar, + "sort_tracker": sort_tracker, + "trackPar": trackPar, + "segPar": segPar + } + self.model_conf = (modeType, model_param, allowedList, names, rainbows) + except Exception: + logger.exception("模型加载异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) + logger.info("模型初始化时间:{}, requestId:{}", time.time() - s, requestId) + + +def obb_process(args): + imgarray_list, iframe_list, model_param, request_id = args + try: + return OBB_tracker_batch(imgarray_list, iframe_list, model_param['modelPar'], model_param['obbModelPar'], + model_param['sort_tracker'], model_param['trackPar'], model_param['segPar']) + except ServiceException as s: + raise s + except Exception: + # self.num += 1 + # cv2.imwrite('/home/th/tuo_heng/dev/img%s.jpg' % str(self.num), frame) + logger.error("算法模型分析异常:{}, requestId:{}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + + +# 车牌分割模型、健康码、行程码分割模型 +class IMModel: + __slots__ = "model_conf" + + def __init__(self, device, allowedList=None, requestId=None, modeType=None, gpu_name=None, base_dir=None, env=None): + try: + logger.info("########################加载{}########################, requestId:{}", modeType.value[2], + requestId) + img_type = 'code' + if ModelType2.PLATE_MODEL == modeType: + img_type = 'plate' + par = { + 'code': {'weights': '../AIlib2/weights/conf/jkm/health_yolov5s_v3.jit', 'img_type': 'code', 'nc': 10}, + 'plate': {'weights': '../AIlib2/weights/conf/jkm/plate_yolov5s_v3.jit', 'img_type': 'plate', 'nc': 1}, + 'conf_thres': 0.4, + 'iou_thres': 0.45, + 'device': 'cuda:%s' % device, + 'plate_dilate': (0.5, 0.3) + } + new_device = torch.device(par['device']) + model = torch.jit.load(par[img_type]['weights']) + model_param = { + "device": new_device, + "model": model, + "par": par, + "img_type": img_type + } + self.model_conf = (modeType, model_param, allowedList) + except Exception: + logger.error("模型加载异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) + + +def im_process(args): + model_param, frame, request_id = args + device, par, img_type = model_param['device'], model_param['par'], model_param['img_type'] + try: + img, padInfos = pre_process(frame, device) + pred = model_param['model'](img) + boxes = post_process(pred, padInfos, device, conf_thres=par['conf_thres'], + iou_thres=par['iou_thres'], nc=par[img_type]['nc']) # 后处理 + dataBack = get_return_data(frame, boxes, modelType=img_type, plate_dilate=par['plate_dilate']) + return dataBack + except ServiceException as s: + raise s + except Exception: + logger.error("算法模型分析异常:{}, requestId:{}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + + +# 百度AI图片识别模型 +class BaiduAiImageModel: + __slots__ = "model_conf" + + def __init__(self, device=None, allowedList=None, requestId=None, modeType=None, gpu_name=None, base_dir=None, + env=None): + try: + logger.info("########################加载{}########################, requestId:{}", modeType.value[2], + requestId) + aipBodyAnalysisClient = AipBodyAnalysisClient(base_dir, env) + aipImageClassifyClient = AipImageClassifyClient(base_dir, env) + rainbows = COLOR + vehicle_names = [VehicleEnum.CAR.value[1], VehicleEnum.TRICYCLE.value[1], VehicleEnum.MOTORBIKE.value[1], + VehicleEnum.CARPLATE.value[1], VehicleEnum.TRUCK.value[1], VehicleEnum.BUS.value[1]] + person_names = ['人'] + model_param = { + "vehicle_client": aipImageClassifyClient, + "person_client": aipBodyAnalysisClient, + } + self.model_conf = (modeType, model_param, allowedList, (vehicle_names, person_names), rainbows) + except Exception: + logger.exception("模型加载异常:{}, requestId:{}", format_exc(), requestId) + raise ServiceException(ExceptionType.MODEL_LOADING_EXCEPTION.value[0], + ExceptionType.MODEL_LOADING_EXCEPTION.value[1]) + + +def baidu_process(args): + model_param, target, url, request_id = args + try: + baiduEnum = BAIDU_MODEL_TARGET_CONFIG2.get(target) + if baiduEnum is None: + raise ServiceException(ExceptionType.DETECTION_TARGET_TYPES_ARE_NOT_SUPPORTED.value[0], + ExceptionType.DETECTION_TARGET_TYPES_ARE_NOT_SUPPORTED.value[1] + + " target: " + target) + return baiduEnum.value[2](model_param['vehicle_client'], model_param['person_client'], url, request_id) + except ServiceException as s: + raise s + except Exception: + logger.error("算法模型分析异常:{}, requestId:{}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + + +def get_baidu_label_arraylist(*args): + width, height, vehicle_names, person_names, rainbows = args + # line = int(round(0.002 * (height + width) / 2) + 1) + line = max(1, int(round(width / 1920 * 3) + 1)) + label = ' 0.97' + tf = max(line, 1) + fontScale = line * 0.33 + text_width, text_height = cv2.getTextSize(label, 0, fontScale=fontScale, thickness=tf)[0] + vehicle_label_arrays = get_label_arrays(vehicle_names, rainbows, fontSize=text_height, fontPath=FONT_PATH) + person_label_arrays = get_label_arrays(person_names, rainbows, fontSize=text_height, fontPath=FONT_PATH) + font_config = (line, text_width, text_height, fontScale, tf) + return vehicle_label_arrays, person_label_arrays, font_config + + +def one_label(width, height, model_config): + # (modeType, model_param, allowedList, names, rainbows) + names = model_config[3] + rainbows = model_config[4] + label_arraylist, font_config = get_label_arraylist(width, height, names, rainbows) + model_config[1]['label_arraylist'] = label_arraylist + model_config[1]['font_config'] = font_config + + +def baidu_label(width, height, model_config): + # modeType, model_param, allowedList, (vehicle_names, person_names), rainbows + vehicle_names = model_config[3][0] + person_names = model_config[3][1] + rainbows = model_config[4] + vehicle_label_arrays, person_label_arrays, font_config = get_baidu_label_arraylist(width, height, vehicle_names, + person_names, rainbows) + model_config[1]['vehicle_label_arrays'] = vehicle_label_arrays + model_config[1]['person_label_arrays'] = person_label_arrays + model_config[1]['font_config'] = font_config + + + + +def model_process1(args): + imgarray_list, iframe_list, model_param, request_id = args + model_conf, frame, request_id = args + model_param, names, rainbows = model_conf[1], model_conf[3], model_conf[4] + # modeType, model_param, allowedList, names, rainbows = model_conf + # segmodel, names, label_arraylist, rainbows, objectPar, font, segPar, mode, postPar, requestId = args + # model_param['digitFont'] = digitFont + # model_param['label_arraylist'] = label_arraylist + # model_param['font_config'] = font_config + try: + return AI_process([frame], model_param['model'], model_param['segmodel'], names, model_param['label_arraylist'], + rainbows, objectPar=model_param['objectPar'], font=model_param['digitFont'], + segPar=loads(dumps(model_param['segPar'])), mode=model_param['mode'], + postPar=model_param['postPar']) + except ServiceException as s: + raise s + except Exception: + # self.num += 1 + # cv2.imwrite('/home/th/tuo_heng/dev/img%s.jpg' % str(self.num), frame) + logger.error("算法模型分析异常:{}, requestId:{}", format_exc(), request_id) + raise ServiceException(ExceptionType.MODEL_ANALYSE_EXCEPTION.value[0], + ExceptionType.MODEL_ANALYSE_EXCEPTION.value[1]) + + +MODEL_CONFIG2 = { + # 加载河道模型 + ModelType2.WATER_SURFACE_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.WATER_SURFACE_MODEL, t, z, h), + ModelType2.WATER_SURFACE_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 加载森林模型 + ModelType2.FOREST_FARM_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.FOREST_FARM_MODEL, t, z, h), + ModelType2.FOREST_FARM_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 加载交通模型 + ModelType2.TRAFFIC_FARM_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.TRAFFIC_FARM_MODEL, t, z, h), + ModelType2.TRAFFIC_FARM_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 加载防疫模型 + ModelType2.EPIDEMIC_PREVENTION_MODEL.value[1]: ( + lambda x, y, r, t, z, h: IMModel(x, y, r, ModelType2.EPIDEMIC_PREVENTION_MODEL, t, z, h), + ModelType2.EPIDEMIC_PREVENTION_MODEL, + None, + lambda x: im_process(x)), + # 加载车牌模型 + ModelType2.PLATE_MODEL.value[1]: ( + lambda x, y, r, t, z, h: IMModel(x, y, r, ModelType2.PLATE_MODEL, t, z, h), + ModelType2.PLATE_MODEL, + None, + lambda x: im_process(x)), + # 加载车辆模型 + ModelType2.VEHICLE_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.VEHICLE_MODEL, t, z, h), + ModelType2.VEHICLE_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 加载行人模型 + ModelType2.PEDESTRIAN_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.PEDESTRIAN_MODEL, t, z, h), + ModelType2.PEDESTRIAN_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x)), + # 加载烟火模型 + ModelType2.SMOGFIRE_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.SMOGFIRE_MODEL, t, z, h), + ModelType2.SMOGFIRE_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x)), + # 加载钓鱼游泳模型 + ModelType2.ANGLERSWIMMER_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.ANGLERSWIMMER_MODEL, t, z, h), + ModelType2.ANGLERSWIMMER_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x)), + # 加载乡村模型 + ModelType2.COUNTRYROAD_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.COUNTRYROAD_MODEL, t, z, h), + ModelType2.COUNTRYROAD_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x)), + # 加载船只模型 + ModelType2.SHIP_MODEL.value[1]: ( + lambda x, y, r, t, z, h: ShipModel(x, y, r, ModelType2.SHIP_MODEL, t, z, h), + ModelType2.SHIP_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: obb_process(x)), + # 百度AI图片识别模型 + ModelType2.BAIDU_MODEL.value[1]: ( + lambda x, y, r, t, z, h: BaiduAiImageModel(x, y, r, ModelType2.BAIDU_MODEL, t, z, h), + ModelType2.BAIDU_MODEL, + lambda x, y, z: baidu_label(x, y, z), + lambda x: baidu_process(x)), + # 航道模型 + ModelType2.CHANNEL_EMERGENCY_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.CHANNEL_EMERGENCY_MODEL, t, z, h), + ModelType2.CHANNEL_EMERGENCY_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x)), + # 河道检测模型 + ModelType2.RIVER2_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.RIVER2_MODEL, t, z, h), + ModelType2.RIVER2_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x)), + # 城管模型 + ModelType2.CITY_MANGEMENT_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.CITY_MANGEMENT_MODEL, t, z, h), + ModelType2.CITY_MANGEMENT_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 人员落水模型 + ModelType2.DROWING_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.DROWING_MODEL, t, z, h), + ModelType2.DROWING_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 城市违章模型 + ModelType2.NOPARKING_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.NOPARKING_MODEL, t, z, h), + ModelType2.NOPARKING_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 城市公路模型 + ModelType2.CITYROAD_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.CITYROAD_MODEL, t, z, h), + ModelType2.CITYROAD_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), + # 加载坑槽模型 + ModelType2.POTHOLE_MODEL.value[1]: ( + lambda x, y, r, t, z, h: Model(x, y, r, ModelType2.POTHOLE_MODEL, t, z, h), + ModelType2.POTHOLE_MODEL, + lambda x, y, z: one_label(x, y, z), + lambda x: model_process(x) + ), +} diff --git a/vodsdk/util/MyConnectionPool.py b/vodsdk/util/MyConnectionPool.py new file mode 100644 index 0000000..d65037c --- /dev/null +++ b/vodsdk/util/MyConnectionPool.py @@ -0,0 +1,227 @@ +# -*- coding: UTF-8 -*- +import pymysql +from loguru import logger +from dbutils.pooled_db import PooledDB + + +""" +@功能:创建数据库连接池 +""" + + +class MyConnectionPool(object): + __pool = None + + def __init__(self, content): + self.conn = self.__getConn(content) + self.cursor = self.conn.cursor() + + # 创建数据库连接conn和游标cursor + # def __enter__(self): + # self.conn = self.__getconn() + # self.cursor = self.conn.cursor() + + # 创建数据库连接池 + def __getconn(self, content): + if self.__pool is None: + self.__pool = PooledDB( + creator=pymysql, + mincached=int(content["mysql"]["db_min_cached"]), + maxcached=int(content["mysql"]["db_max_cached"]), + maxshared=int(content["mysql"]["db_max_shared"]), + maxconnections=int(content["mysql"]["db_max_connecyions"]), + blocking=content["mysql"]["db_blocking"], + maxusage=content["mysql"]["db_max_usage"], + setsession=content["mysql"]["db_set_session"], + host=content["mysql"][content["dsp"]["active"]]["host"], + port=content["mysql"][content["dsp"]["active"]]["port"], + user=content["mysql"][content["dsp"]["active"]]["username"], + passwd=content["mysql"][content["dsp"]["active"]]["password"], + db=content["mysql"][content["dsp"]["active"]]["dbname"], + use_unicode=False, + charset=content["mysql"]["db_charset"] + ) + return self.__pool.connection() + + # 释放连接池资源 + # def __exit__(self, exc_type, exc_val, exc_tb): + # self.cursor.close() + # self.conn.close() + + # 关闭连接归还给链接池 + def close(self): + self.cursor.close() + self.conn.close() + + # 从连接池中取出一个连接 + def getconn(self, content): + conn = self.__getconn(content) + cursor = conn.cursor() + return cursor, conn + + +# 获取连接池,实例化 +def get_my_connection(content): + return MyConnectionPool(content) + + +''' + 执行语句查询有结果返回结果没有返回0;增/删/改返回变更数据条数,没有返回0 +''' + + +class MySqLHelper(object): + def __init__(self, content): + logger.info("开始加载数据库连接池!") + self.db = get_my_connection(content) + logger.info("加载数据库连接池完成!") + + def __new__(cls, *args, **kwargs): + if not hasattr(cls, 'inst'): # 单例 + cls.inst = super(MySqLHelper, cls).__new__(cls, *args, **kwargs) + return cls.inst + + # 封装执行命令 + def execute(self, sql, param=None, autoclose=False): + """ + 【主要判断是否有参数和是否执行完就释放连接】 + :param sql: 字符串类型,sql语句 + :param param: sql语句中要替换的参数"select %s from tab where id=%s" 其中的%s就是参数 + :param autoclose: 是否关闭连接 + :return: 返回连接conn和游标cursor + """ + cursor, conn = self.db.getconn() # 从连接池获取连接 + count = 0 + try: + # count : 为改变的数据条数 + if param: + count = cursor.execute(sql, param) + else: + count = cursor.execute(sql) + conn.commit() + if autoclose: + self.close(cursor, conn) + except Exception as e: + pass + return cursor, conn, count + + # 执行多条命令 + # def executemany(self, lis): + # """ + # :param lis: 是一个列表,里面放的是每个sql的字典'[{"sql":"xxx","param":"xx"}....]' + # :return: + # """ + # cursor, conn = self.db.getconn() + # try: + # for order in lis: + # sql = order['sql'] + # param = order['param'] + # if param: + # cursor.execute(sql, param) + # else: + # cursor.execute(sql) + # conn.commit() + # self.close(cursor, conn) + # return True + # except Exception as e: + # print(e) + # conn.rollback() + # self.close(cursor, conn) + # return False + + # 释放连接 + def close(self, cursor, conn): + logger.info("开始释放数据库连接!") + cursor.close() + conn.close() + logger.info("释放数据库连接完成!") + + # 查询所有 + def selectall(self, sql, param=None): + try: + cursor, conn, count = self.execute(sql, param) + res = cursor.fetchall() + return res + except Exception as e: + logger.error("查询所有数据异常:") + logger.exception(e) + self.close(cursor, conn) + return count + + # 查询单条 + def selectone(self, sql, param=None): + try: + cursor, conn, count = self.execute(sql, param) + res = cursor.fetchone() + self.close(cursor, conn) + return res + except Exception as e: + logger.error("查询单条数据异常:") + logger.exception(e) + self.close(cursor, conn) + return count + + # 增加 + def insertone(self, sql, param): + try: + cursor, conn, count = self.execute(sql, param) + # _id = cursor.lastrowid() # 获取当前插入数据的主键id,该id应该为自动生成为好 + conn.commit() + self.close(cursor, conn) + return count + # 防止表中没有id返回0 + # if _id == 0: + # return True + # return _id + except Exception as e: + logger.error("新增数据异常:") + logger.exception(e) + conn.rollback() + self.close(cursor, conn) + return count + + # 增加多行 + def insertmany(self, sql, param): + """ + :param sql: + :param param: 必须是元组或列表[(),()]或((),()) + :return: + """ + cursor, conn, count = self.db.getconn() + try: + cursor.executemany(sql, param) + conn.commit() + return count + except Exception as e: + logger.error("增加多条数据异常:") + logger.exception(e) + conn.rollback() + self.close(cursor, conn) + return count + + # 删除 + def delete(self, sql, param=None): + try: + cursor, conn, count = self.execute(sql, param) + self.close(cursor, conn) + return count + except Exception as e: + logger.error("删除数据异常:") + logger.exception(e) + conn.rollback() + self.close(cursor, conn) + return count + + # 更新 + def update(self, sql, param=None): + try: + cursor, conn, count = self.execute(sql, param) + conn.commit() + self.close(cursor, conn) + return count + except Exception as e: + logger.error("更新数据异常:") + logger.exception(e) + conn.rollback() + self.close(cursor, conn) + return count diff --git a/vodsdk/util/OcrBaiduSdk.py b/vodsdk/util/OcrBaiduSdk.py new file mode 100644 index 0000000..3e11ca6 --- /dev/null +++ b/vodsdk/util/OcrBaiduSdk.py @@ -0,0 +1,147 @@ +import time +import traceback +from os.path import join + +import cv2 +from aip import AipOcr +from loguru import logger + +from common.YmlConstant import baidu_yml_path +from enums.BaiduSdkEnum import BAIDUERRORDATA +from enums.ExceptionEnum import ExceptionType +from exception.CustomerException import ServiceException +from util.RWUtils import getConfigs + + +class OcrBaiduSdk: + + __slots__ = ('client', "__config") + + def __init__(self, base_dir, env): + self.client = None + self.__config = getConfigs(join(base_dir, baidu_yml_path % env)) + self.init_client() + + def init_client(self): + if self.client is None: + self.client = AipOcr(str(self.__config["orc"]["APP_ID"]), + self.__config["orc"]["API_KEY"], + self.__config["orc"]["SECRET_KEY"]) + + ''' + { + "log_id": 2471272194, + "words_result_num": 2, + "words_result": + [ + {"words": " TSINGTAO"}, + {"words": "青島睥酒"} + ] + } + ''' + + def universal_text_recognition(self, image, request_id): + reply_num = 0 + reply_value = None + while True: + try: + or_result, or_image = cv2.imencode(".jpg", image) + options = { + "language_type": "CHN_ENG", + "detect_direction": "true", + "detect_language": "true", + "probability": "true" + } + res_image = self.client.basicGeneral(or_image.tobytes(), options) + error_code = res_image.get("error_code") + if error_code: + enum = BAIDUERRORDATA.get(error_code) + # 如果异常编码未知, 返回空值 + if enum is None: + logger.error("百度云人流量统计异常!error_code:{}, request_id: {}", error_code, request_id) + return None + # 重试指定次数后,还是异常,输出统一内部异常 + if enum.value[3] == 0: + if reply_value is None: + reply_value = enum.value[4] + logger.error("百度云人流量统计异常!error_code:{}, error_msg:{}, reply_num:{}, request_id: {}", + enum.value[0], enum.value[2], reply_num, request_id) + raise Exception() + # 重试指定次数后,还是异常,输出对应的异常 + if enum.value[3] == 1: + if reply_value is None: + reply_value = enum.value[4] + raise ServiceException(str(enum.value[0]), enum.value[2]) + # 重试指定次数后,还是异常,输出空 + if enum.value[3] == 2: + if reply_value is None: + reply_value = enum.value[4] + if reply_num >= reply_value: + return None + raise Exception() + return res_image + except Exception as e: + time.sleep(1) + reply_num += 0.5 + self.init_client() + if reply_num > reply_value: + if isinstance(e, ServiceException): + raise ServiceException(e.code, e.msg) + logger.error("通用文字识别失败: {}, request_id: {}", traceback.format_exc(), request_id) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + + ''' + { + "log_id": 3583925545, + "words_result": { + "color": "blue", + "number": "苏HS7766" + } + } + ''' + def license_plate_recognition(self, image, request_id): + reply_num = 0 + reply_value = None + while True: + try: + or_result, or_image = cv2.imencode(".jpg", image) + res_image = self.client.licensePlate(or_image.tobytes(), {"multi_detect": "true"}) + error_code = res_image.get("error_code") + if error_code: + enum = BAIDUERRORDATA.get(error_code) + # 如果异常编码未知, 返回空值 + if enum is None: + logger.error("百度云人流量统计异常!error_code:{}, request_id: {}", error_code, request_id) + return None + # 重试指定次数后,还是异常,输出统一内部异常 + if enum.value[3] == 0: + if reply_value is None: + reply_value = enum.value[4] + logger.error("百度云人流量统计异常!error_code:{}, error_msg:{}, reply_num:{}, request_id: {}", + enum.value[0], enum.value[2], reply_num, request_id) + raise Exception() + # 重试指定次数后,还是异常,输出对应的异常 + if enum.value[3] == 1: + if reply_value is None: + reply_value = enum.value[4] + raise ServiceException(str(enum.value[0]), enum.value[2]) + # 重试指定次数后,还是异常,输出空 + if enum.value[3] == 2: + if reply_value is None: + reply_value = enum.value[4] + if reply_num >= reply_value: + return None + raise Exception() + return res_image + except Exception as e: + time.sleep(1) + reply_num += 1 + self.init_client() + if reply_num > reply_value: + if isinstance(e, ServiceException): + raise ServiceException(e.code, e.msg) + logger.error("车牌识别失败: {}, request_id: {}", traceback.format_exc(), request_id) + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + diff --git a/vodsdk/util/PlotsUtils.py b/vodsdk/util/PlotsUtils.py new file mode 100644 index 0000000..ddbbce3 --- /dev/null +++ b/vodsdk/util/PlotsUtils.py @@ -0,0 +1,258 @@ +import cv2 +import numpy as np +from PIL import Image, ImageDraw, ImageFont +import unicodedata +FONT_PATH = "../AIlib2/conf/platech.ttf" + +zhFont = ImageFont.truetype(FONT_PATH, 20, encoding="utf-8") + +def get_label_array(color=None, label=None, font=None, fontSize=40, unify=False): + if unify: + x, y, width, height = font.getbbox("标") # 统一数组大小 + else: + 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, -1), 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) + scale = height / fontSize + im_array = cv2.resize(im_array, (0, 0), fx=scale, fy=scale) + return im_array + + +def get_label_arrays(labelNames, colors, fontSize=40, fontPath="platech.ttf"): + font = ImageFont.truetype(fontPath, fontSize, encoding='utf-8') + label_arraylist = [get_label_array(colors[i % 20], label_name, font, fontSize) for i, label_name in + enumerate(labelNames)] + return label_arraylist + +def get_label_array_dict(colors, fontSize=40, fontPath="platech.ttf"): + font = ImageFont.truetype(fontPath, fontSize, encoding='utf-8') + all_chinese_characters = [] + for char in range(0x4E00, 0x9FFF + 1): # 中文 + chinese_character = chr(char) + if unicodedata.category(chinese_character) == 'Lo': + all_chinese_characters.append(chinese_character) + for char in range(0x0041, 0x005B): # 大写字母 + all_chinese_characters.append(chr(char)) + for char in range(0x0061, 0x007B): # 小写字母 + all_chinese_characters.append(chr(char)) + for char in range(0x0030, 0x003A): # 数字 + all_chinese_characters.append(chr(char)) + zh_dict = {} + for code in all_chinese_characters: + arr = get_label_array(colors[2], code, font, fontSize, unify=True) + zh_dict[code] = arr + return zh_dict + + +def xywh2xyxy(box): + if not isinstance(box[0], (list, tuple, np.ndarray)): + xc, yc, w, h = int(box[0]), int(box[1]), int(box[2]), int(box[3]) + bw, bh = int(w / 2), int(h / 2) + lt, yt, rt, yr = xc - bw, yc - bh, xc + bw, yc + bh + box = [(lt, yt), (rt, yt), (rt, yr), (lt, yr)] + return box + +def xywh2xyxy2(param): + if not isinstance(param[0], (list, tuple, np.ndarray)): + xc, yc, x2, y2 = int(param[0]), int(param[1]), int(param[2]), int(param[3]) + return [(xc, yc), (x2, yc), (x2, y2), (xc, y2)], float(param[4]), int(param[5]) + # bw, bh = int(w / 2), int(h / 2) + # lt, yt, rt, yr = xc - bw, yc - bh, xc + bw, yc + bh + # return [(lt, yt), (rt, yt), (rt, yr), (lt, yr)] + return np.asarray(param[0][0:4], np.int32), float(param[1]), int(param[2]) + + +def draw_painting_joint(box, img, label_array, score=0.5, color=None, config=None, isNew=False): + # 识别问题描述图片的高、宽 + lh, lw = label_array.shape[0:2] + # 图片的长度和宽度 + imh, imw = img.shape[0:2] + box = xywh2xyxy(box) + # 框框左上的位置 + x0, y1 = box[0][0], box[0][1] + # if score_location == 'leftTop': + # x0, y1 = box[0][0], box[0][1] + # # 框框左下的位置 + # elif score_location == 'leftBottom': + # x0, y1 = box[3][0], box[3][1] + # else: + # x0, y1 = box[0][0], box[0][1] + # x1 框框左上x位置 + 描述的宽 + # y0 框框左上y位置 - 描述的高 + x1, y0 = x0 + lw, y1 - lh + # 如果y0小于0, 说明超过上边框 + if y0 < 0: + y0 = 0 + # y1等于文字高度 + y1 = y0 + lh + # 如果y1框框的高大于图片高度 + if y1 > imh: + # y1等于图片高度 + y1 = imh + # y0等于y1减去文字高度 + y0 = y1 - lh + # 如果x0小于0 + if x0 < 0: + x0 = 0 + x1 = x0 + lw + if x1 > imw: + x1 = imw + x0 = x1 - lw + # box_tl = max(int(round(imw / 1920 * 3)), 1) or round(0.002 * (imh + imw) / 2) + 1 + ''' + 1. img(array) 为ndarray类型(可以为cv.imread)直接读取的数据 + 2. box(array):为所画多边形的顶点坐标 + 3. 所画四边形是否闭合,通常为True + 4. color(tuple):BGR三个通道的值 + 5. thickness(int):画线的粗细 + 6. shift:顶点坐标中小数的位数 + ''' + tl = config[0] + box1 = np.asarray(box, np.int32) + cv2.polylines(img, [box1], True, color, tl) + img[y0:y1, x0:x1, :] = label_array + pts_cls = [(x0, y0), (x1, y1)] + # 把英文字符score画到类别旁边 + # tl = max(int(round(imw / 1920 * 3)), 1) or round(0.002 * (imh + imw) / 2) + 1 + label = ' %.2f' % score + # tf = max(tl, 1) + # fontScale = float(format(imw / 1920 * 1.1, '.2f')) or tl * 0.33 + # fontScale = tl * 0.33 + ''' + 1. text:要计算大小的文本内容,类型为字符串。 + 2. fontFace:字体类型,例如cv2.FONT_HERSHEY_SIMPLEX等。 + 3. fontScale:字体大小的缩放因子,例如1.2表示字体大小增加20%。 + 4. thickness:文本线条的粗细,以像素为单位。 + 5. (text_width, text_height):给定文本在指定字体、字体大小、线条粗细下所占用的像素宽度和高度。 + ''' + # t_size = cv2.getTextSize(label, 0, fontScale=fontScale, thickness=tf)[0] + t_size = (config[1], config[2]) + # if socre_location=='leftTop': + p1, p2 = (pts_cls[1][0], pts_cls[0][1]), (pts_cls[1][0] + t_size[0], pts_cls[1][1]) + ''' + 1. img:要绘制矩形的图像 + 2. pt1:矩形框的左上角坐标,可以是一个包含两个整数的元组或列表,例如(x1, y1)或[x1, y1]。 + 3. pt2:矩形框的右下角坐标,可以是一个包含两个整数的元组或列表,例如(x2, y2)或[x2, y2]。 + 4. color:矩形框的颜色,可以是一个包含三个整数的元组或列表,例如(255, 0, 0)表示蓝色,或一个标量值,例如255表示白色。颜色顺序为BGR。 + 5. thickness:线条的粗细,以像素为单位。如果为负值,则表示要绘制填充矩形。默认值为1。 + 6. lineType:线条的类型,可以是cv2.LINE_AA表示抗锯齿线条,或cv2.LINE_4表示4连通线条,或cv2.LINE_8表示8连通线条。默认值为cv2.LINE_8。 + 7. shift:坐标点小数点位数。默认值为0。 + ''' + cv2.rectangle(img, p1, p2, color, -1, cv2.LINE_AA) + p3 = pts_cls[1][0], pts_cls[1][1] - (lh - t_size[1]) // 2 + ''' + 1. img:要在其上绘制文本的图像 + 2. text:要绘制的文本内容,类型为字符串 + 3. org:文本起始位置的坐标,可以是一个包含两个整数的元组或列表,例如(x, y)或[x, y]。 + 4. fontFace:字体类型,例如cv2.FONT_HERSHEY_SIMPLEX等。 + 5. fontScale:字体大小的缩放因子,例如1.2表示字体大小增加20%。 + 6. color:文本的颜色,可以是一个包含三个整数的元组或列表,例如(255, 0, 0)表示蓝色,或一个标量值,例如255表示白色。颜色顺序为BGR。 + 7. thickness:文本线条的粗细,以像素为单位。默认值为1。 + 8. lineType:线条的类型,可以是cv2.LINE_AA表示抗锯齿线条,或cv2.LINE_4表示4连通线条,或cv2.LINE_8表示8连通线条。默认值为cv2.LINE_8。 + 9. bottomLeftOrigin:文本起始位置是否为左下角。如果为True,则文本起始位置为左下角,否则为左上角。默认值为False。 + ''' + if isNew: + cv2.putText(img, label, p3, 0, config[3], [0, 0, 0], thickness=config[4], lineType=cv2.LINE_AA) + else: + cv2.putText(img, label, p3, 0, config[3], [225, 255, 255], thickness=config[4], lineType=cv2.LINE_AA) + return img, box + +# 动态标签 +def draw_name_joint(box, img, label_array_dict, score=0.5, color=None, config=None, name=""): + label_array = None + for zh in name: + if zh in label_array_dict: + if label_array is None: + label_array = label_array_dict[zh] + else: + label_array = np.concatenate((label_array,label_array_dict[zh]), axis= 1) + # 识别问题描述图片的高、宽 + if label_array is None: + lh, lw = 0, 0 + else: + lh, lw = label_array.shape[0:2] + # 图片的长度和宽度 + imh, imw = img.shape[0:2] + box = xywh2xyxy(box) + # 框框左上的位置 + x0, y1 = box[0][0], box[0][1] + x1, y0 = x0 + lw, y1 - lh + # 如果y0小于0, 说明超过上边框 + if y0 < 0: + y0 = 0 + # y1等于文字高度 + y1 = y0 + lh + # 如果y1框框的高大于图片高度 + if y1 > imh: + # y1等于图片高度 + y1 = imh + # y0等于y1减去文字高度 + y0 = y1 - lh + # 如果x0小于0 + if x0 < 0: + x0 = 0 + x1 = x0 + lw + if x1 > imw: + x1 = imw + x0 = x1 - lw + tl = config[0] + box1 = np.asarray(box, np.int32) + cv2.polylines(img, [box1], True, color, tl) + if label_array is not None: + img[y0:y1, x0:x1, :] = label_array + pts_cls = [(x0, y0), (x1, y1)] + # 把英文字符score画到类别旁边 + # tl = max(int(round(imw / 1920 * 3)), 1) or round(0.002 * (imh + imw) / 2) + 1 + label = ' %.2f' % score + t_size = (config[1], config[2]) + # if socre_location=='leftTop': + p1, p2 = (pts_cls[1][0], pts_cls[0][1]), (pts_cls[1][0] + t_size[0], pts_cls[1][1]) + cv2.rectangle(img, p1, p2, color, -1, cv2.LINE_AA) + p3 = pts_cls[1][0], pts_cls[1][1] - (lh - t_size[1]) // 2 + cv2.putText(img, label, p3, 0, config[3], [225, 255, 255], thickness=config[4], lineType=cv2.LINE_AA) + return img, box + + +def filterBox(det0, det1, pix_dis): + # det0为 (m1, 11) 矩阵 + # det1为 (m2, 12) 矩阵 + if len(det0.shape) == 1: + det0 = det0[np.newaxis,...] + if len(det1.shape) == 1: + det1 = det1[np.newaxis,...] + det1 = det1[...,0:11].copy() + m, n = det0.size, det1.size + if not m: + return det0 + # 在det0的列方向加一个元素flag代表该目标框中心点是否在之前目标框内(0代表不在,其他代表在) + flag = np.zeros([len(det0), 1]) + det0 = np.concatenate([det0, flag], axis=1) + det0_copy = det0.copy() + # det1_copy = det1.copy() + if not n: + return det0 + # det0转成 (m1, m2, 12) 的矩阵 + # det1转成 (m1, m2, 12) 的矩阵 + # det0与det1在第3维方向上拼接(6 + 7 = 13) + det0 = det0[:, np.newaxis, :].repeat(det1.shape[0], 1) + det1 = det1[np.newaxis, ...].repeat(det0.shape[0], 0) + joint_det = np.concatenate((det1, det0), axis=2) + # 分别求det0和det1的x1, y1, x2, y2(水平框的左上右下角点) + x1, y1, x2, y2 = joint_det[..., 0], joint_det[..., 1], joint_det[..., 4], joint_det[..., 5] + x3, y3, x4, y4 = joint_det[..., 11], joint_det[..., 12], joint_det[..., 15], joint_det[..., 16] + + x2_c, y2_c = (x1+x2)//2, (y1+y2)//2 + x_c, y_c = (x3+x4)//2, (y3+y4)//2 + dis = (x2_c - x_c)**2 + (y2_c - y_c)**2 + mask = (joint_det[..., 9] == joint_det[..., 20]) & (dis <= pix_dis**2) + + # 类别相同 & 中心点在上一帧的框内 判断为True + res = np.sum(mask, axis=1) + det0_copy[..., -1] = res + return det0_copy \ No newline at end of file diff --git a/vodsdk/util/PushStreamUtils.py b/vodsdk/util/PushStreamUtils.py new file mode 100644 index 0000000..91564da --- /dev/null +++ b/vodsdk/util/PushStreamUtils.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +import time +from traceback import format_exc + +import subprocess as sp + +from loguru import logger +from exception.CustomerException import ServiceException +from enums.ExceptionEnum import ExceptionType + + +class PushStreamUtil: + __slots__ = ('pullUrl', 'pushUrl', 'requestId', "push_stream_sp", "start_time") + + def __init__(self, pullUrl=None, pushUrl=None, requestId=None): + self.pullUrl = pullUrl + self.pushUrl = pushUrl + self.requestId = requestId + self.push_stream_sp = None + self.start_time = time.time() + + def close_push_stream_sp(self): + logger.info("开始关闭推流管道, requestId:{}", self.requestId) + if self.push_stream_sp: + logger.info("尝试关闭推流管道, requestId:{}", self.requestId) + self.push_stream_sp.terminate() + self.push_stream_sp.wait() + if self.push_stream_sp and self.push_stream_sp.poll() is None: + logger.error("尝试关闭推流管道失败, requestId:{}", self.requestId) + self.push_stream_sp.communicate(input=b"q\n", timeout=30) + if self.push_stream_sp and self.push_stream_sp.poll() is not None: + logger.info("尝试关闭推流管道成功, requestId:{}", self.requestId) + self.push_stream_sp = None + if self.push_stream_sp and self.push_stream_sp.poll() is not None: + logger.info("尝试关闭推流管道成功, requestId:{}", self.requestId) + self.push_stream_sp = None + else: + logger.info("推流管道已关闭, requestId:{}", self.requestId) + + # 构建 cv2 + def start_push_stream(self): + try: + if self.push_stream_sp: + return + if self.pullUrl is None or len(self.pullUrl) == 0: + logger.error("推流地址不能为空, requestId:{}", self.requestId) + raise ServiceException(ExceptionType.PULL_STREAM_URL_EXCEPTION.value[0], + ExceptionType.PULL_STREAM_URL_EXCEPTION.value[1]) + if self.pushUrl is None or len(self.pushUrl) == 0: + logger.error("推流地址不能为空, requestId:{}", self.requestId) + raise ServiceException(ExceptionType.PUSH_STREAM_URL_EXCEPTION.value[0], + ExceptionType.PUSH_STREAM_URL_EXCEPTION.value[1]) + command = ['ffmpeg', '-re', '-y', "-an", "-hide_banner"] + if self.pullUrl.startswith("rtsp://"): + command.extend(['-timeout', '20000000', '-rtsp_transport', 'tcp']) + if self.pullUrl.startswith("rtmp://") or self.pullUrl.startswith("http"): + command.extend(['-rw_timeout', '20000000']) + command.extend(['-i', self.pullUrl, + '-c:v', 'copy', + '-b:v', '4000k', + '-bufsize', '4000k', + '-f', 'flv', + self.pushUrl]) + logger.info("推流指令:{}, requestId:{}", command, self.requestId) + self.push_stream_sp = sp.Popen(command, stdin=sp.PIPE, stdout=sp.PIPE, stderr=sp.PIPE, shell=False) + except ServiceException as s: + self.close_push_stream_sp() + logger.error("构建p管道异常: {}, requestId:{}", s.msg, self.requestId) + raise s + except Exception as e: + self.close_push_stream_sp() + logger.error("初始化推流管道异常:{}, requestId:{}", format_exc(), self.requestId) + raise e + diff --git a/vodsdk/util/QueRiver.py b/vodsdk/util/QueRiver.py new file mode 100644 index 0000000..3eb78d2 --- /dev/null +++ b/vodsdk/util/QueRiver.py @@ -0,0 +1,346 @@ +from kafka import KafkaProducer, KafkaConsumer +from kafka.errors import kafka_errors +import traceback +import json, base64,os +import numpy as np +from multiprocessing import Process,Queue +import time,cv2,string,random +import subprocess as sp + +import matplotlib.pyplot as plt +from utils.datasets import LoadStreams, LoadImages +from models.experimental import attempt_load +from utils.general import check_img_size, check_requirements, check_imshow, non_max_suppression, apply_classifier, scale_coords, xyxy2xywh, strip_optimizer, set_logging, increment_path +import torch,sys +#from segutils.segmodel import SegModel,get_largest_contours +#sys.path.extend(['../yolov5/segutils']) + +from segutils.segWaterBuilding import SegModel,get_largest_contours,illBuildings + +#from segutils.core.models.bisenet import BiSeNet +from segutils.core.models.bisenet import BiSeNet_MultiOutput + +from utils.plots import plot_one_box,plot_one_box_PIL,draw_painting_joint,get_label_arrays,get_websource +from collections import Counter +#import matplotlib + +import matplotlib.pyplot as plt +# get_labelnames,get_label_arrays,post_process_,save_problem_images,time_str +#FP_DEBUG=open('debut.txt','w') +def bsJpgCode(image_ori): + jpgCode = cv2.imencode('.jpg',image_ori)[-1]###np.array,(4502009,1) + bsCode = str(base64.b64encode(jpgCode))[2:-1] ###str,长6002680 + return bsCode +def bsJpgDecode(bsCode): + bsDecode = base64.b64decode(bsCode)###types,长4502009 + npString = np.frombuffer(bsDecode,np.uint8)###np.array,(长4502009,) + jpgDecode = cv2.imdecode(npString,cv2.IMREAD_COLOR)###np.array,(3000,4000,3) + return jpgDecode +def get_ms(time0,time1): + str_time ='%.2f ms'%((time1-time0)*1000) + return str_time +rainbows=[ + (0,0,255),(0,255,0),(255,0,0),(255,0,255),(255,255,0),(255,127,0),(255,0,127), + (127,255,0),(0,255,127),(0,127,255),(127,0,255),(255,127,255),(255,255,127), + (127,255,255),(0,255,255),(255,127,255),(127,255,255), + (0,127,0),(0,0,127),(0,255,255) + ] + + +def get_labelnames(labelnames): + with open(labelnames,'r') as fp: + namesjson=json.load(fp) + names_fromfile=namesjson['labelnames'] + names = names_fromfile + return names + +def check_stream(stream): + cap = cv2.VideoCapture(stream) + if cap.isOpened(): + return True + else: + return False +##### +def drawWater(pred,image_array0,river={'color':(0,255,255),'line_width':3,'segRegionCnt':2}):####pred是模型的输出,只有水分割的任务 + ##画出水体区域 + contours, hierarchy = cv2.findContours(pred,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) + water = pred.copy(); water[:,:] = 0 + + if len(contours)==0: + return image_array0,water + max_ids = get_largest_contours(contours,river['segRegionCnt']); + for max_id in max_ids: + cv2.fillPoly(water, [contours[max_id][:,0,:]], 1) + cv2.drawContours(image_array0,contours,max_id,river['color'],river['line_width'] ) + return image_array0,water + + +def scale_back(boxes,padInfos): + top, left,r = padInfos[0:3] + + boxes[:,0] = (boxes[:,0] - left) * r + + boxes[:,2] = (boxes[:,2] - left) * r + boxes[:,1] = (boxes[:,1] - top) * r + boxes[:,3] = (boxes[:,3] - top) * r + return boxes + +def img_pad(img, size, pad_value=[114,114,114]): + ###填充成固定尺寸 + H,W,_ = img.shape + r = max(H/size[0], W/size[1]) + img_r = cv2.resize(img, (int(W/r), int(H/r))) + tb = size[0] - img_r.shape[0] + lr = size[1] - img_r.shape[1] + top = int(tb/2) + bottom = tb - top + left = int(lr/2) + right = lr - left + pad_image = cv2.copyMakeBorder(img_r, top, bottom, left, right, cv2.BORDER_CONSTANT,value=pad_value) + return pad_image,(top, left,r) + +def post_process_(datas,conf_thres, iou_thres,names,label_arraylist,rainbows,iframe,ObjectPar={ 'object_config':[0,1,2,3,4], 'slopeIndex':[5,6,7] ,'segmodel':True,'segRegionCnt':1 },font={ 'line_thickness':None, 'fontSize':None,'boxLine_thickness':None,'waterLineColor':(0,255,255),'waterLineWidth':3},padInfos=None ): + object_config,slopeIndex,segmodel,segRegionCnt=ObjectPar['object_config'],ObjectPar['slopeIndex'],ObjectPar['segmodel'],ObjectPar['segRegionCnt'] + ##输入dataset genereate 生成的数据,model预测的结果pred,nms参数 + ##主要操作NMS ---> 坐标转换 ---> 画图 + ##输出原图、AI处理后的图、检测结果 + time0=time.time() + path, img, im0s, vid_cap ,pred,seg_pred= datas[0:6]; + #segmodel=True + pred = non_max_suppression(pred, conf_thres, iou_thres, classes=None, agnostic=False) + time1=time.time() + i=0;det=pred[0]###一次检测一张图片 + time1_1 = time.time() + #p, s, im0 = path[i], '%g: ' % i, im0s[i].copy() + p, s, im0 = path[i], '%g: ' % i, im0s[i] + time1_2 = time.time() + gn = torch.tensor(im0.shape)[[1, 0, 1, 0]] # normalization gain whwh + time1_3 = time.time() + det_xywh=[]; + #im0_brg=cv2.cvtColor(im0,cv2.COLOR_RGB2BGR); + if segmodel: + if len(seg_pred)==2: + im0,water = illBuildings(seg_pred,im0) + else: + river={ 'color':font['waterLineColor'],'line_width':font['waterLineWidth'],'segRegionCnt':segRegionCnt } + im0,water = drawWater(seg_pred,im0,river) + time2=time.time() + #plt.imshow(im0);plt.show() + if len(det)>0: + # Rescale boxes from img_size to im0 size + if not padInfos: + det[:, :4] = scale_coords(img.shape[2:], det[:, :4],im0.shape).round() + else: + #print('####line131:',det[:, :]) + det[:, :4] = scale_back( det[:, :4],padInfos).round() + #print('####line133:',det[:, :]) + #用seg模型,确定有效检测匡及河道轮廓线 + if segmodel: + cls_indexs = det[:, 5].clone().cpu().numpy().astype(np.int32) + ##判断哪些目标属于岸坡的 + slope_flag = np.array([x in slopeIndex for x in cls_indexs ] ) + + det_c = det.clone(); det_c=det_c.cpu().numpy() + try: + area_factors = np.array([np.sum(water[int(x[1]):int(x[3]), int(x[0]):int(x[2])] )*1.0/(1.0*(x[2]-x[0])*(x[3]-x[1])+0.00001) for x in det_c] ) + except: + print('*****************************line143: error:',det_c) + water_flag = np.array(area_factors>0.1) + det = det[water_flag|slope_flag]##如果是水上目标,则需要与水的iou超过0.1;如果是岸坡目标,则直接保留。 + #对检测匡绘图 + for *xyxy, conf, cls in reversed(det): + xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist() # normalized xywh + cls_c = cls.cpu().numpy() + if int(cls_c) not in object_config: ###如果不是所需要的目标,则不显示 + continue + conf_c = conf.cpu().numpy() + line = [float(cls_c), *xywh, float(conf_c)] # label format + det_xywh.append(line) + label = f'{names[int(cls)]} {conf:.2f}' + + im0 = draw_painting_joint(xyxy,im0,label_arraylist[int(cls)],score=conf,color=rainbows[int(cls)%20],font=font) + time3=time.time() + strout='nms:%s drawWater:%s,copy:%s,toTensor:%s,detDraw:%s '%(get_ms(time0,time1),get_ms(time1,time2),get_ms(time1_1,time1_2),get_ms(time1_2,time1_3), get_ms(time2,time3) ) + return [im0s[0],im0,det_xywh,iframe],strout + + + +def preprocess(par): + print('#####process:',par['name']) + ##负责读取视频,生成原图及供检测的使用图,numpy格式 + #source='rtmp://liveplay.yunhengzhizao.cn/live/demo_HD5M' + #img_size=640; stride=32 + while True: + cap = cv2.VideoCapture(par['source']) + iframe = 0 + if cap.isOpened(): + print( '#### read %s success!'%(par['source'])) + try: + dataset = LoadStreams(par['source'], img_size=640, stride=32) + for path, img, im0s, vid_cap in dataset: + datas=[path, img, im0s, vid_cap,iframe] + par['queOut'].put(datas) + iframe +=1 + except Exception as e: + print('###read error:%s '%(par['source'])) + time.sleep(10) + iframe = 0 + + else: + print('###read error:%s '%(par['source'] )) + time.sleep(10) + iframe = 0 + +def gpu_process(par): + print('#####process:',par['name']) + half=True + ##gpu运算,检测模型 + weights = par['weights'] + device = par['device'] + print('###line127:',par['device']) + model = attempt_load(par['weights'], map_location=par['device']) # load FP32 model + if half: + model.half() + + ##gpu运算,分割模型 + seg_nclass = par['seg_nclass'] + seg_weights = par['seg_weights'] + + #segmodel = SegModel(nclass=seg_nclass,weights=seg_weights,device=device) + + + nclass = [2,2] + Segmodel = BiSeNet_MultiOutput(nclass) + weights='weights/segmentation/WaterBuilding.pth' + segmodel = SegModel(model=Segmodel,nclass=nclass,weights=weights,device='cuda:0',multiOutput=True) + while True: + if not par['queIn'].empty(): + time0=time.time() + datas = par['queIn'].get() + path, img, im0s, vid_cap,iframe = datas[0:5] + time1=time.time() + img = torch.from_numpy(img).to(device) + img = img.half() if half else img.float() # uint8 to fp16/32 + img /= 255.0 # 0 - 255 to 0.0 - 1.0 + time2 = time.time() + pred = model(img,augment=False)[0] + time3 = time.time() + seg_pred = segmodel.eval(im0s[0],outsize=None,smooth_kernel=20) + time4 = time.time() + fpStr= 'process:%s ,iframe:%d,getdata:%s,copygpu:%s,dettime:%s,segtime:%s , time:%s, queLen:%d '%( par['name'],iframe,get_ms(time0,time1) ,get_ms(time1,time2) ,get_ms(time2,time3) ,get_ms(time3,time4),get_ms(time0,time4) ,par['queIn'].qsize() ) + #FP_DEBUG.write( fpStr+'\n' ) + datasOut = [path, img, im0s, vid_cap,pred,seg_pred,iframe] + par['queOut'].put(datasOut) + if par['debug']: + print('#####process:',par['name'],' line107') + else: + time.sleep(1/300) +def get_cls(array): + dcs = Counter(array) + keys = list(dcs.keys()) + values = list(dcs.values()) + max_index = values.index(max(values)) + cls = int(keys[max_index]) + return cls +def save_problem_images(post_results,iimage_cnt,names,streamName='live-THSAHD5M',outImaDir='problems/images_tmp',imageTxtFile=False): + ## [cls, x,y,w,h, conf] + problem_image=[[] for i in range(6)] + + + dets_list = [x[2] for x in post_results] + + mean_scores=[ np.array(x)[:,5].mean() for x in dets_list ] ###mean conf + + best_index = mean_scores.index(max(mean_scores)) ##获取该批图片里,问题图片的index + best_frame = post_results[ best_index][3] ##获取绝对帧号 + img_send = post_results[best_index][1]##AI处理后的图 + img_bak = post_results[best_index][0]##原图 + cls_max = get_cls( x[0] for x in dets_list[best_index] ) + + + time_str = time.strftime("%Y-%m-%d-%H-%M-%S", time.localtime()) + uid=''.join(random.sample(string.ascii_letters + string.digits, 16)) + #ori_name = '2022-01-20-15-57-36_frame-368-720_type-漂浮物_qVh4zI08ZlwJN9on_s-live-THSAHD5M_OR.jpg' + #2022-01-13-15-07-57_frame-9999-9999_type-结束_9999999999999999_s-off-XJRW20220110115904_AI.jpg + outnameOR= '%s/%s_frame-%d-%d_type-%s_%s_s-%s_AI.jpg'%(outImaDir,time_str,best_frame,iimage_cnt,names[cls_max],uid,streamName) + outnameAR= '%s/%s_frame-%d-%d_type-%s_%s_s-%s_OR.jpg'%(outImaDir,time_str,best_frame,iimage_cnt,names[cls_max],uid,streamName) + + cv2.imwrite(outnameOR,img_send) + cv2.imwrite(outnameAR,img_bak) + if imageTxtFile: + outnameOR_txt = outnameOR.replace('.jpg','.txt') + fp=open(outnameOR_txt,'w');fp.write(outnameOR+'\n');fp.close() + outnameAI_txt = outnameAR.replace('.jpg','.txt') + fp=open(outnameAI_txt,'w');fp.write(outnameAR+'\n');fp.close() + + parOut = {}; parOut['imgOR'] = img_send; parOut['imgAR'] = img_send; parOut['uid']=uid + parOut['imgORname']=os.path.basename(outnameOR);parOut['imgARname']=os.path.basename(outnameAR); + parOut['time_str'] = time_str;parOut['type'] = names[cls_max] + return parOut + + + + +def post_process(par): + + print('#####process:',par['name']) + ###post-process参数 + conf_thres,iou_thres,classes=par['conf_thres'],par['iou_thres'],par['classes'] + labelnames=par['labelnames'] + rainbows=par['rainbows'] + fpsample = par['fpsample'] + names=get_labelnames(labelnames) + label_arraylist = get_label_arrays(names,rainbows,outfontsize=40) + iimage_cnt = 0 + post_results=[] + while True: + if not par['queIn'].empty(): + time0=time.time() + datas = par['queIn'].get() + iframe = datas[6] + if par['debug']: + print('#####process:',par['name'],' line129') + p_result,timeOut = post_process_(datas,conf_thres, iou_thres,names,label_arraylist,rainbows,iframe) + par['queOut'].put(p_result) + ##输出结果 + + + + ##每隔 fpsample帧处理一次,如果有问题就保存图片 + if (iframe % fpsample == 0) and (len(post_results)>0) : + #print('####line204:',iframe,post_results) + save_problem_images(post_results,iframe,names) + post_results=[] + + if len(p_result[2] )>0: ## + #post_list = p_result.append(iframe) + post_results.append(p_result) + #print('####line201:',type(p_result)) + + time1=time.time() + outstr='process:%s ,iframe:%d,%s , time:%s, queLen:%d '%( par['name'],iframe,timeOut,get_ms(time0,time1) ,par['queIn'].qsize() ) + #FP_DEBUG.write(outstr +'\n') + #print( 'process:%s ,iframe:%d,%s , time:%s, queLen:%d '%( par['name'],iframe,timeOut,get_ms(time0,time1) ,par['queIn'].qsize() ) ) + else: + time.sleep(1/300) + + +def save_logfile(name,txt): + if os.path.exists(name): + fp=open(name,'r+') + else: + fp=open(name,'w') + + fp.write('%s %s \n'%(time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),txt)) + fp.close() +def time_str(): + return time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()) + + + +if __name__=='__main__': + jsonfile='config/queRiver.json' + #image_encode_decode() + work_stream(jsonfile) + #par={'name':'preprocess'} + #preprocess(par) diff --git a/vodsdk/util/QueUtil.py b/vodsdk/util/QueUtil.py new file mode 100644 index 0000000..4fb8334 --- /dev/null +++ b/vodsdk/util/QueUtil.py @@ -0,0 +1,50 @@ +# -*- coding: utf-8 -*- +from time import time +from traceback import format_exc + +from loguru import logger + +from enums.ExceptionEnum import ExceptionType +from exception.CustomerException import ServiceException + + +def get_no_block_queue(queue): + try: + return queue.get(block=False) + except Exception: + return None + + +def put_queue(queue, result, block=True, timeout=None, is_ex=False): + try: + queue.put(result, block=block, timeout=timeout) + except Exception: + logger.error("添加队列异常:{}", format_exc()) + if is_ex: + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + + +def put_queue_result(queue, result, block=True, timeout=None): + try: + queue.put(result, block=block, timeout=timeout) + return True + except Exception: + logger.error("添加队列异常:{}", format_exc()) + return False + + +def clear_queue(queue): + c_time = time() + while True: + if time() - c_time > 120: + logger.error("清空队列失败, 情况队列超时!") + raise ServiceException(ExceptionType.SERVICE_INNER_EXCEPTION.value[0], + ExceptionType.SERVICE_INNER_EXCEPTION.value[1]) + get_no_block_queue(queue) + if queue.empty() or queue.qsize() == 0: + break + # try: + # queue.get_nowait() + # except Exception: + # break diff --git a/vodsdk/util/RWUtils.py b/vodsdk/util/RWUtils.py new file mode 100644 index 0000000..86d5923 --- /dev/null +++ b/vodsdk/util/RWUtils.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from json import loads + +from ruamel.yaml import safe_load + + +def getConfigs(path, read_type='yml'): + with open(path, 'r', encoding="utf-8") as f: + if read_type == 'json': + return loads(f.read()) + if read_type == 'yml': + return safe_load(f) + raise Exception('路径: %s未获取配置信息' % path) + + +def readFile(file, ty="rb"): + with open(file, ty) as f: + return f.read() + diff --git a/vodsdk/util/TimeUtils.py b/vodsdk/util/TimeUtils.py new file mode 100644 index 0000000..64c9516 --- /dev/null +++ b/vodsdk/util/TimeUtils.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- + +import time +import datetime + +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__": +# print(now_date_to_str(YMDHMSF)) diff --git a/vodsdk/util/TorchUtils.py b/vodsdk/util/TorchUtils.py new file mode 100644 index 0000000..fc87839 --- /dev/null +++ b/vodsdk/util/TorchUtils.py @@ -0,0 +1,315 @@ +# YOLOv5 PyTorch utils + +import datetime + +import math +import os +import platform +import subprocess +import time +from contextlib import contextmanager +from copy import deepcopy +from pathlib import Path +from loguru import logger +import torch +import torch.backends.cudnn as cudnn +import torch.nn as nn +import torch.nn.functional as F +import torchvision + +try: + import thop # for FLOPS computation +except ImportError: + thop = None + + +@contextmanager +def torch_distributed_zero_first(local_rank: int): + """ + Decorator to make all processes in distributed training wait for each local_master to do something. + """ + if local_rank not in [-1, 0]: + torch.distributed.barrier() + yield + if local_rank == 0: + torch.distributed.barrier() + + +def init_torch_seeds(seed=0): + # Speed-reproducibility tradeoff https://pytorch.org/docs/stable/notes/randomness.html + torch.manual_seed(seed) + if seed == 0: # slower, more reproducible + cudnn.benchmark, cudnn.deterministic = False, True + else: # faster, less reproducible + cudnn.benchmark, cudnn.deterministic = True, False + + +# 文件最后修改时间 +def date_modified(path=__file__): + # return human-readable file modification date, i.e. '2021-3-26' + t = datetime.datetime.fromtimestamp(Path(path).stat().st_mtime) + return f'{t.year}-{t.month}-{t.day}' + + +def git_describe(path=Path(__file__).parent): # path must be a directory + # return human-readable git description, i.e. v5.0-5-g3e25f1e https://git-scm.com/docs/git-describe + # -C 指定GIT仓库的路径 + # describe: 命令名,表示获取最近的Git标签信息。 + # tags: 选项,表示只考虑标签。 + # long: 选项,表示使用完整的Git SHA-1哈希值来描述提交。 + # always: 选项,表示如果没有Git标签,则使用Git哈希值来描述提交。 + s = f'git -C {path} describe --tags --long --always' + try: + return subprocess.check_output(s, shell=True, stderr=subprocess.STDOUT).decode()[:-1] + except subprocess.CalledProcessError as e: + return '' + + +def select_device(device='0'): + logger.info("当前torch版本: {}", torch.__version__) + # 设置环境变量 + os.environ['CUDA_VISIBLE_DEVICES'] = device + assert torch.cuda.is_available(), f'CUDA unavailable, invalid device {device} requested' + return torch.device('cuda:%s' % device) + + +# def select_device(device='', batch_size=None): +# # device = 'cpu' or '0' or '0,1,2,3' +# s = f'YOLOv5 🚀 {git_describe() or date_modified()} torch {torch.__version__} ' # string +# cpu = device.lower() == 'cpu' +# if cpu: +# os.environ['CUDA_VISIBLE_DEVICES'] = '-1' # force torch.cuda.is_available() = False +# elif device: # non-cpu device requested +# os.environ['CUDA_VISIBLE_DEVICES'] = device # set environment variable +# assert torch.cuda.is_available(), f'CUDA unavailable, invalid device {device} requested' # check availability +# +# cuda = not cpu and torch.cuda.is_available() +# if cuda: +# n = torch.cuda.device_count() +# if n > 1 and batch_size: # check that batch_size is compatible with device_count +# assert batch_size % n == 0, f'batch-size {batch_size} not multiple of GPU count {n}' +# space = ' ' * len(s) +# for i, d in enumerate(device.split(',') if device else range(n)): +# p = torch.cuda.get_device_properties(i) +# s += f"{'' if i == 0 else space}CUDA:{d} ({p.name}, {p.total_memory / 1024 ** 2}MB)\n" # bytes to MB +# else: +# s += 'CPU\n' +# logger.info(s.encode().decode('ascii', 'ignore') if platform.system() == 'Windows' else s) # emoji-safe +# return torch.device('cuda:0' if cuda else 'cpu') + + +def time_synchronized(): + # pytorch-accurate time + if torch.cuda.is_available(): + torch.cuda.synchronize() + return time.time() + + +def profile(x, ops, n=100, device=None): + # profile a pytorch module or list of modules. Example usage: + # x = torch.randn(16, 3, 640, 640) # input + # m1 = lambda x: x * torch.sigmoid(x) + # m2 = nn.SiLU() + # profile(x, [m1, m2], n=100) # profile speed over 100 iterations + + device = device or torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') + x = x.to(device) + x.requires_grad = True + print(torch.__version__, device.type, torch.cuda.get_device_properties(0) if device.type == 'cuda' else '') + print(f"\n{'Params':>12s}{'GFLOPS':>12s}{'forward (ms)':>16s}{'backward (ms)':>16s}{'input':>24s}{'output':>24s}") + for m in ops if isinstance(ops, list) else [ops]: + m = m.to(device) if hasattr(m, 'to') else m # device + m = m.half() if hasattr(m, 'half') and isinstance(x, torch.Tensor) and x.dtype is torch.float16 else m # type + dtf, dtb, t = 0., 0., [0., 0., 0.] # dt forward, backward + try: + flops = thop.profile(m, inputs=(x,), verbose=False)[0] / 1E9 * 2 # GFLOPS + except: + flops = 0 + + for _ in range(n): + t[0] = time_synchronized() + y = m(x) + t[1] = time_synchronized() + try: + _ = y.sum().backward() + t[2] = time_synchronized() + except: # no backward method + t[2] = float('nan') + dtf += (t[1] - t[0]) * 1000 / n # ms per op forward + dtb += (t[2] - t[1]) * 1000 / n # ms per op backward + + s_in = tuple(x.shape) if isinstance(x, torch.Tensor) else 'list' + s_out = tuple(y.shape) if isinstance(y, torch.Tensor) else 'list' + p = sum(list(x.numel() for x in m.parameters())) if isinstance(m, nn.Module) else 0 # parameters + print(f'{p:12}{flops:12.4g}{dtf:16.4g}{dtb:16.4g}{str(s_in):>24s}{str(s_out):>24s}') + + +def is_parallel(model): + return type(model) in (nn.parallel.DataParallel, nn.parallel.DistributedDataParallel) + + +def intersect_dicts(da, db, exclude=()): + # Dictionary intersection of matching keys and shapes, omitting 'exclude' keys, using da values + return {k: v for k, v in da.items() if k in db and not any(x in k for x in exclude) and v.shape == db[k].shape} + + +def initialize_weights(model): + for m in model.modules(): + t = type(m) + if t is nn.Conv2d: + pass # nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu') + elif t is nn.BatchNorm2d: + m.eps = 1e-3 + m.momentum = 0.03 + elif t in [nn.Hardswish, nn.LeakyReLU, nn.ReLU, nn.ReLU6]: + m.inplace = True + + +def find_modules(model, mclass=nn.Conv2d): + # Finds layer indices matching module class 'mclass' + return [i for i, m in enumerate(model.module_list) if isinstance(m, mclass)] + + +def sparsity(model): + # Return global model sparsity + a, b = 0., 0. + for p in model.parameters(): + a += p.numel() + b += (p == 0).sum() + return b / a + + +def prune(model, amount=0.3): + # Prune model to requested global sparsity + import torch.nn.utils.prune as prune + print('Pruning model... ', end='') + for name, m in model.named_modules(): + if isinstance(m, nn.Conv2d): + prune.l1_unstructured(m, name='weight', amount=amount) # prune + prune.remove(m, 'weight') # make permanent + print(' %.3g global sparsity' % sparsity(model)) + + +def fuse_conv_and_bn(conv, bn): + # Fuse convolution and batchnorm layers https://tehnokv.com/posts/fusing-batchnorm-and-conv/ + fusedconv = nn.Conv2d(conv.in_channels, + conv.out_channels, + kernel_size=conv.kernel_size, + stride=conv.stride, + padding=conv.padding, + groups=conv.groups, + bias=True).requires_grad_(False).to(conv.weight.device) + + # prepare filters + w_conv = conv.weight.clone().view(conv.out_channels, -1) + w_bn = torch.diag(bn.weight.div(torch.sqrt(bn.eps + bn.running_var))) + fusedconv.weight.copy_(torch.mm(w_bn, w_conv).view(fusedconv.weight.shape)) + + # prepare spatial bias + b_conv = torch.zeros(conv.weight.size(0), device=conv.weight.device) if conv.bias is None else conv.bias + b_bn = bn.bias - bn.weight.mul(bn.running_mean).div(torch.sqrt(bn.running_var + bn.eps)) + fusedconv.bias.copy_(torch.mm(w_bn, b_conv.reshape(-1, 1)).reshape(-1) + b_bn) + + return fusedconv + + +def model_info(model, verbose=False, img_size=640): + # Model information. img_size may be int or list, i.e. img_size=640 or img_size=[640, 320] + n_p = sum(x.numel() for x in model.parameters()) # number parameters + n_g = sum(x.numel() for x in model.parameters() if x.requires_grad) # number gradients + if verbose: + print('%5s %40s %9s %12s %20s %10s %10s' % ('layer', 'name', 'gradient', 'parameters', 'shape', 'mu', 'sigma')) + for i, (name, p) in enumerate(model.named_parameters()): + name = name.replace('module_list.', '') + print('%5g %40s %9s %12g %20s %10.3g %10.3g' % + (i, name, p.requires_grad, p.numel(), list(p.shape), p.mean(), p.std())) + + try: # FLOPS + from thop import profile + stride = max(int(model.stride.max()), 32) if hasattr(model, 'stride') else 32 + img = torch.zeros((1, model.yaml.get('ch', 3), stride, stride), device=next(model.parameters()).device) # input + flops = profile(deepcopy(model), inputs=(img,), verbose=False)[0] / 1E9 * 2 # stride GFLOPS + img_size = img_size if isinstance(img_size, list) else [img_size, img_size] # expand if int/float + fs = ', %.1f GFLOPS' % (flops * img_size[0] / stride * img_size[1] / stride) # 640x640 GFLOPS + except (ImportError, Exception): + fs = '' + + logger.info(f"Model Summary: {len(list(model.modules()))} layers, {n_p} parameters, {n_g} gradients{fs}") + + +def load_classifier(name='resnet101', n=2): + # Loads a pretrained model reshaped to n-class output + model = torchvision.models.__dict__[name](pretrained=True) + + # ResNet model properties + # input_size = [3, 224, 224] + # input_space = 'RGB' + # input_range = [0, 1] + # mean = [0.485, 0.456, 0.406] + # std = [0.229, 0.224, 0.225] + + # Reshape output to n classes + filters = model.fc.weight.shape[1] + model.fc.bias = nn.Parameter(torch.zeros(n), requires_grad=True) + model.fc.weight = nn.Parameter(torch.zeros(n, filters), requires_grad=True) + model.fc.out_features = n + return model + + +def scale_img(img, ratio=1.0, same_shape=False, gs=32): # img(16,3,256,416) + # scales img(bs,3,y,x) by ratio constrained to gs-multiple + if ratio == 1.0: + return img + else: + h, w = img.shape[2:] + s = (int(h * ratio), int(w * ratio)) # new size + img = F.interpolate(img, size=s, mode='bilinear', align_corners=False) # resize + if not same_shape: # pad/crop img + h, w = [math.ceil(x * ratio / gs) * gs for x in (h, w)] + return F.pad(img, [0, w - s[1], 0, h - s[0]], value=0.447) # value = imagenet mean + + +def copy_attr(a, b, include=(), exclude=()): + # Copy attributes from b to a, options to only include [...] and to exclude [...] + for k, v in b.__dict__.items(): + if (len(include) and k not in include) or k.startswith('_') or k in exclude: + continue + else: + setattr(a, k, v) + + +class ModelEMA: + """ Model Exponential Moving Average from https://github.com/rwightman/pytorch-image-models + Keep a moving average of everything in the model state_dict (parameters and buffers). + This is intended to allow functionality like + https://www.tensorflow.org/api_docs/python/tf/train/ExponentialMovingAverage + A smoothed version of the weights is necessary for some training schemes to perform well. + This class is sensitive where it is initialized in the sequence of model init, + GPU assignment and distributed training wrappers. + """ + + def __init__(self, model, decay=0.9999, updates=0): + # Create EMA + self.ema = deepcopy(model.module if is_parallel(model) else model).eval() # FP32 EMA + # if next(model.parameters()).device.type != 'cpu': + # self.ema.half() # FP16 EMA + self.updates = updates # number of EMA updates + self.decay = lambda x: decay * (1 - math.exp(-x / 2000)) # decay exponential ramp (to help early epochs) + for p in self.ema.parameters(): + p.requires_grad_(False) + + def update(self, model): + # Update EMA parameters + with torch.no_grad(): + self.updates += 1 + d = self.decay(self.updates) + + msd = model.module.state_dict() if is_parallel(model) else model.state_dict() # model state_dict + for k, v in self.ema.state_dict().items(): + if v.dtype.is_floating_point: + v *= d + v += (1. - d) * msd[k].detach() + + def update_attr(self, model, include=(), exclude=('process_group', 'reducer')): + # Update EMA attributes + copy_attr(self.ema, model, include, exclude) diff --git a/vodsdk/util/__init__.py b/vodsdk/util/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/vodsdk/util/__pycache__/AliyunSdk.cpython-38.pyc b/vodsdk/util/__pycache__/AliyunSdk.cpython-38.pyc new file mode 100644 index 0000000..ff407b8 Binary files /dev/null and b/vodsdk/util/__pycache__/AliyunSdk.cpython-38.pyc differ diff --git a/vodsdk/util/__pycache__/CpuUtils.cpython-38.pyc b/vodsdk/util/__pycache__/CpuUtils.cpython-38.pyc new file mode 100644 index 0000000..8380bad Binary files /dev/null and b/vodsdk/util/__pycache__/CpuUtils.cpython-38.pyc differ diff --git a/vodsdk/util/__pycache__/Cv2Utils.cpython-38.pyc b/vodsdk/util/__pycache__/Cv2Utils.cpython-38.pyc new file mode 100644 index 0000000..e879d50 Binary files /dev/null and b/vodsdk/util/__pycache__/Cv2Utils.cpython-38.pyc differ diff --git a/vodsdk/util/__pycache__/FileUtils.cpython-38.pyc b/vodsdk/util/__pycache__/FileUtils.cpython-38.pyc new file mode 100644 index 0000000..0fe7fa8 Binary files /dev/null and b/vodsdk/util/__pycache__/FileUtils.cpython-38.pyc differ diff --git a/vodsdk/util/__pycache__/GPUtils.cpython-38.pyc b/vodsdk/util/__pycache__/GPUtils.cpython-38.pyc new file mode 100644 index 0000000..46b5a42 Binary files /dev/null and b/vodsdk/util/__pycache__/GPUtils.cpython-38.pyc differ diff --git a/vodsdk/util/__pycache__/ImageUtils.cpython-310.pyc b/vodsdk/util/__pycache__/ImageUtils.cpython-310.pyc new file mode 100644 index 0000000..74f8546 Binary files /dev/null and b/vodsdk/util/__pycache__/ImageUtils.cpython-310.pyc differ diff --git a/vodsdk/util/__pycache__/ImageUtils.cpython-38.pyc b/vodsdk/util/__pycache__/ImageUtils.cpython-38.pyc new file mode 100644 index 0000000..44a32f2 Binary files /dev/null and b/vodsdk/util/__pycache__/ImageUtils.cpython-38.pyc differ diff --git a/vodsdk/util/__pycache__/ImgBaiduSdk.cpython-38.pyc b/vodsdk/util/__pycache__/ImgBaiduSdk.cpython-38.pyc new file mode 100644 index 0000000..99f5be9 Binary files /dev/null and b/vodsdk/util/__pycache__/ImgBaiduSdk.cpython-38.pyc differ diff --git a/vodsdk/util/__pycache__/KafkaUtils.cpython-38.pyc b/vodsdk/util/__pycache__/KafkaUtils.cpython-38.pyc new file mode 100644 index 0000000..96daf51 Binary files /dev/null and b/vodsdk/util/__pycache__/KafkaUtils.cpython-38.pyc differ diff --git a/vodsdk/util/__pycache__/LocationUtils.cpython-38.pyc b/vodsdk/util/__pycache__/LocationUtils.cpython-38.pyc new file mode 100644 index 0000000..e1d16ee Binary files /dev/null and b/vodsdk/util/__pycache__/LocationUtils.cpython-38.pyc differ diff --git a/vodsdk/util/__pycache__/LogUtils.cpython-38.pyc b/vodsdk/util/__pycache__/LogUtils.cpython-38.pyc new file mode 100644 index 0000000..d6eeb6e Binary files /dev/null and b/vodsdk/util/__pycache__/LogUtils.cpython-38.pyc differ diff --git a/vodsdk/util/__pycache__/MinioSdk.cpython-38.pyc b/vodsdk/util/__pycache__/MinioSdk.cpython-38.pyc new file mode 100644 index 0000000..3ef6bab Binary files /dev/null and b/vodsdk/util/__pycache__/MinioSdk.cpython-38.pyc differ diff --git a/vodsdk/util/__pycache__/ModelUtils.cpython-38.pyc b/vodsdk/util/__pycache__/ModelUtils.cpython-38.pyc new file mode 100644 index 0000000..2381de6 Binary files /dev/null and b/vodsdk/util/__pycache__/ModelUtils.cpython-38.pyc differ diff --git a/vodsdk/util/__pycache__/ModelUtils2.cpython-38.pyc b/vodsdk/util/__pycache__/ModelUtils2.cpython-38.pyc new file mode 100644 index 0000000..29b6a09 Binary files /dev/null and b/vodsdk/util/__pycache__/ModelUtils2.cpython-38.pyc differ diff --git a/vodsdk/util/__pycache__/OcrBaiduSdk.cpython-38.pyc b/vodsdk/util/__pycache__/OcrBaiduSdk.cpython-38.pyc new file mode 100644 index 0000000..e8af1ec Binary files /dev/null and b/vodsdk/util/__pycache__/OcrBaiduSdk.cpython-38.pyc differ diff --git a/vodsdk/util/__pycache__/PlotsUtils.cpython-38.pyc b/vodsdk/util/__pycache__/PlotsUtils.cpython-38.pyc new file mode 100644 index 0000000..db14438 Binary files /dev/null and b/vodsdk/util/__pycache__/PlotsUtils.cpython-38.pyc differ diff --git a/vodsdk/util/__pycache__/PushStreamUtils.cpython-38.pyc b/vodsdk/util/__pycache__/PushStreamUtils.cpython-38.pyc new file mode 100644 index 0000000..1d96aec Binary files /dev/null and b/vodsdk/util/__pycache__/PushStreamUtils.cpython-38.pyc differ diff --git a/vodsdk/util/__pycache__/QueUtil.cpython-38.pyc b/vodsdk/util/__pycache__/QueUtil.cpython-38.pyc new file mode 100644 index 0000000..dec6224 Binary files /dev/null and b/vodsdk/util/__pycache__/QueUtil.cpython-38.pyc differ diff --git a/vodsdk/util/__pycache__/RWUtils.cpython-38.pyc b/vodsdk/util/__pycache__/RWUtils.cpython-38.pyc new file mode 100644 index 0000000..28455a7 Binary files /dev/null and b/vodsdk/util/__pycache__/RWUtils.cpython-38.pyc differ diff --git a/vodsdk/util/__pycache__/TimeUtils.cpython-38.pyc b/vodsdk/util/__pycache__/TimeUtils.cpython-38.pyc new file mode 100644 index 0000000..1a50bb9 Binary files /dev/null and b/vodsdk/util/__pycache__/TimeUtils.cpython-38.pyc differ diff --git a/vodsdk/util/__pycache__/TorchUtils.cpython-38.pyc b/vodsdk/util/__pycache__/TorchUtils.cpython-38.pyc new file mode 100644 index 0000000..fedd5ab Binary files /dev/null and b/vodsdk/util/__pycache__/TorchUtils.cpython-38.pyc differ diff --git a/vodsdk/util/__pycache__/__init__.cpython-310.pyc b/vodsdk/util/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000..20efd09 Binary files /dev/null and b/vodsdk/util/__pycache__/__init__.cpython-310.pyc differ diff --git a/vodsdk/util/__pycache__/__init__.cpython-38.pyc b/vodsdk/util/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..bf6d77c Binary files /dev/null and b/vodsdk/util/__pycache__/__init__.cpython-38.pyc differ