Ejemplo n.º 1
0
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")()
Ejemplo n.º 3
0
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)
Ejemplo n.º 4
0
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)()
Ejemplo n.º 5
0
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']))
Ejemplo n.º 6
0
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()))
Ejemplo n.º 7
0
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))
Ejemplo n.º 8
0
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]
Ejemplo n.º 9
0
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)
Ejemplo n.º 10
0
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
Ejemplo n.º 11
0
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)
Ejemplo n.º 12
0
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]]