class Config: """ Configuration settings """ def __init__(self, file=None): if not file: file = os.path.abspath(os.curdir) + "/config.ini" self.log = Log().handle(__name__) self.log.info(f"Config file: {file}") self.config = configparser.ConfigParser(allow_no_value=True) self.config.read(file) def settings(self, section, field=None): settings = self.config.items(section) try: settings = self.config.items(section) except Exception as e: self.log.error(f"Script exited with error: [{e}]") sys.exit(1) if field: try: section_settings = dict(settings)[field.lower()] except Exception as e: self.log.error(f"Script exited with error: [{e}]") sys.exit(1) self.log.debug( f"Config settings for {section}:{field} is {section_settings}") return section_settings
class FileReadersFactory: """ Returns file reader object """ def __init__(self): self.log = Log().handle(__name__) def get_file_reader(self, file_type): self.log.debug(f"Returning [{file_type}] reader object") return eval(f"{file_type.title()}FileReader")()
class Mail(object): ''' classdocs ''' def __init__(self, from_addr, to_addrs): self.logger = Log().getLogger("Mail") self.from_addr = from_addr self.to_addrs = to_addrs def set_from_addr(self, from_addr): self.from_addr = from_addr def set_to_addrs(self, to_addrs): self.to_addrs = to_addrs def init_smtp(self, from_addr, to_addrs): self.smtp = smtplib.SMTP('mail.emea.nsn-intra.net') self.message = MIMEMultipart() self.message['From'] = from_addr self.message['To'] = to_addrs def close_smtp(self): self.smtp.close() def create(self, subject, content, attachment=None, subtype='plain'): self.init_smtp(self.from_addr, self.to_addrs) self.add_mail_subject(subject) if content: self.add_mail_content(content, subtype) if attachment: self.add_mail_attach(attachment) def send(self): self.logger.debug('From: ' + self.from_addr + ' To:' + self.to_addrs + ' Message:' + self.message.as_string()) self.smtp.sendmail(self.from_addr, self.to_addrs, self.message.as_string()) self.close_smtp() def add_mail_subject(self, subject): self.message['Subject'] = subject def add_mail_content(self, content_str, subtype): mail_msg = MIMEText(content_str, subtype) self.message.attach(mail_msg) def add_mail_attach(self, attach_list): for filename in attach_list: source_file = open(filename, 'rb') attachment = MIMEApplication(source_file.read()) attachment.add_header('Content-Disposition', 'attachment', filename=os.path.basename(filename)) self.message.attach(attachment) self.logger.info('add %s as attachment' % filename)
class BanksFactory: """ Returns bank object """ def __init__(self): self.log = Log().handle(__name__) def get_bank(self, bank): self.log.debug(f"Returning bank [{bank}] object") return eval(bank)()
class Test(unittest.TestCase): def setUp(self): self.uri = 'http://e.mi.com/openapi/' self.signId = 'HyASGBRpjkmwqdmo' self.customerId = '112651' self.port = 'campaign/list' self.method = 'GET' self.log = Log("TestCreativeList").print_log() def test_creative_test(self): data = { "customerId": self.customerId, "sdate": "2018-08-05", "edate": "2018-08-05" } data.update({"signId": self.signId}) url = GenerateURL().generate_url(u=str(self.uri + self.port), d=data) print(url) request = Client(url, method=self.method).send_request() json = request.json() print(json) self.assertTrue(json['success']) self.assertEqual(0, json['code']) self.log.debug("response " + str(json['result']))
class SVHN_Predict(): def __init__(self, opt, ReIDCfg, Num_Pred_opt, Pose_output_queue, S_Number_Predict, vis=False, save_results=False, queueSize=1024): self.opt = opt self.dir_name = opt.dir_name self.root_path = os.path.join(opt.data_root, '{}'.format(opt.dir_name)) # logger.info('目标文件夹是{}'.format(self.root_path)) self.file_name = opt.file_name self.file_save_name_before_Number_Rectify = 'Step1_' self.file_save_name_after_Number_Rectify = 'Step2_' # 本来就是要载入两次视频,分开读亦可以 self.Videoparameters, \ self.setting_parameter, \ self.action_datas, \ self.channel_list, \ self.parameter = read_data_from_json_file_v2(self.root_path, self.file_name, self.opt) # 号码纠正器, 根据四官报告来修改参数 self.Number_Rectifier = Number_Rectifier self.datalen = len(self.action_datas) self.batch_size = 60 self.Num_Pred_opt = Num_Pred_opt # 用来设置号码识别模型的参数。 self.SVHN_predictor = load_in_Svhn_model(self.Num_Pred_opt) self.input_Q = Pose_output_queue # 骨骼关键节点检测后的输入结果 self.PreProcess_Q = Queue(maxsize=queueSize) # 在号码识别前,对输入图片进行预处理。 self.SVHN_Q = Queue(maxsize=queueSize) self.transform = transforms.Compose([ transforms.Resize([54, 54]), transforms.ToTensor(), transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]) ]) self.vis = vis if self.vis == True: self.vis_path = os.path.join(self.root_path, 'vis') os.makedirs(self.vis_path, exist_ok=True) self.S_Number_Predict = S_Number_Predict self.S_Final = max(S_Number_Predict - 1, 0) self.height_threshold = 21 self.width_threshold = 12 self.save_results = save_results if self.save_results == True: self.intermediate_results_dir = os.path.join( self.root_path, 'intermediate_results', 'SVHN_Predict') os.makedirs(self.intermediate_results_dir, exist_ok=True) self.main_imgs_dir = os.path.join(self.root_path, 'intermediate_results', 'main_imgs') self.FMLoader_dir = os.path.join(self.root_path, 'intermediate_results', 'FMLoader') # 加载 ReID 模型 self.ReIDCfg = ReIDCfg self.num_cls = 4 # 场上有几种类型的人 self.logger = Log(__name__, 'SVHN_Predict').getlog() def Read_From_Cache(self): ''' 从文件把之前计算过的结果提取出来 ''' self.logger.debug( 'The pid of SVHN_Predict.Read_From_Cache() : {}'.format( os.getpid())) self.logger.debug( 'The thread of SVHN_Predict.Read_From_Cache() : {}'.format( currentThread())) self.load_intermediate_resutls(self.S_Final) self.logger.log( 24, ' SVHN_Predict loads action {} from Cache file '.format( self.S_Final)) def PreProcess_(self): self.t_PreProcess = Thread(target=self.PreProcess, args=()) self.t_PreProcess.daemon = True self.t_PreProcess.start() def PreProcess(self): ''' 对需要号码识别的图片进行预处理。 ''' self.logger.debug('The pid of SVHN_Predict.PreProcess() : {}'.format( os.getpid())) self.logger.debug( 'The thread of SVHN_Predict.PreProcess() : {}'.format( currentThread())) PreProcess_timer = Timer() for action_index in range(self.S_Number_Predict, self.datalen): PreProcess_timer.tic() # 开始计时 self.logger.debug( 'PreProcess() ======================================== action {}' .format(action_index)) Flag, input_results = self.input_Q.get() if Flag == False: # Flag == False 的话,直接就不要了 self.PreProcess_Q.put((False, (action_index, []))) continue #输入的数据有意义,可以接着处理 [input_index, sub_imgs_out, target_regions] = input_results if input_index != action_index: self.logger.log( 31, '---——————————————————————————————————index does match') raise Exception( 'SVHN_Predict.PreProcess action_index_update {} != input_index {} ' .format(action_index, input_index)) # 对数据进行预处理。 rectangle_imgs, original_imgs = self.img_pre_for_SVHN( sub_imgs_out, target_regions) if type(rectangle_imgs) != torch.Tensor: self.PreProcess_Q.put((False, (action_index, []))) else: self.PreProcess_Q.put( (True, (action_index, rectangle_imgs, original_imgs))) # self.logger.info('Calibrate_transfer.sub_img_generate() action {} consums {}s'.format(action_index,sub_img_generate_timer.toc())) self.logger.log( 24, 'SVHN_Predict.PreProcess() action {} consums {}s'.format( action_index, PreProcess_timer.toc())) def img_pre_for_SVHN(self, sub_imgs_out, target_regions): ''' 对需要 SVHN 的图片进行 数据预处理的 具体操作 ''' rectangle_imgs = [] original_imgs = [] for target_index in range(len(target_regions)): sub_img = sub_imgs_out[target_index] [xmin, xmax, ymin, ymax] = target_regions[target_index] i_height, i_weight, i_channel = sub_img.shape crop_img = sub_img[max(ymin, 0):min(i_height, ymax), max(xmin, 0):min(xmax, i_weight)] h_i, w_i, _ = crop_img.shape if h_i < self.height_threshold or w_i < self.width_threshold: # 如果背部区域太小了,也要舍弃。 continue crop_image = Image.fromarray(crop_img) crop_image = self.transform(crop_image) rectangle_imgs.append(crop_image) original_imgs.append(sub_img) # 如果都不符合条件的话。 if len(rectangle_imgs) == 0: return None, None rectangle_imgs = torch.stack(rectangle_imgs, dim=0) return rectangle_imgs, original_imgs def Predict_(self): self.t_Predict = Thread(target=self.Predict, args=()) self.t_Predict.daemon = True self.t_Predict.start() def Predict(self): ''' 使用 SVHN 对完成预处理的图片进行号码预测 ''' Predict_timer = Timer() self.logger.debug('The pid of SVHN_Predict.Predict() : {}'.format( os.getpid())) self.logger.debug('The thread of SVHN_Predict.Predict() : {}'.format( currentThread())) for action_index in range(self.S_Number_Predict, self.datalen): Predict_timer.tic() # 开始计时 PreProcess_Flag, PreResults = self.PreProcess_Q.get() self.logger.debug( 'Predict() ======================================== action {}'. format(action_index)) if PreProcess_Flag == False: # 输入的数据无意义 preNum = -1 self.action_datas[action_index]['predicted_nums'] = [] else: # 输入的数据有意义, 读取数据 _, rectangle_imgs, original_imgs = PreResults imgs_length = rectangle_imgs.size(0) leftover = 0 if (imgs_length) % self.batch_size: leftover = 1 num_batches = imgs_length // self.batch_size + leftover if self.vis == True: vis_dir = os.path.join(self.vis_path, '{}'.format(action_index), 'SVHN_Predict') makedir_v1(vis_dir) vis_dir_0 = os.path.join(self.vis_path, '{}'.format(action_index), 'SVHN_Predict_Minus_one') makedir_v1(vis_dir_0) NumsArray = [] for j in range(num_batches): input_imgs_j = rectangle_imgs[j * self.batch_size:min( (j + 1) * self.batch_size, imgs_length)] length_logits_j, digits_logits_j = self.SVHN_predictor( input_imgs_j.cuda()) '''This max function return two column, the first row is value, and the second row is index ''' length_predictions_j = length_logits_j.max( 1)[1].cpu().tolist() digits_predictions_j = [ digits_logits_j.max(1)[1].cpu().tolist() for digits_logits_j in digits_logits_j ] NumsArray_j = [] for Num_i in range(len(length_predictions_j)): Number_len = length_predictions_j[Num_i] if Number_len == 1: Num = digits_predictions_j[0][Num_i] NumsArray_j.append(Num) elif Number_len == 2: Num = digits_predictions_j[0][ Num_i] * 10 + digits_predictions_j[1][Num_i] NumsArray_j.append(Num) elif Number_len == 0: Num = -1 if self.vis == True: cv2.imwrite( os.path.join( vis_dir_0, '{}_P{}.jpg'.format( num_batches * j + Num_i, Num)), original_imgs[Num_i]) continue else: continue if self.vis == True: cv2.imwrite( os.path.join( vis_dir, '{}_P{}.jpg'.format( num_batches * j + Num_i, Num)), original_imgs[Num_i]) NumsArray.extend(NumsArray_j) # 将数据保存下来 self.action_datas[action_index]['predicted_nums'] = NumsArray if len(NumsArray) > 1: # NumberArray range from 0 to 99. # We need to count how many times does each number appear! NumsArray = np.histogram(NumsArray, bins=100, range=(0, 100))[0] preNum = np.argmax(NumsArray) # if preNum == 10: # print('wrong value') preNum_count = NumsArray[preNum] if np.where(NumsArray == preNum_count)[0].size > 1: # if there are more than one number have the maximun counts, then return -1 # can sort by number classification scores. preNum = -1 else: preNum = -1 # 保存数据 True_num = self.action_datas[action_index]['num'] self.action_datas[action_index]['num'] = '{}'.format(preNum) self.logger.log( 24, 'SVHN_Predict.Predict action {} consums {}s'.format( action_index, Predict_timer.toc())) self.logger.log( 24, 'action {} ====================== True num = {}, Predict num = {} =============' .format(action_index, True_num, preNum)) if self.save_results == True: self.save_intermediate_resutls(action_index) self.logger.log( 24, '-----------------------------Finished SVHN_Predict.Predict() datalen = {}-----------------------------' .format(self.datalen)) # Finished 完成了所有的计算,保存最终结果,未进行号码矫正 write_data_to_json_file( self.root_path, self.file_name, self.action_datas, self.parameter, file_save_name=self.file_save_name_before_Number_Rectify) # 根据四官报告修改最终结果 self.action_datas = self.Number_Rectifier( os.path.join( self.root_path, self.file_save_name_before_Number_Rectify + self.file_name)).rectify() self.logger.log( 24, 'Successfully Rectify numbers according to four officials report') write_data_to_json_file( self.root_path, self.file_name, self.action_datas, self.parameter, file_save_name=self.file_save_name_after_Number_Rectify) # 并根据ReID特征划分主图片。 self.cluster_main_imgs() def save_intermediate_resutls(self, action_index): '''将每一次计算的结果保存下来。''' intermediate_resutls_path = os.path.join(self.intermediate_results_dir, '{}'.format(action_index)) os.makedirs(intermediate_resutls_path, exist_ok=True) json_file = os.path.join(intermediate_resutls_path, '{}_action_data.json'.format(action_index)) with open(json_file, 'w') as f: json.dump(self.action_datas, f) def load_intermediate_resutls(self, action_index): '''将中间结果读取出来''' intermediate_resutls_path = os.path.join(self.intermediate_results_dir, '{}'.format(action_index)) os.makedirs(intermediate_resutls_path, exist_ok=True) json_file = os.path.join(intermediate_resutls_path, '{}_action_data.json'.format(action_index)) with open(json_file, 'r') as f: self.action_datas = json.load(f) def mk_cluster_dirs(self, save_dir, num_cls): ''' save_dir : 保存分类结果的根目录 num_cls : 分类的数量,种类数 ''' for i in range(num_cls): sub_dir = os.path.join(save_dir, str(i)) if os.path.exists(sub_dir): shutil.rmtree(sub_dir) os.makedirs(sub_dir, exist_ok=True) def generate_main_imgs(self): '''在追踪结果的基础之上,生成各个动作的主图片。''' if os.path.exists(self.main_imgs_dir): shutil.rmtree(self.main_imgs_dir) os.makedirs(self.main_imgs_dir) FMLoader = self.FMLoader_dir if os.path.exists(FMLoader): print('{} exists'.format(FMLoader)) action_indexes = os.listdir(FMLoader) action_indexes = sorted(action_indexes, key=lambda x: int(x)) for action_index in action_indexes: action_dir = os.path.join(FMLoader, '{}'.format(action_index)) if os.path.exists(action_dir): target_read_path = os.path.join(action_dir, '0.jpg') target_save_path = os.path.join( self.main_imgs_dir, '{}.jpg'.format(action_index)) shutil.copy(target_read_path, target_save_path) self.logger.log(24, 'SVHN_Predict.generate_main_imgs() Finished') def cluster_main_imgs(self): ''' :param ReID: ReID model :param ReIDCfg: ReID configure :param main_img_dir: The dir save the imgs which the programme what to cluster. :param action_datas: :param save_dir: :param num_cls: how many classes that the programme want ! :return: ''' # 计时器 cluster_main_imgs_timer = Timer() cluster_main_imgs_timer.tic() '''在追踪结果的基础之上,生成各个动作的主图片。''' self.generate_main_imgs() # 创建ReID模型 self.ReID = ReID_Model(self.ReIDCfg) self.ReID.cuda() # make directories to save the clustered imgs. action_datas = self.action_datas # 场上有四类目标人物,创建四个子文件夹 save_dir = self.main_imgs_dir self.mk_cluster_dirs(save_dir, self.num_cls) '''Preprocess the imgs before ReID''' if not os.path.exists(self.main_imgs_dir): raise ValueError("The main_img_dir is not exits") '''对要输入ReID网络的图片进行预处理''' imgs_arrays_all, img_names_all = ReID_imgs_load_by_home_and_away( self.ReIDCfg, self.main_imgs_dir, self.action_datas) # 分成主客两队 cls_res_all = { 'Home': 0, 'Away': 2 } # 主队保存在前两个文件夹 0 和 1, 客队保存在后两个文件夹 2 和 3 for TeanIndex, TeamType in enumerate(['Home', 'Away']): imgs_arrays = imgs_arrays_all[TeamType] img_names = img_names_all[TeamType] cls_res = cls_res_all[TeamType] all_feats = [] # 用来存储各个动作主图片的ReID特征 with torch.no_grad(): for imgs_array in imgs_arrays: imgs_array = imgs_array.to('cuda') feats = self.ReID(imgs_array).cpu().numpy().tolist() all_feats.extend(feats) length = len(all_feats) self.logger.log( 24, ' ReID models ,there are {} actions of TeamType {} want to be delt with.' .format(length, TeamType)) '''根据ReID特征,进行分类,分成num_cls类, 门将和球员''' assignments, dataset = k_means(all_feats, 2) '''根据分类结果,将图片按文件夹分类''' for index, cls in enumerate(assignments): cls += cls_res # 所要保存的文件夹的序号 # 是否有识别成功以号码检测为准。 if int(action_datas[int(img_names[index])]['num']) == -1 or \ action_datas[int(img_names[index])]['num'] == None: shutil.copyfile( os.path.join(self.main_imgs_dir, img_names[index] + '.jpg'), os.path.join(save_dir, '{}'.format(cls), '{}_.jpg'.format(img_names[index]))) else: shutil.copyfile( os.path.join(self.main_imgs_dir, img_names[index] + '.jpg'), os.path.join( save_dir, '{}'.format(cls), '{}_{}.jpg'.format( img_names[index], action_datas[int(img_names[index])]['num']))) action_datas[int(img_names[index])]['team'] = str(cls) self.action_datas = action_datas self.logger.log( 24, 'SVHN_Predict.cluster_main_imgs() Finished, consums {}s'.format( cluster_main_imgs_timer.toc()))
class SVHN_Predict(): def __init__(self,dir_root, ReIDCfg, Num_Pred_opt, vis, queueSize=1024): self.dir_root = dir_root self.dir_list = [d for d in os.listdir(self.dir_root) if os.path.isdir(os.path.join(self.dir_root, d))] self.dir_list = sorted(self.dir_list, key=lambda x: int(x)) # logger.info('目标文件夹是{}'.format(self.root_path)) self.datalen = len(self.dir_list) self.Start_Index = 0 if vis: self.vis_path = vis # 号码纠正器, 根据四官报告来修改参数 self.Number_Rectifier = Number_Rectifier self.batch_size = 60 self.Num_Pred_opt = Num_Pred_opt # 用来设置号码识别模型的参数。 self.SVHN_predictor = load_in_Svhn_model(self.Num_Pred_opt) self.PreProcess_Q = Queue(maxsize=queueSize) # 在号码识别前,对输入图片进行预处理。 self.SVHN_Q = Queue(maxsize=queueSize) self.transform = transforms.Compose([ transforms.Resize([54, 54]), transforms.ToTensor(), transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5]) ]) self.height_threshold = 21 self.width_threshold = 12 # 加载 ReID 模型 self.ReIDCfg = ReIDCfg self.num_cls = 4 # 场上有几种类型的人 self.logger = Log(__name__, 'SVHN_Predict').getlog() def PreProcess_(self): self.t_PreProcess = Thread(target=self.PreProcess, args=()) self.t_PreProcess.daemon = True self.t_PreProcess.start() def PreProcess(self): ''' 对需要号码识别的图片进行预处理。 ''' self.logger.debug('The pid of SVHN_Predict.PreProcess() : {}'.format(os.getpid())) self.logger.debug('The thread of SVHN_Predict.PreProcess() : {}'.format(currentThread())) PreProcess_timer = Timer() for dir_index in range(self.Start_Index, self.datalen): PreProcess_timer.tic() # 开始计时 # self.logger.debug('PreProcess() ======================================== action {}'.format(dir_index)) this_dir = os.path.join(self.dir_root,self.dir_list[dir_index],'Target') imgs_name_list= os.listdir(this_dir) if len(imgs_name_list) <= 0: self.PreProcess_Q.put((False, (dir_index, []))) print('{} is empty'.format(this_dir)) continue imgs_transfered_list = [] original_imgs = [] for img_name in imgs_name_list: this_img_path = os.path.join(this_dir,img_name) this_img = cv2.imread(this_img_path) if this_img.size == 0: print('dir_index : {}, img_name : {} is empty'.format(dir_index, img_name) ) continue height, width, _ = this_img.shape if height < self.height_threshold or width < self.width_threshold: # 图片太小了,就不放入骨骼点检测的序列中。 continue img_transfered = Image.fromarray(this_img) img_transfered = self.transform(img_transfered) imgs_transfered_list.append(img_transfered) original_imgs.append(this_img) # 如果都不符合条件的话。 if len(original_imgs) == 0: self.PreProcess_Q.put((False, (dir_index, []))) else: imgs_transfered_list = torch.stack(imgs_transfered_list, dim=0) self.PreProcess_Q.put((True, (dir_index, imgs_transfered_list, original_imgs))) # self.logger.info('Calibrate_transfer.sub_img_generate() action {} consums {}s'.format(action_index,sub_img_generate_timer.toc())) # self.logger.log(24, 'SVHN_Predict.PreProcess() action {} consums {}s'.format(dir_index, PreProcess_timer.toc())) def Predict_(self): self.t_Predict = Thread(target=self.Predict, args=()) self.t_Predict.daemon = True self.t_Predict.start() def Predict(self): ''' 使用 SVHN 对完成预处理的图片进行号码预测 ''' Predict_timer = Timer() self.logger.debug( 'The pid of SVHN_Predict.Predict() : {}'.format(os.getpid())) self.logger.debug( 'The thread of SVHN_Predict.Predict() : {}'.format(currentThread())) Number_TrackingID_dict = {} for dir_index in range(self.Start_Index, self.datalen): Predict_timer.tic() # 开始计时 Predict_len = 0 dir_name = self.dir_list[dir_index] PreProcess_Flag, PreResults = self.PreProcess_Q.get() # self.logger.debug('Predict() ======================================== action {}'.format(action_index)) if PreProcess_Flag == False: # 输入的数据无意义 preNum = -1 else: # 输入的数据有意义, 读取数据 _, rectangle_imgs,original_imgs = PreResults imgs_length = rectangle_imgs.size(0) leftover = 0 if (imgs_length) % self.batch_size: leftover = 1 num_batches = imgs_length // self.batch_size + leftover if self.vis_path: vis_dir = os.path.join(self.vis_path,'{}'.format(dir_name),'SVHN_Predict') makedir_v1(vis_dir) vis_dir_0 = os.path.join(self.vis_path, '{}'.format(dir_name), 'SVHN_Predict_Minus_one') makedir_v1(vis_dir_0) NumsArray = [] for j in range(num_batches): input_imgs_j = rectangle_imgs[j*self.batch_size:min((j+1)*self.batch_size , imgs_length)] length_logits_j, digits_logits_j = self.SVHN_predictor(input_imgs_j.cuda()) '''This max function return two column, the first row is value, and the second row is index ''' length_predictions_j = length_logits_j.max(1)[1].cpu().tolist() digits_predictions_j = [digits_logits_j.max(1)[1].cpu().tolist() for digits_logits_j in digits_logits_j] NumsArray_j = [] for Num_i in range(len(length_predictions_j)): Number_len = length_predictions_j[Num_i] if Number_len == 1: Num = digits_predictions_j[0][Num_i] NumsArray_j.append(Num) elif Number_len == 2: Num = digits_predictions_j[0][Num_i] * 10 + digits_predictions_j[1][Num_i] NumsArray_j.append(Num) elif Number_len == 0: Num = -1 if self.vis_path: cv2.imwrite(os.path.join(vis_dir_0, '{}_P{}.jpg'.format(num_batches*j + Num_i, Num)), original_imgs[Num_i]) continue else: continue if self.vis_path: cv2.imwrite(os.path.join(vis_dir, '{}_P{}.jpg'.format(num_batches*j + Num_i, Num)), original_imgs[Num_i]) NumsArray.extend(NumsArray_j) Predict_len = len(NumsArray) if Predict_len > 1: # NumberArray range from 0 to 99. # We need to count how many times does each number appear! NumsArray = np.histogram(NumsArray, bins=100, range=(0, 100))[0] preNum = np.argmax(NumsArray) # if preNum == 10: # print('wrong value') preNum_count = NumsArray[preNum] if np.where(NumsArray == preNum_count)[0].size > 1: # if there are more than one number have the maximun counts, then return -1 # can sort by number classification scores. preNum = -1 else: preNum = -1 # 保存数据 # self.logger.log(24, 'SVHN_Predict.Predict action {} consums {}s'.format(action_index, Predict_timer.toc())) self.logger.log(24,'dir_name {} Predict_len = {} Predict num = {} ============='.format(dir_name, Predict_len, preNum)) Number_TrackingID_dict[int(dir_name)] = int(preNum) with open(os.path.join(self.vis_path,'Number_results.json'),'w') as f : json.dump(Number_TrackingID_dict,f) self.logger.log(24, '-----------------------------Finished SVHN_Predict.Predict() datalen = {}-----------------------------'.format(self.datalen))
class ParseConfig(object): ''' classdocs ''' def __init__(self, baseline): ''' Constructor ''' self.logger = Log().getLogger("ParseConfig") self.baseline = baseline.strip() self.externals = "" self.fetch_config() self._check_config() def get_externals(self): if self.externals == "": self._parse_externals() return self.externals def _parse_externals(self): self.externals = Externals(self.baseline).parse() def fetch_config(self): self.config = BitbakePostCheckConfig(self.baseline).get_configs() self._parse_externals() self._set_specific_config() self.logger.info("Configuration for baseline " + self.baseline) self.logger.info(self.config) return self.config def _set_specific_config(self): if self.externals.get("CB_BB_PATTERN", "") == "": self.config["patternRepo"] = self.config.get("defaultPatternRepo", "") else: externals = self.externals.get("CB_BB_PATTERN").get("externals", "") if externals == "" or len(externals) == 0 or externals[0].get("repo_path", "") == "": self.config["patternRepo"] = self.config.get("defaultPatternRepo", "") else: if externals[0].get("revision", "") == "": patternRepo = externals[0].get("repo_path") else: patternRepo = "{}@{}".format(externals[0].get("repo_path"), externals[0].get("revision")) self.config["patternRepo"] = "{}{}".format(self.config.get("svnServer"), patternRepo) if self.externals.get("CB_BB_SCRIPTS", "") == "": self.config["bbScriptRepo"] = self.config.get("defaultBbScriptRepo", "") else: externals = self.externals.get("CB_BB_SCRIPTS").get("externals", "") if externals == "" or len(externals) == 0 or externals[0].get("repo_path", "") == "": self.config["bbScriptRepo"] = self.config.get("defaultBbScriptRepo", "") else: if externals[0].get("revision", "") == "": patternRepo = externals[0].get("repo_path") else: patternRepo = "{}@{}".format(externals[0].get("repo_path"), externals[0].get("revision")) self.config["bbScriptRepo"] = "{}{}".format(self.config.get("svnServer"), patternRepo) def _check_config(self): pattern_repo = self.config.get("patternRepo", "") module = self.config.get("module", "") product_id = self.config.get("productId", "") bitbake_path = self.config.get("bitbakePath", "") repo = self.config.get("repo", "") if pattern_repo == "" or module == "" or product_id == "" or bitbake_path == "" or repo == "": raise Exception("Missing configurations, please double check") def fetch_sc_from_package_config(self): config = self._read_package_config() return self._parse_package_config(config) def _parse_package_config(self, config): baselines_from_share = "<baselines from share>" scs = self._get_sc(config, baselines_from_share) baselines_from_externals = "<baselines from svn:external>" scs.extend(self._get_sc(config, baselines_from_externals)) self.logger.debug("Sc list is {}".format(scs)) return scs def _get_sc(self, config, start_line): sc_name = [] start = False for line in config: line = line.strip() if line == "": continue if line == start_line: start = True continue if start: if line == "</baselines>": break sc = line.split()[0] sc_name.append(sc) return sc_name def _read_package_config(self): package_config = SVN().cat(os.path.join(self.config.get("repo"), self.baseline, ".config")).splitlines() return package_config def _read_hardwares(self): pattern_config = os.path.join(self.config.get("patternRepo"), self.config.get("productId"), self.config.get("module"), 'config.json') hardwares = [] if SVN().checkifexist(pattern_config): config = json.loads(SVN().cat(pattern_config)) hardwares = config["hardwares"] else: hardwares.append(os.path.join(self.config.get("productId"), self.config.get("module"))) return hardwares def fetch_bitbake_config(self): self.hardwares = self._read_hardwares() if len(self.hardwares) > 1: self.logger.info("Merging recipes data from {}".format(', '.join(self.hardwares))) self.recipes_data = self._merge_recipe_data() else: recipes_file = os.path.join(self.config.get("patternRepo"), self.hardwares[0], 'recipes.json') json_data = SVN().cat(recipes_file) self.recipes_data = json.loads(json_data) return self.recipes_data def _merge_recipe_data(self): json_recipes = self._read_recipes_files() package_names = set() for file in json_recipes: for package in file: package_names.add(package["package_name"]) recipes_data = [] for package in package_names: data = self._merge_package(json_recipes, package) recipes_data.append(data) return recipes_data def _read_recipes_files(self): json_recipes = [] for hw in self.hardwares: recipes_file = os.path.join(self.config.get("patternRepo"), hw, 'recipes.json') self.logger.info("Reading {}".format(recipes_file)) json_data = SVN().cat(recipes_file) json_recipes.append(json.loads(json_data)) return json_recipes def _merge_package(self, json_recipes, package_name): recipes = [] target_names = set() package_data = {"package_name": package_name} package_dependencies = set() pattern_sources = set() for file in json_recipes: for package in file: if package["package_name"] == package_name: for dependency in package["depends_on"]: package_dependencies.add(dependency) if "pattern_sources" in package: for src in package["pattern_sources"]: pattern_sources.add(src) for target in package["recipes"]: if target["name"] not in target_names: target_names.add(target["name"]) recipes.append(target) else: index = self._find_target(recipes, target["name"]) recipes[index] = self._merge_recipes(recipes[index], target) package_data["recipes"] = recipes package_data["depends_on"] = list(package_dependencies) package_data["pattern_sources"] = list(pattern_sources) return package_data def _find_target(self, recipes, name): for i in range(len(recipes)): if recipes[i]["name"] == name: return i raise IndexError def _merge_recipes(self, target1, target2): if target1["type"] == "target" and target2["type"] == "target": target1["architectures"] = self._merge_values(target1, target2, "architectures") target1["depends_on"] = self._merge_values(target1, target2, "depends_on") elif target1["type"] == "source" and target2["type"] == "source": if not "require_to_package" in target1: target1["require_to_package"] = True if not "require_to_package" in target2: target2["require_to_package"] = True target1["require_to_package"] = target1["require_to_package"] or target2["require_to_package"] else: print('ERROR: Could not merge recipes with different types') return target1 def _merge_values(self, target1, target2, key): for value in target2[key]: if value not in target1[key]: target1[key].append(value) return target1[key]
class Client(object): def __init__(self, base_url, method='GET', headers=None, cookies=None): """ :param method: 请求方式,类型要与METHOD中的一致 :param base_url: 请求地址like:1."http://e.mi.com/get" 2."http://e.mi.com/get?customerId=3306&creativeId=1000789" :param headers: 请求的headers参数,入参类型为字典(dict) :param cookies: 请求的cookies参数,入参类型为字典(dict) """ self.url = base_url if method in METHOD: self.method = method else: raise UnKnowMethod('不能识别参数%s' % method) self.header = headers self.cookie = cookies # 声明日志类 self.log = Log('httpclient').print_log() # 新建会话 self.session = requests.session() self.set_session_headers(self.header) self.set_session_cookies(self.cookie) # 获取调用函数的名字 self.module_name = traceback.extract_stack()[-2][2] # 获取调用函数所在文件的文件名 self.module_file = os.path.basename( str(traceback.extract_stack()[-2][0])) def send_request(self, params=None, data=None, timeout=20, remark='', **kwargs): """ 用于单次请求 :param remark: 备注 :param params:关键字参数,字典类型(dict) like:{'key1':'values1', 'key2':['values2', 'values3']} requests会自动与URL拼装,得:http://e.mi.com/get?key1=values1&key2=values2&key2=values3 :param data:post请求发送表单数据参数,字典类型(dict) :param timeout:设置请求超时时间,防止服务器无响应,程序仍在等待中 :param kwargs:其余参数 :return:返回request对象 """ response = '' msg = '' desc = '' if self.method == 'GET': start_time = datetime.utcnow() try: response = requests.get(url=self.url, headers=self.header, cookies=self.cookie, params=params, data=data, timeout=timeout, **kwargs) except RequestException: return None time.sleep(0.02) end_time = datetime.utcnow() sub_time = end_time - start_time result = response.json() if response.status_code == 200: if 'msg' in result: msg = result['msg'] if 'desc' in result: desc = result['desc'] self.log.debug( '>File:%s Module:%s Method:GET Success:%s Code:%s Msg:%s Desc:%s Time_Cost:%s \n URL:%s' % (self.module_file, self.module_name, result['success'], result['code'], msg, desc, sub_time, response.url)) response.encoding = 'utf-8' else: # print(response.text) self.log.debug('error :%s' % response.text) return None elif self.method == 'POST': start_time = datetime.utcnow() try: response = requests.post(url=self.url, headers=self.header, cookies=self.cookie, params=params, data=data, timeout=timeout, **kwargs) except RequestException: return None time.sleep(0.02) end_time = datetime.utcnow() sub_time = end_time - start_time result = response.json() if response.status_code == 200: if 'msg' in result: msg = result['msg'] if 'desc' in result: desc = result['desc'] self.log.debug( '>File:%s Module:%s Method:GET Success:%s Code:%s Msg:%s Desc:%s Time_Cost:%s URL:%s' % (self.module_file, self.module_name, result['success'], result['code'], msg, desc, sub_time, response.url)) response.encoding = 'utf-8' else: # print(response.text) self.log.debug('error :%s' % response.text) return None return response def send_session(self, params=None, data=None, timeout=1, **kwargs): """ 使用session会话请求,特点:会话可记忆设置的headers及cookies :param params: 关键字参数 :param data: form类型数据 :param timeout: 超时 :param kwargs: :return:返回session会话,自由变更cookies和headers """ start_time = datetime.utcnow() response = self.session.request(method=self.method, url=self.url, params=params, data=data, timeout=timeout, **kwargs) end_time = datetime.utcnow() sub_time = end_time - start_time self.log.debug( 'Execute>> method:%s code:%s time_cost:%s URL:%s' % (self.method, response.status_code, sub_time, response.url)) response.encoding = 'utf-8' return response def set_session_headers(self, headers): """设置会话的headers""" if headers: self.session.headers.update(headers) def set_session_cookies(self, cookies): """设置会话的cookies""" if cookies: self.session.cookies.update(cookies)
class Calibrate_transfer(): def __init__(self, opt, detector_opt, Tracker_output_queue, C_T_output_queue, S_Coordinate_transfer, S_Pose_Estimate, vis=False, save_results=False, queueSize=1024): self.logger = Log(__name__, 'Calibrate_transfer').getlog() self.opt = opt self.dir_name = opt.dir_name self.root_path = os.path.join(opt.data_root, '{}'.format(opt.dir_name)) # logger.info('目标文件夹是{}'.format(self.root_path)) self.file_name = opt.file_name # 本来就是要载入两次视频,分开读亦可以 self.Videoparameters, \ self.setting_parameter, \ self.action_datas, \ self.channel_list, \ self.parameter = read_data_from_json_file(self.root_path, self.file_name, self.opt) self.datalen = len(self.action_datas) self.detector_opt = detector_opt # 用来设置追踪器参数的。 self.logger.info('Creating model...') self.detector_model = create_JDETracker_model(self.detector_opt) self.detector = JDETracker( self.detector_opt, self.detector_model) # What is JDE Tracker? 把这个tracker 当detector用 self.input_Q = Tracker_output_queue # 追踪数据的整体输入 self.PreProcess_Q = Queue(maxsize=queueSize) # 在目标检测前,对左边转换后的截图进行预处理 self.tracking_Q = Queue(maxsize=queueSize) self.detecions_Q = Queue(maxsize=queueSize) self.output_Q = C_T_output_queue self.vis = vis if self.vis == True: self.vis_path = os.path.join(self.root_path, 'vis') os.makedirs(self.vis_path, exist_ok=True) self.S_Coordinate_transfer = S_Coordinate_transfer self.S_Pose_Estimate = S_Pose_Estimate self.save_results = save_results if self.save_results == True: self.intermediate_results_dir = os.path.join( self.root_path, 'intermediate_results', 'Calibrate_transfer') os.makedirs(self.intermediate_results_dir, exist_ok=True) def Read_From_Cache(self): ''' 从文件把之前计算过的结果提取出来 ''' from utils.index_operation import get_index self.logger.debug( 'The pid of Calibrate_transfer.Read_From_Cache() : {}'.format( os.getpid())) self.logger.debug( 'The thread of Calibrate_transfer.Read_From_Cache() : {}'.format( currentThread())) cache_index = get_index(self.intermediate_results_dir) # 只需读取有用的部分即可。 action_index = self.S_Pose_Estimate for action_index in range(self.S_Pose_Estimate, self.S_Coordinate_transfer): if action_index not in cache_index: # cache 中没有保存说明 此动作本身是False self.output_Q.put((False, (action_index, [], [], [], []))) else: # 从文件夹中读取出该动作对应的计算结果。 _, sub_img_tracking, ReID_features_tracking, sub_imgs_detection, ReID_features_detection = self.load_intermediate_resutls( action_index) self.output_Q.put( (True, (action_index, sub_img_tracking, ReID_features_tracking, sub_imgs_detection, ReID_features_detection))) self.logger.log( 22, ' Calibrate_transfer loads action {} from Cache file '.format( action_index)) def update_(self): self.t_update = Thread(target=self.update, args=()) self.t_update.daemon = True self.t_update.start() def update(self): ''' 将一个视角下的所有图片转换到其他视角下。 ''' self.logger.debug('The pid of Calibrate_transfer.update() : {}'.format( os.getpid())) self.logger.debug( 'The thread of Calibrate_transfer.update() : {}'.format( currentThread())) update_timer = Timer() sub_img_generate_timer = Timer() for action_index in range(self.S_Coordinate_transfer, self.datalen): update_timer.tic() # 开始计时 self.logger.debug( 'update() ======================================== action {}'. format(action_index)) Flag, input_index, tracking_results = self.input_Q.get() if input_index != action_index: self.logger.log( 31, '---——————————————————————————————————index does match') raise Exception( 'Calibrate_transfer.update action_index_update {} != input_index {} ' .format(action_index, input_index)) if Flag == False: # Flag == False 的话,直接就不要了 self.tracking_Q.put((False, (action_index, [], []))) self.PreProcess_Q.put((False, (action_index, []))) continue frames_time, sub_imgs, ReID_feature_list, img_points = tracking_results # 分为 追踪结果和 对 每一帧追踪进行坐标转换后得到的检测结果 # 这里先将追踪结果存入队列中。 self.tracking_Q.put( (True, (action_index, sub_imgs, ReID_feature_list))) channel, action_time, img_point, video_parameter = read_subdata( self.action_datas[action_index], self.Videoparameters) calibrateParameter = video_parameter['CalibrateParameter'] # 将追踪结果对应的像素坐标转换成世界坐标 '''队列的首项是终极目标,用于校准,不用于后续的坐标转换计算''' '''因此,直接从第二项开始''' world_points = [] start_time = frames_time[1] # 追踪序列开始的时间,这里的时间是相对于开球时间 for p_index in range(1, len(img_points)): img_point = img_points[p_index] # 输入的是连续的轨迹,因为检测原因,可能有诺干帧是没有img_points,长度因此为0 if len(img_point) == 0: world_points.append(None) else: world_point = transform_2d_to_3d( img_point, calibrateParameter.cameraMatrix, calibrateParameter.distCoeffs, calibrateParameter.rotation_vector, calibrateParameter.translation_vector, world_z=0) world_point = np.reshape(world_point, [1, 3]) world_points.append(world_point) # 将世界坐标转换到其他的视角下,并且 截图+detection\ # print('len(world_points) : ', len(world_points)) sub_img_generate_timer.tic() self.sub_img_generate_multi_thread(channel, action_index, world_points, start_time) # self.logger.info('Calibrate_transfer.sub_img_generate() action {} consums {}s'.format(action_index,sub_img_generate_timer.toc())) self.logger.log( 22, 'Calibrate_transfer.update() action {} consums {}s'.format( action_index, update_timer.toc())) def sub_img_generate(self, video_parameter, setting_parameter, world_points, start_time): ''' 基于世界坐标,生成其他视角下的像素坐标 ''' results = [] video = video_parameter['video'] width = video.get(cv2.CAP_PROP_FRAME_WIDTH) height = video.get(cv2.CAP_PROP_FRAME_HEIGHT) # 将时间调整至追踪序列的开头,然后逐帧读取 time = start_time + video_parameter[ 'delta_t'] # action time need to add the delta time to calibrate the time between channels . video.set(cv2.CAP_PROP_POS_MSEC, round(1000 * time)) for index in range(len(world_points)): _, img = video.read() world_point = world_points[index] if type(world_point) != np.ndarray: continue img_point_of_other = object_To_pixel( world_point, video_parameter['CalibrateParameter']) img_point_of_other = np.reshape(img_point_of_other, 2) Message = ScreenSHot_batch(img_point_of_other, img, setting_parameter, width, height) if Message[0] == True: # print('sub img of channel {} candidate {} exists'.format(other_channel,img_count_)) image = Message[1] reference_point = Message[2] sub_imgs_bias = Message[3] results.append([index, image, reference_point, sub_imgs_bias]) else: continue return results def sub_img_generate_multi_thread(self, channel, action_index, world_points, start_time): ''' 基于世界坐标,生成其他视角下的像素坐标 ''' results_all = [] executor = ThreadPoolExecutor(max_workers=len(self.channel_list) - 1) task_list = [] for other_channel in self.channel_list: # 同一个视角,无需在生成截图 if other_channel == channel: continue video_parameter = self.Videoparameters[other_channel] setting_parameter = self.setting_parameter task = executor.submit(self.sub_img_generate, video_parameter, setting_parameter, world_points, start_time) task_list.append(task) for task in task_list: while not task.done(): time.sleep(1) results_all += task.result() if len(results_all) > 0: self.PreProcess_Q.put((True, (action_index, results_all))) else: self.PreProcess_Q.put((False, (action_index, results_all))) def detect_(self): self.t_detect = Thread(target=self.detect, args=()) self.t_detect.daemon = True self.t_detect.start() def detect(self): ''' 用检测其检测每一场图片中的人物 ''' detect_timer = Timer() self.logger.debug('The pid of Calibrate_transfer.detect() : {}'.format( os.getpid())) self.logger.debug( 'The thread of Calibrate_transfer.detect() : {}'.format( currentThread())) for action_index in range(self.S_Coordinate_transfer, self.datalen): self.logger.debug( 'Calibrate_transfer.Detection ------------action {} has been read ' .format(action_index)) Flag_PreProcess, (acton_index, Preprocess_results) = self.PreProcess_Q.get() detect_timer.tic() results = [] if Flag_PreProcess == False: self.detecions_Q.put((False, (acton_index, results))) continue # 争取写成并行的 for [index, img0, reference_point, sub_img_bias] in Preprocess_results: # Img preprocess before detection img = img0[:, :, ::-1].transpose(2, 0, 1) img = np.ascontiguousarray(img, dtype=np.float32) img /= 255.0 # timer.tic() blob = torch.from_numpy(img).cuda().unsqueeze(0) # detection using tracker kernel # dets = [xl, yl, w, h] [dets, id_feature] = self.detector.update_for_detection(blob, img0) if dets.shape[0] == 0: #截图中没有检测到人物, 继续 continue results.append( [img0, dets, id_feature, reference_point, sub_img_bias]) if len(results) > 0: self.detecions_Q.put((True, (acton_index, results))) else: self.detecions_Q.put((False, (acton_index, results))) self.logger.log( 22, 'Calibrate_transfer.detect() action {} consums {}s'.format( action_index, detect_timer.toc())) def postProcess_(self): self.t_postProcess = Thread(target=self.postProcess, args=()) self.t_postProcess.daemon = True self.t_postProcess.start() def postProcess(self): ''' 对检测完之后的结果进行后处理 ''' postProcess_timer = Timer() self.logger.debug( 'The pid of Calibrate_transfer.postProcess() : {}'.format( os.getpid())) self.logger.debug( 'The thread of Calibrate_transfer.postProcess() : {}'.format( currentThread())) for action_index in range(self.S_Coordinate_transfer, self.datalen): self.logger.debug( 'postProcess ------------action {} has been read '.format( action_index)) Flag_detect, (acton_index_detection, results) = self.detecions_Q.get() Flag_tracking, (action_index_tracking, sub_imgs_tracking, ReID_features_tracking) = self.tracking_Q.get() postProcess_timer.tic() if Flag_detect == False or Flag_tracking == False: self.output_Q.put((False, (action_index, [], [], [], []))) continue elif acton_index_detection != action_index or action_index_tracking != action_index: raise Exception( 'acton_index_detection {} != action_index_tracking {} '. format(acton_index_detection, action_index_tracking)) if self.vis == True: vis_dir_ = os.path.join(self.vis_path, '{}'.format(action_index), 'Calibrate_transfer') makedir_v1(vis_dir_) # 把每个sub_box提取出来。 sub_imgs_detection = [] ReID_features_detection = [] # 对所有结果进行筛选,选出和目标人物相同ID的。 for r_index, [ img0, dets, id_feature, reference_point, sub_img_bias ] in enumerate(results): I_h, I_w, _ = img0.shape new_reference_point, target_id = sort_by_point( [acton_index_detection, dets, False], reference_point, input_index='{}_{}'.format(action_index, r_index)) if target_id == None: '''根据reference_point来筛选框时,没有合适的框''' if self.vis == True: vis_img = np.copy(img0) for cv2_index in range(int(dets.shape[0])): box = dets[cv2_index].tolist() x1, y1, w, h = box c_intbox = tuple( map(int, (max(0, x1), max(0, y1), min( x1 + w, I_w), min(y1 + h, I_h)))) cv2.rectangle(vis_img, (c_intbox[0], c_intbox[1]), (c_intbox[2], c_intbox[3]), (255, 0, 0), thickness=2) cv2.circle( vis_img, (int(reference_point[0]), int(reference_point[1])), radius=5, color=(0, 0, 255), thickness=-1) # 原始点为红色 cv2.imwrite( os.path.join(vis_dir_, '{}.jpg'.format(r_index)), vis_img) continue # print('dets.shape, target_id : ',dets.shape, target_id) target_bbox = dets[target_id] # print('target_bbox.shape : ', target_bbox.shape) target_bbox = target_bbox.tolist() # print('target_bbox : ', target_bbox) x1, y1, w, h = target_bbox # 目标区域 intbox = tuple( map(int, (max(0, x1), max(0, y1), min( x1 + w, I_w), min(y1 + h, I_h)))) sub_img = img0[intbox[1]:intbox[3], intbox[0]:intbox[2]] # ids = np.arryy(result[2]) target_feature = id_feature[target_id] sub_imgs_detection.append(sub_img) ReID_features_detection.append(target_feature) if self.vis == True: vis_img = np.copy(img0) for cv2_index in range(int(dets.shape[0])): box = dets[cv2_index].tolist() x1, y1, w, h = box c_intbox = tuple( map(int, (max(0, x1), max(0, y1), min( x1 + w, I_w), min(y1 + h, I_h)))) cv2.rectangle(vis_img, (c_intbox[0], c_intbox[1]), (c_intbox[2], c_intbox[3]), (255, 0, 0), thickness=2) cv2.circle( vis_img, (int(reference_point[0]), int(reference_point[1])), radius=5, color=(0, 0, 255), thickness=-1) # 原始点为红色 cv2.circle(vis_img, (int( new_reference_point[0]), int(new_reference_point[1])), radius=5, color=(0, 255, 255), thickness=-1) cv2.rectangle(vis_img, (intbox[0], intbox[1]), (intbox[2], intbox[3]), (0, 255, 255), thickness=2) cv2.imwrite( os.path.join(vis_dir_, '{}.jpg'.format(r_index)), vis_img) # 可以在此处加一个 ReID 模块 ,用于剔除劣质 sub_imgs sub_imgs = sub_imgs_detection + sub_imgs_tracking ReID_features = ReID_features_detection + ReID_features_tracking self.output_Q.put( (True, (action_index, sub_imgs_tracking, ReID_features_tracking, sub_imgs_detection, ReID_features_detection))) # 保存中间结果 if self.save_results == True: self.save_intermediate_resutls(action_index, sub_imgs, ReID_features, sub_imgs_detection, sub_imgs_tracking, ReID_features_detection, ReID_features_tracking) self.logger.log( 22, 'Calibrate_transfer.postProcess() action {} consums {}s'. format(action_index, postProcess_timer.toc())) # self.logger.log(22, '-----------------------------Finished Calibrate_transfer.postProcess() datalen = {}-----------------------------'.format(self.datalen)) def save_intermediate_resutls(self, action_index, sub_imgs, ReID_features, sub_imgs_detection, sub_imgs_tracking, ReID_features_detection, ReID_features_tracking): '''将每一次计算的结果保存下来。''' intermediate_resutls_path = os.path.join(self.intermediate_results_dir, '{}'.format(action_index)) os.makedirs(intermediate_resutls_path, exist_ok=True) ReID_features = np.array(ReID_features) np.save( os.path.join(intermediate_resutls_path, '{}_ReID_features.npy'.format(action_index)), ReID_features) for img_index in range(len(sub_imgs)): cv2.imwrite( os.path.join(intermediate_resutls_path, '{}.jpg'.format(img_index)), sub_imgs[img_index]) # 保存tracking部分的img和feature intermediate_resutls_path_tracking = os.path.join( self.intermediate_results_dir, '{}/tracking'.format(action_index)) os.makedirs(intermediate_resutls_path_tracking, exist_ok=True) ReID_features_tracking = np.array(ReID_features_tracking) np.save( os.path.join(intermediate_resutls_path_tracking, '{}_ReID_features_tracking.npy'.format(action_index)), ReID_features_tracking) for img_index_tracking in range(len(sub_imgs_tracking)): cv2.imwrite( os.path.join(intermediate_resutls_path_tracking, '{}.jpg'.format(img_index_tracking)), sub_imgs_tracking[img_index_tracking]) # 保存detection部分的img和feature intermediate_resutls_path_detection = os.path.join( self.intermediate_results_dir, '{}/detection'.format(action_index)) os.makedirs(intermediate_resutls_path_detection, exist_ok=True) ReID_features_detection = np.array(ReID_features_detection) np.save( os.path.join( intermediate_resutls_path_detection, '{}_ReID_features_detection.npy'.format(action_index)), ReID_features_detection) for img_index_detection in range(len(sub_imgs_detection)): cv2.imwrite( os.path.join(intermediate_resutls_path_detection, '{}.jpg'.format(img_index_detection)), sub_imgs_detection[img_index_detection]) def load_intermediate_resutls(self, action_index): '''将中间结果读取出来''' intermediate_resutls_path = os.path.join(self.intermediate_results_dir, '{}'.format(action_index)) ReID_features = np.load( os.path.join(intermediate_resutls_path, '{}_ReID_features.npy'.format(action_index))) ReID_features = [_ for _ in ReID_features] # 转换为我们需要的格式 # 把这个文件夹下的图片名称读出来。 sub_imgs_names = [ img_name for img_name in os.listdir(intermediate_resutls_path) if img_name.split('.')[-1] == 'jpg' ] # 把图片名字按升序排列 sub_imgs_names = sorted( sub_imgs_names, key=lambda img_index: int(img_index.split('.')[0])) sub_imgs = [] for img_name in sub_imgs_names: sub_img = cv2.imread( os.path.join(intermediate_resutls_path, img_name)) sub_imgs.append(sub_img) # 读取追踪部分 intermediate_resutls_path_tracking = os.path.join( intermediate_resutls_path, 'tracking') ReID_features_tracking = np.load( os.path.join(intermediate_resutls_path_tracking, '{}_ReID_features_tracking.npy'.format(action_index))) ReID_features_tracking = [_ for _ in ReID_features_tracking ] # 转换为我们需要的格式 # 把这个文件夹下的图片名称读出来。 sub_imgs_names_tracking = [ img_name_tracking for img_name_tracking in os.listdir( intermediate_resutls_path_tracking) if img_name_tracking.split('.')[-1] == 'jpg' ] # 把图片名字按升序排列 sub_imgs_names_tracking = sorted( sub_imgs_names_tracking, key=lambda img_index: int(img_index.split('.')[0])) sub_imgs_tracking = [] for img_name_tracking in sub_imgs_names_tracking: sub_img_tracking = cv2.imread( os.path.join(intermediate_resutls_path_tracking, img_name_tracking)) sub_imgs_tracking.append(sub_img_tracking) # 读取 坐标转换部分 intermediate_resutls_path_detection = os.path.join( intermediate_resutls_path, 'detection') ReID_features_detection = np.load( os.path.join( intermediate_resutls_path_detection, '{}_ReID_features_detection.npy'.format(action_index))) ReID_features_detection = [_ for _ in ReID_features_detection ] # 转换为我们需要的格式 # 把这个文件夹下的图片名称读出来。 sub_imgs_names_detection = [ img_name_detection for img_name_detection in os.listdir( intermediate_resutls_path_detection) if img_name_detection.split('.')[-1] == 'jpg' ] # 把图片名字按升序排列 sub_imgs_names_detection = sorted( sub_imgs_names_detection, key=lambda img_index: int(img_index.split('.')[0])) sub_imgs_detection = [] for img_name_detection in sub_imgs_names_detection: sub_img_detection = cv2.imread( os.path.join(intermediate_resutls_path_detection, img_name_detection)) sub_imgs_detection.append(sub_img_detection) return action_index, sub_imgs_tracking, ReID_features_tracking, sub_imgs_detection, ReID_features_detection
class FMLoader: ''' 载入FairMot的短时序追踪结果 ''' def __init__(self, opt, tracker_opt, Tracker_output_queue, S_Short_track, S_Coordinate_transfer, track_len=2, vis=False, save_results=False, queueSize=1000, sp=False): self.logger = Log(__name__, 'FMLoader').getlog() self.opt = opt self.track_len = track_len # 相对于动作点,前后追踪 track_len 秒 self.dir_name = opt.dir_name self.root_path = os.path.join(opt.data_root, '{}'.format(opt.dir_name)) # 从缓存中读取已经计算出来的结果。 self.S_Short_track = S_Short_track #代表的是一个index, 在这个数之前追踪结果的都已经计算并保存了。 self.S_Coordinate_transfer = S_Coordinate_transfer #代表的是一个index, 在这个数之前转换结果的都已经计算并保存了。 # logger.info('目标文件夹是{}'.format(self.root_path)) self.file_name = opt.file_name # 本来就是要载入两次视频,分开读亦可以 self.Videoparameters, \ self.setting_parameter, \ self.action_datas, \ self.channel_list, \ self.parameter = read_data_from_json_file(self.root_path, self.file_name, self.opt) self.datalen = len(self.action_datas) self.logger.log( 21, '___________________一共有 {} 条数据_______________'.format( self.datalen)) # 是否要将图画出来,可视化给别人看 self.vis = vis if self.vis == True: self.vis_path = os.path.join(self.root_path, 'vis') os.makedirs(self.vis_path, exist_ok=True) self.save_results = save_results if self.save_results == True: self.intermediate_results_dir = os.path.join( self.root_path, 'intermediate_results', 'FMLoader') os.makedirs(self.intermediate_results_dir, exist_ok=True) self.tracker_opt = tracker_opt # 用来设置追踪器参数的。 self.IoUthreshold = 0.5 # self.logger.info('Creating model...') self.tracker_model = create_JDETracker_model(self.tracker_opt) # self.tracker = JDETracker(self.tracker_opt ) # What is JDE Tracker? # initialize the queue used to store frames read from # the video file self.PostProcess_Q = Queue(maxsize=queueSize) self.Output_Q = Tracker_output_queue def Read_From_Cache(self): ''' 从文件把之前计算过的结果提取出来 ''' from utils.index_operation import get_index self.logger.debug('The pid of FMLoader.Read_From_Cache() : {}'.format( os.getpid())) self.logger.debug( 'The thread of FMLoader.Read_From_Cache() : {}'.format( currentThread())) cache_index = get_index(self.intermediate_results_dir) # 只需读取有用的部分即可。 action_index = self.S_Coordinate_transfer for action_index in range(self.S_Coordinate_transfer, self.S_Short_track): if action_index not in cache_index: # cache 中没有保存说明 此动作本身是False self.Output_Q.put((False, action_index, [])) else: # 从文件夹中读取出该动作对应的计算结果。 _, [ frames_time, sub_imgs, ReID_feature_list, bottom_center_point_list ] = self.load_intermediate_resutls(action_index) self.Output_Q.put((True, action_index, [ frames_time, sub_imgs, ReID_feature_list, bottom_center_point_list ])) self.logger.log( 21, 'length of self.Output_Q = {}'.format(self.Output_Q.qsize())) self.logger.log( 21, ' FMLoader loads action {} from Cache file '.format(action_index)) # show_memory_info('===========Read_From_Cache==============') def update_(self): self.t_update = Thread(target=self.update, args=()) self.t_update.daemon = True self.t_update.start() return self def update(self): ''' ''' self.logger.debug('The pid of FMLoader.update_() : {}'.format( os.getpid())) self.logger.debug('The thread of FMLoader.update() : {}'.format( currentThread())) self.logger.log(21, 'self.datalen : {}'.format(self.datalen)) self.update_timer = Timer() # keep looping the whole dataset for index in range(self.S_Short_track, self.datalen): self.update_timer.tic() self.logger.debug('update <===========> action {} '.format(index)) # show_memory_info('action _ {}, {}'.format(index, ' S_Short_track begin')) # result_root = make_dir(self.root_path, index, Secondary_directory='{}_short_tracking'.format(self.dir_name)) '''read each item from subdata of action datas according to the index ''' channel, action_time, img_point, video_parameter = read_subdata( self.action_datas[index], self.Videoparameters) video = video_parameter['video'] # action time need to add the delta time to calibrate the time between channels . video_time = action_time + video_parameter['delta_t'] width = video.get(cv2.CAP_PROP_FRAME_WIDTH) height = video.get(cv2.CAP_PROP_FRAME_HEIGHT) Message = GenerateRect(img_point, self.setting_parameter['Output_size'], self.setting_parameter['bias'], width, height) if Message[0] == True: # 获取目标区域 rect = Message[1] x_l = int(rect[0]) y_l = int(rect[1]) x_r = int(rect[2] + rect[0]) y_r = int(rect[3] + rect[1]) rect = [x_l, y_l, x_r, y_r] # 目标点坐标相对于从原图中的位置,更新到相对于截图中的位置 reference_point = (int(img_point[0] - x_l), int(img_point[1] - y_l)) Left_Up_points = (rect[0], rect[1]) # 截图的右上角相对于原图的位置 # sub_img = img[y_l:y_r, x_l:x_r] else: # 如果没有截图则,则无需放入Queue中。 self.PostProcess_Q.put( (False, None, None, None, None, None, None)) continue # 没有必要逐帧检测。 # print('self.setting_parameter[\'Output_size\'], multiple=self.track_len', self.setting_parameter['Output_size'], self.track_len) self.logger.debug('Starting Building LoadShortCutVideo...') dataloader = LoadShortCutVideo( video, video_time, rect, self.setting_parameter['Output_size'], multiple=self.track_len) # show_memory_info('action _ {}, {}'.format(index, 'LoadShortCutVideo release ===========')) target_frame = dataloader.multiple * dataloader.frame_rate frame_rate = dataloader.frame_rate start_time = action_time - self.track_len # 调整到需要追踪的小视频,相对于开球的时间。 # 进行短时徐追踪 self.logger.debug('Starting tracking...') tracker = JDETracker(self.tracker_opt, self.tracker_model) # 创建一个追踪器 results = Short_track(tracker, dataloader, self.tracker_opt) # 删除tracker并立即会手内存 # del tracker # gc.collect() # 传入Queue中。 self.PostProcess_Q.put( (True, results, target_frame, start_time, frame_rate, Left_Up_points, reference_point)) # del results # show_memory_info('action _ {}, {}'.format(index, 'self.PostProcess_Q.put')) self.logger.log( 21, 'FMLoader.update() action {} consums {}s'.format( index, self.update_timer.toc())) def PostProcess_(self): self.t_PostProcess = Thread(target=self.PostProcess, args=()) self.t_PostProcess.daemon = True self.t_PostProcess.start() def PostProcess(self): ''' 数据结果后处理 ''' self.PostProcess_timer = Timer() self.logger.debug('The pid of FMLoader.PostProcess : {}'.format( os.getpid())) self.logger.debug('The thread of FMLoader.PostProcess : {}'.format( currentThread())) for action_index in range(self.S_Short_track, self.datalen): self.PostProcess_timer.tic() # show_memory_info('action _ {}, {}'.format(action_index, 'Before get ')) Flag, results, target_frame, start_time, frame_rate, Left_Up_points, reference_point = self.PostProcess_Q.get( ) self.logger.debug( 'PostProcess <===========> action {} '.format(action_index)) # 截图都没有。 if Flag == False: self.Output_Q.put((False, action_index, [])) continue # 把每个sub_box提取出来。 sub_imgs = [] ReID_feature_list = [] frames_time = [] bottom_center_point_list = [] for bias in [0, -1, 1, -2, 2]: # 总能检测到的? input_result = results[target_frame + bias] if len(input_result[1]) == 0: # 有可能目标帧没有检测到,一个目标都没有。 target_id = None continue new_reference_point, target_id = sort_by_point( results[target_frame + bias], reference_point, IoUthreshold=self.IoUthreshold) if target_id != None: # 检测到了的话,就跳出循环 # 将目标帧的图片放在了sub_imgs 和 ReID_feature_list 队列的首个 bboxes = input_result[1] ids = input_result[2] target_id_index = ids.index(target_id) box = bboxes[target_id_index] ReID_features = input_result[3] ReID_feature = ReID_features[target_id_index] img0 = input_result[4] I_h, I_w, _ = img0.shape x1, y1, w, h = box intbox = tuple( map(int, (max(0, x1), max(0, y1), min( x1 + w, I_w), min(y1 + h, I_h)))) sub_img = img0[intbox[1]:intbox[3], intbox[0]:intbox[2]] '''队列的首项是终极目标,用于校准,不用于后续的坐标转换计算''' frames_time.append(None) bottom_center_point_list.append(None) # sub_imgs 和 ReID_feature_list 在后续直接用于计算,因此不需要与 frames_time 保持长度上的一致 sub_imgs.append(sub_img) ReID_feature_list.append(ReID_feature) if self.vis == True: vis_dir_ = os.path.join(self.vis_path, '{}'.format(action_index), 'tracking') makedir_v1(vis_dir_) self.vis_target_frame(input_result, target_id, reference_point, new_reference_point, vis_dir_) break # 如果前中后三帧都没有检测到,那就说明这个动作区分不开了。 放弃了。 if target_id == None: # 目标不存在 self.Output_Q.put((False, action_index, [])) continue # 对所有结果进行筛选,选出和目标人物相同ID的。 for r_index, result in enumerate(results): frame_id = result[0] time = start_time + frame_id / frame_rate # 这帧画面对应的时间(相对于开球时间) bboxes = result[1] # ids = np.arryy(result[2]) ids = result[2] ReID_features = result[3] img0 = result[4] I_h, I_w, _ = img0.shape # 找出复合target id的那一个bbox。 每一帧最多存在一个复合要求的box # 有可能有几帧是不存在的。因此需要标注时间,或者相对帧数 if target_id not in ids: # 需要记录每个sub_imgs所对应的时间。 # 要保证时间连续,就算没有信号,也需要添加在其中, # 各个参数之间的长度需要保持一致 frames_time.append(time) bottom_center_point_list.append([]) continue else: id_index = ids.index(target_id) box = bboxes[id_index] ReID_feature = ReID_features[id_index] x1, y1, w, h = box intbox = tuple( map(int, (max(0, x1), max(0, y1), min( x1 + w, I_w), min(y1 + h, I_h)))) # print(intbox) sub_img = img0[intbox[1]:intbox[3], intbox[0]:intbox[2]] # 底部中心的坐标从相对于截图的位置,还原到相对于原图的位置。 bottom_center_point = (x1 + 0.5 * w + Left_Up_points[0], y1 + h + Left_Up_points[1]) # 需要记录每个bottom_center_point所对应的时间。 # frames_time 和 bottom_center_point 需要在长度上保持一致 frames_time.append(time) bottom_center_point_list.append(bottom_center_point) # sub_imgs 和 ReID_feature_list 在后续直接用于计算,因此不需要与 frames_time 保持长度上的一致 sub_imgs.append(sub_img) ReID_feature_list.append(ReID_feature) if self.vis == True: img_vis = np.copy(img0) cv2.rectangle(img_vis, (intbox[0], intbox[1]), (intbox[2], intbox[3]), (255, 255, 0), thickness=2) cv2.imwrite( os.path.join(vis_dir_, '{}.jpg'.format(r_index)), img_vis) # cv2.imwrite(os.path.join(vis_dir_,'{}.jpg'.format(r_index)),img_vis) self.Output_Q.put((True, action_index, [ frames_time, sub_imgs, ReID_feature_list, bottom_center_point_list ])) if self.save_results == True: self.save_intermediate_resutls(action_index, frames_time, sub_imgs, ReID_feature_list, bottom_center_point_list) self.logger.log( 21, 'FMLoader.PostProcess() action {} consums {}s'.format( action_index, self.PostProcess_timer.toc())) # show_memory_info('action _ {}, {}'.format(action_index, 'Before del results ')) # print('action index {} sys.getrefcount(results)'.format(action_index),sys.getrefcount(results)) # del results # show_memory_info('action _ {}, {}'.format(action_index, 'After del results ')) # self.logger.log(21, '-----------------------------Finished FMLoader.PostProcess() datalen = {}-----------------------------'.format(self.datalen)) def get__(self): for action_index in range(self.S_Short_track, self.datalen): results = self.Output_Q.get() self.logger.log(21, 'FMLoader.get__() action {} '.format(action_index)) def save_intermediate_resutls(self, action_index, frames_time, sub_imgs, ReID_feature_list, bottom_center_point_list): '''将每一次计算的结果保存下来。''' intermediate_resutls_path = os.path.join(self.intermediate_results_dir, '{}'.format(action_index)) os.makedirs(intermediate_resutls_path, exist_ok=True) # 保存 ReID ReID_feature_list = np.array(ReID_feature_list) np.save( os.path.join(intermediate_resutls_path, '{}_ReID_feature_list.npy'.format(action_index)), ReID_feature_list) # 保存图片 for img_index in range(len(sub_imgs)): cv2.imwrite( os.path.join(intermediate_resutls_path, '{}.jpg'.format(img_index)), sub_imgs[img_index]) # 保存 frames_time 和 bottom_center_point_list with open( os.path.join( intermediate_resutls_path, '{}_frames_time_and_bottom_center_point_list.json'.format( action_index)), 'w') as f: results = { 'frames_time': frames_time, 'bottom_center_point_list': bottom_center_point_list } json.dump(results, f) def load_intermediate_resutls(self, action_index): '''将中间结果读取出来。''' intermediate_resutls_path = os.path.join(self.intermediate_results_dir, '{}'.format(action_index)) ReID_feature_list = np.load( os.path.join(intermediate_resutls_path, '{}_ReID_feature_list.npy'.format(action_index))) ReID_feature_list = [_ for _ in ReID_feature_list] # 转换为我们需要的格式 # 把这个文件夹下的图片名称读出来。 sub_imgs_names = [ img_name for img_name in os.listdir(intermediate_resutls_path) if img_name.split('.')[-1] == 'jpg' ] # 把图片名字按升序排列 sub_imgs_names = sorted( sub_imgs_names, key=lambda img_index: int(img_index.split('.')[0])) sub_imgs = [] for img_name in sub_imgs_names: sub_img = cv2.imread( os.path.join(intermediate_resutls_path, img_name)) sub_imgs.append(sub_img) with open( os.path.join( intermediate_resutls_path, '{}_frames_time_and_bottom_center_point_list.json'.format( action_index)), 'r') as f: results = json.load(f) frames_time = results['frames_time'] bottom_center_point_list = results['bottom_center_point_list'] return action_index, [ frames_time, sub_imgs, ReID_feature_list, bottom_center_point_list ] def read(self): # return next frame in the queue return self.Output_Q.get() def len(self): # return queue len return self.Output_Q.qsize() def vis_target_frame(self, input_result, target_id, reference_point, new_reference_point, vis_dir_): ''' 将目标帧的效果画出来。 ''' bboxes = input_result[1] ids = input_result[2] img0 = input_result[4] img_vis = np.copy(img0) id_index = ids.index(target_id) box = bboxes[id_index] x1, y1, w, h = box I_h, I_w, _ = img0.shape intbox = tuple( map(int, (max(0, x1), max(0, y1), min(x1 + w, I_w), min(y1 + h, I_h)))) cv2.rectangle(img_vis, (intbox[0], intbox[1]), (intbox[2], intbox[3]), (255, 255, 0), thickness=2) # 追踪效果和转换后的点为黄色 cv2.circle(img_vis, (int(new_reference_point[0]), int(new_reference_point[1])), radius=5, color=(25, 255, 0), thickness=-1) cv2.circle(img_vis, (int(reference_point[0]), int(reference_point[1])), radius=5, color=(0, 255, 0), thickness=-1) # 原始点为红色 cv2.imwrite(os.path.join(vis_dir_, 'target_id.jpg'), img0)
class Alphapose(): def __init__(self,opt, pose_opt, ReIDCfg, C_T_output_queue,Pose_output_queue, S_Pose_Estimate, S_Number_Predict, vis=False,save_results=False, queueSize=1024): self.opt = opt self.dir_name = opt.dir_name self.root_path = os.path.join(opt.data_root, '{}'.format(opt.dir_name)) # logger.info('目标文件夹是{}'.format(self.root_path)) self.file_name = opt.file_name self.Videoparameters, \ self.setting_parameter, \ self.action_datas, \ self.channel_list, \ self.parameter = read_data_from_json_file_v2(self.root_path, self.file_name, self.opt) # 视频是否需要再次读入呢? 是否暂用资源 self.datalen = len(self.action_datas) # 加载 poser self.device = torch.device('cuda') self.batchSize = 4 self.ReID_BatchSize = 50 self.gpus = opt.gpus self.pose_model = build_poser(pose_opt,self.gpus) # 加载 ReID 模型 self.ReIDCfg = ReIDCfg self.ReID = ReID_Model(self.ReIDCfg) self.ReID.cuda() # ReID 模型参数 self.distance_threshold = 1 self.height_threshold = 95 self.width_threshold = 40 self._input_size = pose_opt.DATA_PRESET.IMAGE_SIZE self._output_size = pose_opt.DATA_PRESET.HEATMAP_SIZE self._sigma = pose_opt.DATA_PRESET.SIGMA self.aspect_ratio = 0.45 if pose_opt.DATA_PRESET.TYPE == 'simple': self.transformation = SimpleTransform( self, scale_factor=0, input_size=self._input_size, output_size=self._output_size, rot=0, sigma=self._sigma, train=False, add_dpg=False, gpu_device=self.device) self.input_Q = C_T_output_queue # 追踪数据的整体输入 self.Posing_Q = Queue(maxsize=queueSize) #在骨骼关键点检测前,对左边转换后的截图进行预处理 self.PostProcess_Q = Queue(maxsize=queueSize) # 在骨骼关键点检测前,对左边转换后的截图进行预处理 self.output_Q = Pose_output_queue self.vis = vis if self.vis == True: self.vis_path = os.path.join(self.root_path, 'vis') os.makedirs(self.vis_path, exist_ok=True) self.save_results = save_results self.S_Pose_Estimate = S_Pose_Estimate self.S_Number_Predict = S_Number_Predict if self.save_results == True: self.intermediate_results_dir = os.path.join(self.root_path, 'intermediate_results','Alphapose') os.makedirs(self.intermediate_results_dir, exist_ok=True) self.logger = Log(__name__, 'Alphapose' ).getlog() def Read_From_Cache(self): ''' 从文件把之前计算过的结果提取出来 ''' from utils.index_operation import get_index self.logger.debug('The pid of Alphapose.Read_From_Cache() : {}'.format(os.getpid())) self.logger.debug('The thread of Alphapose.Read_From_Cache() : {}'.format(currentThread())) cache_index = get_index(self.intermediate_results_dir) # 只需读取有用的部分即可。 action_index = self.S_Number_Predict for action_index in range(self.S_Number_Predict,self.S_Pose_Estimate): if action_index not in cache_index: # cache 中没有保存说明 此动作本身是False self.output_Q.put((False, [action_index])) else: # 从文件夹中读取出该动作对应的计算结果。 _, sub_imgs_out, target_regions = self.load_intermediate_resutls(action_index) self.output_Q.put((True, [action_index,sub_imgs_out,target_regions])) self.logger.log(23, ' Alphapose loads action {} from Cache file '.format(action_index)) def posing_preprocess_(self): self.t_posing_preprocess = Thread(target=self.posing_preprocess, args=()) self.t_posing_preprocess.daemon = True self.t_posing_preprocess.start() def posing_preprocess(self): # 预处理 self.logger.debug('The pid of Alphapose.posing_preprocess() : {}'.format(os.getpid())) self.logger.debug('The thread of Alphapose.posing_preprocess() : {}'.format(currentThread())) posing_preprocess_timer = Timer() for action_index in range(self.S_Pose_Estimate, self.datalen): self.logger.debug('alphapose.posing_preprocess() ======================================== action {}'.format(action_index)) Flag_PreProcess, (input_index, sub_imgs_tracking, ReID_features_tracking,sub_imgs_detection,ReID_features_detection) = self.input_Q.get() if input_index != action_index: self.logger.log(31, '---——————————————————————————————————index does match') raise Exception('Alphapose.update action_index_update {} != input_index {} '.format(action_index, input_index)) if Flag_PreProcess == False: self.Posing_Q.put((False,[])) continue else: # 开始计时 posing_preprocess_timer.tic() inps = [] cropped_boxes = [] # 通过 ReID 特征剔除一部分。 sub_imgs = self.imgs_sorted_by_ReID(sub_imgs_tracking,sub_imgs_detection,action_index) if len(sub_imgs) == 0 : # 被筛选后的图片序列为0,则跳过。 self.Posing_Q.put((False, [])) continue for imgs_index in range(len(sub_imgs)): orig_img = sub_imgs[imgs_index] height, width, _ = orig_img.shape box = [0, 0, width - 1, height - 1] inp, cropped_box = self.transformation.test_transform(orig_img, box) inps.append(inp) cropped_boxes.append(cropped_box) inps_ = torch.stack(inps,dim=0) self.Posing_Q.put((True,(sub_imgs,inps_,cropped_boxes))) self.logger.log(23, 'alphapose.posing_preprocess() action {} consums {}s'.format(action_index, posing_preprocess_timer.toc())) def posing_detect_(self): self.t_posing_detect = Thread(target=self.posing_detect, args=()) self.t_posing_detect.daemon = True self.t_posing_detect.start() def posing_detect(self): posing_detect_timer = Timer() for action_index in range(self.S_Pose_Estimate, self.datalen): self.logger.debug('posing_detect ------------action {} has been read '.format(action_index)) Flag_Posing_detect, preprocess_results = self.Posing_Q.get() if Flag_Posing_detect == False: self.PostProcess_Q.put((False,[])) continue else: posing_detect_timer.tic() sub_imgs, inps_ , cropped_boxes = preprocess_results inps = inps_.to(self.device) inps_len = inps_.size(0) leftover = 0 if (inps_len) % self.batchSize: leftover = 1 num_batches = inps_len // self.batchSize + leftover keypoints_all = [] for j in range(num_batches): inps_j = inps[j * self.batchSize : min((j + 1) * self.batchSize, inps_len)] sub_cropped_boxes = cropped_boxes[j * self.batchSize : min((j + 1) * self.batchSize, inps_len)] # self.logger.log(23, ' j : {}, inps_j.size() '.format(j, inps_j.size())) hm_j = self.pose_model(inps_j) keypoints_several = self.heats_to_maps(hm_j, sub_cropped_boxes) keypoints_all.extend(keypoints_several) self.PostProcess_Q.put((True,(keypoints_all,sub_imgs))) self.logger.log(23, 'alphapose.posing_detect() action {} consums {}s'.format(action_index, posing_detect_timer.toc())) def posing_postprocess_(self): self.t_posing_postprocess = Thread(target=self.posing_postprocess, args=()) self.t_posing_postprocess.daemon = True self.t_posing_postprocess.start() def posing_postprocess(self): '''对骨骼关键节点的检测结果坐后处理,并通过 简单规则对结果进行以此初步筛选。''' pposing_postprocess_timer = Timer() for action_index in range(self.S_Pose_Estimate, self.datalen): self.logger.debug('posing_postprocess ------------action {} has been read '.format(action_index)) Flag_posing_postprocess, posing_detect_resutls = self.PostProcess_Q.get() if Flag_posing_postprocess == False: self.output_Q.put((False,[action_index])) continue else: pposing_postprocess_timer.tic() keypoints_all,sub_imgs = posing_detect_resutls target_regions = [] sub_imgs_out = [] if self.vis == True: vis_dir_positive = os.path.join(self.vis_path, '{}'.format(action_index), 'Alphapose_positive') makedir_v1(vis_dir_positive) vis_dir_negative = os.path.join(self.vis_path, '{}'.format(action_index), 'Alphapose_negative') makedir_v1(vis_dir_negative) Negative_num = 0 vis_dir_small_size = os.path.join(self.vis_path, '{}'.format(action_index), 'Alphapose_small_size') makedir_v1(vis_dir_small_size) small_size_num = 0 vis_dir_small_target = os.path.join(self.vis_path, '{}'.format(action_index), 'Alphapose_small_target') makedir_v1(vis_dir_small_target) small_target_num = 0 Positive_num = 0 for k_index in range(len(keypoints_all)): # 对每一张关节点图做逐一处理 origin_img = sub_imgs[k_index] height, width, _ = origin_img.shape if height < self.height_threshold or width < self.width_threshold: small_size_num += 1 if self.vis == True: img_name = '{}.jpg'.format(k_index) cv2.imwrite(os.path.join(vis_dir_small_size, img_name), origin_img) continue keypoints = keypoints_all[k_index] # 这个判断标准和get_box的标准不一样。 # 用来判断是否背向的 l_x_max = max(keypoints[5 * 3], keypoints[11 * 3]) r_x_min = min(keypoints[6 * 3], keypoints[12 * 3]) t_y_max = max(keypoints[5 * 3 + 1], keypoints[6 * 3 + 1]) b_y_min = min(keypoints[11 * 3 + 1], keypoints[12 * 3 + 1]) if l_x_max < r_x_min and t_y_max < b_y_min: '初步判断球员是否背向' [xmin_old, xmax_old], [xmin, xmax, ymin, ymax] = self.get_box(keypoints, height, width, ratio=0.1, expand_w_min=10) # 计算上半身体长度 body_length = ymax - ymin if body_length < 20: # 130 和 60 应该来自 opt small_target_num += 1 if self.vis == True: img_name = '{}.jpg'.format(k_index) cv2.imwrite(os.path.join(vis_dir_small_target, img_name), origin_img) continue # 计算肩宽、胯宽 Shoulder_width = keypoints[6 * 3] - keypoints[5 * 3] Crotch_width = keypoints[12 * 3] - keypoints[11 * 3] aspect_ratio = (max(Shoulder_width, Crotch_width)) / (body_length) # 计算比例 if aspect_ratio >= self.aspect_ratio: # 如果这个比例合适,则送入号码检测 sub_imgs_out.append(origin_img) target_regions.append([xmin, xmax, ymin, ymax]) Positive_num += 1 # 复合条件的 +1 if self.vis == True: img_name = '{}.jpg'.format(k_index) vis_img = np.copy(origin_img) cv2.rectangle(vis_img, (xmin_old, ymin), (xmax_old, ymax), color=(255, 0, 0), thickness=1) cv2.rectangle(vis_img, (xmin, ymin), (xmax, ymax), color=(0, 255, 0), thickness=1) cv2.imwrite(os.path.join(vis_dir_positive, img_name), vis_img) else: Negative_num += 1 if self.vis == True: img_name = '{}.jpg'.format(k_index) cv2.imwrite(os.path.join(vis_dir_negative, img_name), origin_img) self.output_Q.put((True, [action_index, sub_imgs_out,target_regions ])) # 保存中间结果 if self.save_results == True: self.save_intermediate_resutls(action_index,sub_imgs_out,target_regions) # # 输出 日志 # self.logger.log(23,'Positive_num {}, Negative_num {}, small_target_num {}, small_size_num {}, all {}'.format( # Positive_num, # Negative_num, # small_target_num, # small_size_num, # len(keypoints_all))) self.logger.log(23, 'alphapose.posing_postprocess() action {} consums {}s Positive_num / All = {}/{}'.format( action_index, pposing_postprocess_timer.toc(), Positive_num, len(keypoints_all))) def save_intermediate_resutls(self,action_index,sub_imgs_out,target_regions): '''将每一次计算的结果保存下来。''' intermediate_resutls_path = os.path.join(self.intermediate_results_dir,'{}'.format(action_index)) os.makedirs(intermediate_resutls_path,exist_ok=True) # 保存图片 for img_index in range(len(sub_imgs_out)): cv2.imwrite(os.path.join(intermediate_resutls_path,'{}.jpg'.format(img_index)),sub_imgs_out[img_index]) # 保存 target_regions with open(os.path.join(intermediate_resutls_path,'{}_target_regions.json'.format(action_index)),'w') as f: results = {'target_regions' : target_regions} json.dump(results,f) def load_intermediate_resutls(self,action_index): '''将中间结果读取出来。''' intermediate_resutls_path = os.path.join(self.intermediate_results_dir,'{}'.format(action_index)) # 把这个文件夹下的图片名称读出来。 sub_imgs_names = [ img_name for img_name in os.listdir(intermediate_resutls_path) if img_name.split('.')[-1] == 'jpg' ] # 把图片名字按升序排列 sub_imgs_names = sorted(sub_imgs_names, key=lambda img_index : int(img_index.split('.')[0])) sub_imgs_out = [] for img_name in sub_imgs_names: sub_img = cv2.imread(os.path.join(intermediate_resutls_path,img_name)) sub_imgs_out.append(sub_img) # 保存 target_regions with open(os.path.join(intermediate_resutls_path, '{}_target_regions.json'.format(action_index)), 'r') as f: results = json.load(f) target_regions = results['target_regions'] return action_index,sub_imgs_out,target_regions def heats_to_maps(self,hm_data,cropped_boxes): # 将 heatmap 转化成 keypoints 数组 pred = hm_data.cpu().data.numpy() assert pred.ndim == 4 keypoints_all = [] for hms_index in range(hm_data.size(0)): pose_coord, pose_score = heatmap_to_coord_simple(pred[hms_index], cropped_boxes[hms_index]) keypoints_single = [] for n in range(pose_score.shape[0]): keypoints_single.append(float(pose_coord[n, 0])) keypoints_single.append(float(pose_coord[n, 1])) keypoints_single.append(float(pose_score[n])) keypoints_all.append(keypoints_single) return keypoints_all def get_box(self, keypoints, img_height, img_width, ratio=0.1, expand_w_min=10): '''这个get box 是用来获取球员的背部区域的''' xmin = min(keypoints[5 * 3], keypoints[11 * 3]) xmax = max(keypoints[6 * 3], keypoints[12 * 3]) ymin = min(keypoints[5 * 3 + 1], keypoints[6 * 3 + 1]) ymax = max(keypoints[11 * 3 + 1], keypoints[12 * 3 + 1]) return [int(round(xmin)), int(round(xmax))], self.expand_bbox(xmin, xmax, ymin, ymax, img_width, img_height, ratio, expand_w_min) def expand_bbox(self, left, right, top, bottom, img_width, img_height,ratio = 0.1, expand_w_min = 10): ''' 以一定的ratio向左右外扩。 不向上向下扩展了。 ''' width = right - left height = bottom - top # expand ratio expand_w_min = max(ratio * width , expand_w_min) # 最小外扩 expand_w_min new_left = np.clip(left - expand_w_min, 0, img_width) new_right = np.clip(right + expand_w_min, 0, img_width) return [int(new_left), int(new_right), int(top), int(bottom)] def imgs_sorted_by_ReID(self,imgs_tracking,imgs_detection,action_index): '''通过ReID模型来筛选与目标特征相符的图片''' sub_imgs = [] # 把追踪序列和目标人物进行对比,剔除后得到追踪序列的平均ReID特征值 if len(imgs_tracking) == 0: # 如果追踪序列长度为0的话,那就没什么好处理的了,直接返回 空 就行。 return sub_imgs else: imgs_tracking_index, distmat_tracking, output_feature = imgs_sorted_by_ReID(self.ReID, self.ReIDCfg, imgs_tracking, distance_threshold=self.distance_threshold, feat_norm='yes', version=0, batch_size=self.ReID_BatchSize) for P_index in imgs_tracking_index: sub_imgs.append(imgs_tracking[P_index]) if len(imgs_detection) > 0: # 把追踪序列的平均ReID特征值和坐标转换序列对比,进行第二次筛选 imgs_detection_index, distmat_detection, _ = imgs_sorted_by_ReID(self.ReID, self.ReIDCfg, imgs_detection, distance_threshold=self.distance_threshold, feat_norm='yes', version=2, input_features=output_feature, batch_size=self.ReID_BatchSize) for P_index_detection in imgs_detection_index: sub_imgs.append(imgs_detection[P_index_detection]) if self.vis ==True: # 将追踪序列的sub_imgs 按ReID的分类结果保存 Positive_dir = os.path.join(self.vis_path, '{}/ReID'.format(action_index)) makedir_v1(Positive_dir) Negative_dir = os.path.join(self.vis_path, '{}/ReID/Negative'.format(action_index)) for P_index, _ in enumerate(imgs_tracking): distance = distmat_tracking[0, P_index] if P_index in imgs_tracking_index: cv2.imwrite(os.path.join(Positive_dir, '{}_{:3f}.jpg'.format(P_index, distance)), imgs_tracking[P_index]) else: cv2.imwrite(os.path.join(Negative_dir, '{}_{:3f}.jpg'.format(P_index, distance)), imgs_tracking[P_index]) # 将坐标转换后序列的sub_imgs 按ReID的分类结果保存 Positive_dir_detection = os.path.join(self.vis_path, '{}/ReID/detection'.format(action_index)) makedir_v1(Positive_dir_detection) Negative_dir_detection = os.path.join(self.vis_path, '{}/ReID/detection/Negative'.format(action_index)) makedir_v1(Negative_dir_detection) for P_index_detection, _ in enumerate(imgs_detection): distance = distmat_detection[0, P_index_detection] if P_index_detection in imgs_detection_index: cv2.imwrite(os.path.join(Positive_dir_detection, '{}_{:3f}.jpg'.format(P_index_detection, distance)), imgs_detection[P_index_detection]) else: cv2.imwrite(os.path.join(Negative_dir_detection, '{}_{:3f}.jpg'.format(P_index_detection, distance)), imgs_detection[P_index_detection]) return sub_imgs @property def joint_pairs(self): """Joint pairs which defines the pairs of joint to be swapped when the image is flipped horizontally.""" return [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12], [13, 14], [15, 16]]