def parse_args(): """ 处理脚本参数,支持相对路径 img_file 文件路径,默认文件夹:img_downloader/urls out_folder 输出文件夹,默认文件夹:img_data :return: arg_img,文件路径;out_folder,输出文件夹 """ parser = argparse.ArgumentParser(description='下载数据脚本') parser.add_argument('--img_file', required=True, help='文件路径', type=str) parser.add_argument('--out_folder', help='输出文件夹', type=str) args = parser.parse_args() arg_img = args.img_file if len(arg_img.split('/')) == 1: arg_img = os.path.join(ROOT_DIR, 'img_downloader', 'urls', arg_img) print_info("文件路径:%s" % arg_img) arg_out = args.out_folder if not arg_out: file_name = arg_img.split('/')[-1] arg_out = os.path.join(ROOT_DIR, 'img_data', file_name) elif len(arg_out.split('/')) == 1: arg_out = os.path.join(ROOT_DIR, 'img_data', arg_out) print_info("输出文件夹:%s" % arg_out) return arg_img, arg_out
def format_img_and_anno(img_folder): """ 格式化输出。图片和标注文件夹 :param img_folder: 图片文件夹 :return: """ file_paths, file_names = traverse_dir_files(img_folder) img_dict = dict() # 将标注和图片路径,生成一个字典 for file_path, file_name in zip(file_paths, file_names): if file_name.endswith('.jpg'): name = file_name.replace('.jpg', '') if name not in img_dict: img_dict[name] = (None, None) (img_p, anno_p) = img_dict[name] img_dict[name] = (file_path, anno_p) if file_name.endswith('.xml'): name = file_name.replace('.xml', '') if name not in img_dict: img_dict[name] = (None, None) (img_p, anno_p) = img_dict[name] img_dict[name] = (img_p, file_path) print_info('图片数: {}'.format(len(img_dict.keys()))) return img_dict
def detect_img(self, yolo, img_path, anno_path, out_folder=None): """ 检测图片,与标注对比 :param yolo: YOLO :param img_path: 图片路径 :param anno_path: 标注路径 :param out_folder: 存储错误图像 :return: """ img_data = Image.open(img_path) boxes, scores, classes = yolo.__detect_img_facets(img_data) boxes = self.reform_boxes(boxes) print_info('检测: {}'.format(boxes)) anno_boxes, name_list = read_anno_xml(anno_path) anno_boxes = self.reform_boxes2(anno_boxes) print_info('真值: {}'.format(anno_boxes)) precision, recall = self.iou_of_boxes(boxes, anno_boxes) if True or out_folder and (precision != 1.0 or recall != 1.0): img_data = yolo.draw_boxes(img_data, boxes, scores, classes, [(255, 0, 0)]) img_data = yolo.draw_boxes(img_data, anno_boxes, [1.0 for i in range(len(anno_boxes))], [0 for i in range(len(anno_boxes))], [(128, 128, 255)]) # 图片的缩略图 # size = 1024, 1024 # img_data.thumbnail(size, Image.ANTIALIAS) img_name = img_path.split('/')[-1] out_img = os.path.join(out_folder, img_name + '.d.png') img_data.save(out_img) # 存储 # img_data.show() # 显示 return img_path, precision, recall
def detect_img_folder(img_folder, out_folder, yolo): mkdir_if_not_exist(out_folder) path_list, name_list = traverse_dir_files(img_folder) print_info('图片数: %s' % len(path_list)) _, imgs_names = traverse_dir_files(out_folder) count = 0 for path, name in zip(path_list, name_list): if path.endswith('.gif'): continue out_name = name + '.d.jpg' if out_name in imgs_names: print_info('已检测: %s' % name) continue print_info('检测图片: %s' % name) try: image = Image.open(path) out_file = os.path.join(ROOT_DIR, 'face', 'yolov3', 'output_data', 'logAll_res.txt') r_image = yolo.detect_image(image, ('logAll/' + name), out_file) r_image.save(os.path.join(out_folder, name + '.d.jpg')) except Exception as e: print(e) pass count += 1 if count % 100 == 0: print_info('已检测: %s' % count) yolo.close_session()
def __init__(self, model_path='model_data/ep074-loss26.535-val_loss27.370.h5', classes_path='configs/wider_classes.txt', anchors_path='configs/yolo_anchors.txt'): self.model_path = model_path # 模型文件 self.classes_path = classes_path # 类别文件 self.anchors_path = anchors_path # anchors文件 print_info('模型: {}'.format(model_path)) self.score = 0.25 self.iou = 0.30 print_info('置信度: {}, IoU: {}'.format(self.score, self.iou)) # 输出参数 self.class_names = self._get_class() # 获取类别 self.anchors = self._get_anchors() # 获取anchor self.sess = K.get_session() print_info('anchors: {}, 类别: {}'.format(len(self.anchors), len(self.class_names))) self.model_image_size = (416, 416) # fixed size or (None, None), hw print_info('图片尺寸: {}'.format(self.model_image_size)) # 输出参数 self.yolo_model = None self.colors = None self.input_image_shape = None self.boxes, self.scores, self.classes = self.generate()
def iou_of_boxes(boxes1, boxes2): """ 框的IOU :param boxes1_: 真值 :param boxes2_: 预测 :return: 精准和召回 """ res_list = [] boxes1_ = copy.deepcopy(boxes1) boxes2_ = copy.deepcopy(boxes2) t1, t2 = len(boxes1_), len(boxes2_) for box1 in boxes1_: final_iou = 0 final_box = None for box2 in boxes2_: iou = bb_intersection_over_union(box1, box2) if iou > final_iou: final_iou = iou final_box = box2 if final_iou > 0.5: res_list.append((box1, final_box, final_iou)) boxes2_.remove(final_box) tr = len(res_list) if tr == 0: # 没有检测源, 则认为正确 if t1 == 0 and t2 != 0: recall, precision = 1.0, 0.0 elif t1 != 0 and t2 == 0: recall, precision = 0.0, 1.0 elif t1 != 0 and t2 != 0: recall, precision = 0.0, 0.0 else: recall, precision = 1.0, 1.0 else: recall = safe_div(tr, t1) # 召回率 precision = safe_div(tr, t2) # 精准率 print_info('精准: {:.4f}, 召回: {:.4f}, 匹配结果: {}'.format( precision, recall, res_list)) return [precision, recall]
def load_model(self): net = DarkNet(input_dim=self.input_dim, num_classes=self.num_classes) # 基础网络DarkNet net.initialize(ctx=self.ctx) if self.params_path.endswith(".params"): # 加载模型 net.load_params(self.params_path) elif self.params_path.endswith(".weights"): tmp_batch = nd.uniform(shape=(1, 3, self.input_dim, self.input_dim), ctx=self.ctx) net(tmp_batch) net.load_weights(self.params_path, fine_tune=False) else: print("params {} load error!".format(self.params_path)) exit() print_info("加载参数: {}".format(self.params_path)) net.hybridize() return net
def download_imgs_for_mp(img_file, out_folder, prefix=None, n_prc=10): """ 多线程下载 :param img_file: 图片文件 :param out_folder: 输出文件夹 :param prefix: 图片前缀 :param n_prc: 进程数, 默认40个 :return: None """ print_info('进程总数: %s' % n_prc) pool = Pool(processes=n_prc) # 多线程下载 paths_list = read_file(img_file) print_info('文件数: %s' % len(paths_list)) _, imgs_names = traverse_dir_files(out_folder) for (index, path) in enumerate(paths_list): if prefix: pool.apply_async(download_img, (path, out_folder, imgs_names, prefix + '_' + str(index) + '.jpg')) else: pool.apply_async(download_img, (path, out_folder, imgs_names)) pool.close() pool.join() # _, imgs_names = traverse_dir_files(out_folder) # print_info('图片总数: %s' % len(imgs_names)) print_info('全部下载完成')
def verify_model(self): """ 处理标记文件夹 :param img_folder: 图片文件夹 :param out_folder: :return: """ yolo = YoloV3(model_path=self.model_path, classes_path=self.classes_path, anchors_path=self.anchors_path) # yolo算法类 img_dict = format_img_and_anno(self.img_folder) res_dict = dict() for count, img_name in enumerate(img_dict): print_info('-' * 50) print_info('图片: {}'.format(img_name)) (img_p, anno_p) = img_dict[img_name] _, precision, recall = self.detect_img(yolo, img_p, anno_p, self.out_folder) res_dict[img_name] = (precision, recall) if count == 10: break ap, ar = 0, 0 for name in res_dict.keys(): precision, recall = res_dict[name] ap += precision ar += recall mAp = safe_div(ap, len(res_dict.keys())) mAr = safe_div(ar, len(res_dict.keys())) print_info('平均精准率: {:.4f} %, 平均召回率: {:.4f} %'.format( mAp * 100, mAr * 100))
def __load_model(self): """ 加载网络模型 :return: 网络 """ net = DarkNet(input_dim=self.input_dim, num_classes=self.num_classes) # 基础网络 DarkNet net.initialize(ctx=self.ctx) # 网络环境 cpu or gpu print_info("模型: {}".format(self.params_path)) if self.params_path.endswith(".params"): # 加载参数 net.load_params(self.params_path) elif self.params_path.endswith(".weights"): # 加载模型 tmp_batch = nd.uniform(shape=(1, 3, self.input_dim, self.input_dim), ctx=self.ctx) net(tmp_batch) net.load_weights(self.params_path, fine_tune=False) else: raise Exception('模型错误') # 抛出异常 net.hybridize() # 编译和优化网络 return net
def download_img(img_url, out_folder, imgs_names, img_name=None): """ 下载图片 :param img_url: 图片URL :param out_folder: 输出文件夹 :param imgs_names: 已有图片 :param img_name: 图片名称 :return: None """ if not img_name: img_name = img_url.split('/')[-1] # 图片文件名 if img_name in imgs_names: print_info('图片已存在: %s' % img_name) return img_data = requests.get(img_url).content out_file = os.path.join(out_folder, img_name) # 输出文件 with open(out_file, 'wb') as hl: hl.write(img_data) print_info('图片已下载: %s' % img_name)
def download_imgs(img_file, out_folder, prefix=None): """ 下载图片集合 :param img_file: 图片文件 :param out_folder: 文件夹 :param prefix: 文件前缀 :return: None """ paths_list = read_file(img_file) print_info('图片总数: %s' % len(paths_list)) _, imgs_names = traverse_dir_files(out_folder) count = 0 for (index, path) in enumerate(paths_list): if prefix: download_img(path, out_folder, imgs_names, prefix + '_' + str(index) + '.jpg') else: download_img(path, out_folder, imgs_names) count += 1 if count % 200 == 0: print_info('已下载: %s' % count)
def iou_of_boxes(boxes1, boxes2): res_list = [] for box1 in boxes1: final_iou = 0 final_box = None for box2 in boxes2: iou = bb_intersection_over_union(box1, box2) if iou > final_iou: final_iou = iou final_box = box2 if final_iou > 0.5: res_list.append((box1, final_box, final_iou)) t1, t2, tr = len(boxes1), len(boxes2), len(res_list) if tr == 0: # 没有检测源, 则认为正确 return [1.0, 1.0] recall = safe_div(tr, t1) # 召回率 precision = safe_div(tr, t2) # 精准率 print_info('精准: {:.4f}, 召回: {:.4f}, 匹配结果: {}'.format( precision, recall, res_list)) return [precision, recall]
def detect_image_facets(self, image): """ 检测图片的数据细节,检测框、置信度、类别 :param image: PIL图片 :return: 检测框、置信度、类别 """ start_t = timer() # 起始时间 print_info('{}检测开始{}'.format('-' * 10, '-' * 10)) if self.model_image_size != ( None, None): # 416x416, 416=32*13,必须为32的倍数,最小尺度是除以32 assert self.model_image_size[ 0] % 32 == 0, 'Multiples of 32 required' assert self.model_image_size[ 1] % 32 == 0, 'Multiples of 32 required' boxed_image = letterbox_image(image, tuple(reversed( self.model_image_size))) # 填充图像 else: new_image_size = (image.width - (image.width % 32), image.height - (image.height % 32)) boxed_image = letterbox_image(image, new_image_size) # 强制转换为32的倍数 image_data = np.array(boxed_image, dtype='float32') # 图片数据 image_data /= 255. # 转换0~1 image_data = np.expand_dims(image_data, 0) # 添加批次维度,将图片增加1维 # 参数盒子、得分、类别;输入图像0~1,4维;原始图像的尺寸 out_boxes, out_scores, out_classes = self.sess.run( [self.boxes, self.scores, self.classes], feed_dict={ self.yolo_model.input: image_data, # 输入检测图片 self.input_image_shape: [image.size[1], image.size[0]], # 输入检测尺寸 K.learning_phase(): 0 # 学习率, 0表示测试, 1表示训练 }) print_info('检测时间: {:.4f} 秒'.format(timer() - start_t)) # 检测执行时间 print_info('检测物体数: {} 个'.format(len(out_boxes))) # 检测结果 print_info('{}检测结束{}'.format('-' * 10, '-' * 10)) return out_boxes, out_scores, out_classes
def verify_model(self): """ 处理标记文件夹 :param img_folder: 图片文件夹 :param out_folder: :return: """ img_dict = format_img_and_anno(self.img_folder) res_list = [] for count, img_name in enumerate(img_dict): print_info('-' * 50) print_info('图片: {}'.format(img_name)) (img_p, anno_p) = img_dict[img_name] try: res_dict = self.detect_img(img_p, anno_p, self.out_folder) except Exception as e: print_ex('检测异常: {}'.format(e)) continue res_list.append(res_dict) # if count == 10: # break print_info('-' * 50) for target_name in (['all'] + self.targets_name): if target_name in ['truck', 'bus']: continue ap, ar, count = 0, 0, 0 for pr_dict in res_list: if target_name in pr_dict: tp, tr = pr_dict[target_name] ap += tp ar += tr count += 1 mAp = safe_div(ap, count) mAr = safe_div(ar, count) print_info('类: {} P: {:.4f} %, R: {:.4f} %'.format( target_name, mAp * 100, mAr * 100))
def process_anno_folder(img_folder, out_folder): img_dict = format_img_and_anno(img_folder) _, file_names = traverse_dir_files(out_folder) for count, img_name in enumerate(img_dict.keys()): print_info('-' * 50) (img_p, anno_p) = img_dict[img_name] if not img_p or not anno_p: print_info('图片: {} 异常'.format(img_name)) continue if img_name in file_names: print_info('图片: {} 已存在'.format(img_name)) else: print_info('图片: {}'.format(img_name)) image_data = Image.open(img_p) boxes_list, name_list = read_anno_xml(anno_p) prob_list = [1.0 for x in range(len(boxes_list))] img_boxes = draw_boxes_simple(image_data, boxes_list, prob_list, name_list) img_boxes.save(os.path.join(out_folder, img_name + '.d.jpg'))
def main(): ym = Y3Model() img_folder = os.path.join(IMG_DATA, 'jiaotong-0727') right_folder = os.path.join(IMG_DATA, 'jiaotong-0727-right') wrong_folder = os.path.join(IMG_DATA, 'jiaotong-0727-wrong') none_folder = os.path.join(IMG_DATA, 'jiaotong-0727-none') mkdir_if_not_exist(right_folder, is_delete=True) mkdir_if_not_exist(wrong_folder, is_delete=True) mkdir_if_not_exist(none_folder, is_delete=True) img_dict = format_img_and_anno(img_folder) r_count = 0 all_count = 0 no_recall_count = 0 for count, img_name in enumerate(img_dict): (img_p, anno_p) = img_dict[img_name] # print(img_p) try: tag_res, img_box = ym.detect_img(img_p, True) except Exception as e: continue w_tags = [] for tag in tag_res.keys(): if tag_res[tag] <= 0.01: print_info('删除Tag {} {}'.format(tag, tag_res[tag])) w_tags.append(tag) for tag in w_tags: tag_res.pop(tag, None) # 小于1%的类别 all_count += 1 p_classes = set(tag_res.keys()) _, t_classes = read_anno_xml(anno_p) merge_dict = {'truck': 'car', 'bus': 'car', 'car': 'car'} # 合并类别 t_classes = map_classes(merge_dict, t_classes) # 合并类别 traffic_names = [ 'bicycle', 'car', 'motorbike', 'aeroplane', 'bus', 'train', 'truck', 'boat' ] t_classes = set(t_classes) & set(traffic_names) img_name = img_p.split('/')[-1] is_right = False if p_classes and p_classes.issubset(t_classes): # 检测正确 r_count += 1 img_box.save(os.path.join(right_folder, img_name + '.d.jpg')) is_right = True elif not p_classes and not t_classes: # 空,检测正确 r_count += 1 if not img_box: img_box = Image.open(img_p) img_box.save(os.path.join(right_folder, img_name + '.d.jpg')) is_right = True elif not p_classes and t_classes: # 检测为空,实际有类 if not img_box: img_box = Image.open(img_p) img_box.save(os.path.join(none_folder, img_name + '.d.jpg')) no_recall_count += 1 # 未召回 r_count += 1 is_right = True else: # 其他,检测错误 if not img_box: img_box = Image.open(img_p) img_box.save(os.path.join(wrong_folder, img_name + '.d.jpg')) print_info('P: {}, T: {}, {}'.format(list(p_classes), list(t_classes), '正确' if is_right else '错误')) right_ratio = safe_div(r_count, all_count) print_info('正确: {}, 全部: {}, 未召回: {}, 准确率: {}'.format( r_count, all_count, no_recall_count, right_ratio))
def detect_img(self, img_path, xml_path, out_folder=None): color_list_1 = make_line_colors(n_color=20, alpha=0.6, bias=1.0) color_list_2 = make_line_colors(n_color=20, alpha=1.0, bias=0.8) car_list = ['truck', 'bus', 'car'] # img_path = os.path.join(IMG_DATA, 'jiaotong-0727', '6emekgFq0neQv8ELXmCq5aQnL3Zz.jpg') # xml_path = os.path.join(IMG_DATA, 'jiaotong-0727', '6emekgFq0neQv8ELXmCq5aQnL3Zz.xml') img_data = Image.open(img_path) boxes, scores, classes_no = self.detect_image_facets(img_path) # 检测图片 boxes = self.reform_boxes(boxes) classes = [self.classes_name[int(i)] for i in classes_no] # 将classes的no转换为name boxes, scores, classes = filter_sbox( (img_data.size[0], img_data.size[1]), (boxes, scores, classes)) boxes, scores, classes = self.keep_classes(self.targets_name, boxes, scores, classes) classes = self.merge_classes_name(car_list, 'car', classes) print_info('检测数: {} - {}'.format(len(boxes), classes)) t_boxes, t_classes = read_anno_xml(xml_path) t_scores = ['T' for i in range(len(t_boxes))] t_boxes, t_scores, t_classes = \ filter_sbox((img_data.size[0], img_data.size[1]), (t_boxes, t_scores, t_classes)) t_boxes, t_scores, t_classes = self.keep_classes( self.targets_name, t_boxes, t_scores, t_classes) t_classes = self.merge_classes_name(car_list, 'car', t_classes) print_info('真值数: {}'.format(len(t_boxes), t_classes)) uni_classes = sorted(list(set(classes) | set(t_classes))) color_dict_1 = dict(zip(uni_classes, color_list_1[:len(uni_classes)])) color_dict_2 = dict(zip(uni_classes, color_list_2[:len(uni_classes)])) img_true = draw_boxes_simple(img_data, t_boxes, t_scores, t_classes, color_dict_2) # img_true.show() img_pred = draw_boxes_simple(img_data, boxes, scores, classes, color_dict_1, is_alpha=True) # img_pred.show() if out_folder: img_name = img_path.split('/')[-1] out_img = os.path.join(out_folder, img_name + '.d.png') img_pred.save(out_img) # 存储 res_dict = dict() # print('all') print_info('交通工具') ap, ar = self.iou_of_boxes(t_boxes, boxes) res_dict['all'] = (ap, ar) print_info('') for class_name in uni_classes: print_info('类别: {}'.format(class_name)) sub_t_boxes, sub_t_classes = self.filter_class( class_name, t_boxes, t_classes) sub_boxes, sub_classes = self.filter_class(class_name, boxes, classes) ap, ar = self.iou_of_boxes(sub_t_boxes, sub_boxes) res_dict[class_name] = (ap, ar) return res_dict