区块链技术博客
www.b2bchain.cn

基于yolo3的图像半自动打标

这篇文章主要介绍了基于yolo3的图像半自动打标的讲解,通过具体代码实例进行16570 讲解,并且分析了基于yolo3的图像半自动打标的详细步骤与相关技巧,需要的朋友可以参考下https://www.b2bchain.cn/?p=16570

本文实例讲述了2、树莓派设置连接WiFi,开启VNC等等的讲解。分享给大家供大家参考文章查询地址https://www.b2bchain.cn/7039.html。具体如下:

文章目录

  • 前言
  • 1. 图像样本
  • 2. yolo_test.py
    • 2.1 代码
    • 2.2 运行过程和结果
  • 3. txt2xml.py将result.txt转换为xml文件
    • 3.1 代码
    • 3.2 结果
  • 4. 用labelimg人工复查
  • 总结

前言

这篇文章以yolo3为基础,用yolo3测试没有打标的图片,将结果转换为xml文件,然后在通过人工复查,一半智能一半人工所以叫做半自动。具体实施:先用少量打标样本训练出一个模型,用该模型测试未打标样本,通过人工复查之后将样本合并,这样减少了打标过程。图片样本过多打标确实是很累啊,我当时是有5000张图片需要打标,打标一整天搞了2000张人都麻木了,加入半自动后只需要微调结果框就好,半天就搞完剩余的3000张。

1. 图像样本

首先在根目录下新建semi-auto文件夹,文件夹包括Annotations和JPEGImages,与voc格式一样,方便最终的合并。
基于yolo3的图像半自动打标
JPEGImages文件夹下放需要打标的图片,命名我建议从命名为voc格式的,然后接着已经打过标签的图片名往下继续,也就是说已经打过标的图片如果有8张,那么没打过标的就以000009开始。我当时是以时间命名的,后来出现标签与图片不对应的问题,所有的图片都要重新复查,都是泪。
基于yolo3的图像半自动打标

2. yolo_test.py

2.1 代码

用该代码替换原来的yolo_test.py或则命名为yolo_test1.py。

# -*- coding: utf-8 -*- import colorsys import os from timeit import default_timer as timer import time  import numpy as np from keras import backend as K from keras.models import load_model from keras.layers import Input from PIL import Image, ImageFont, ImageDraw  from yolo3.model import yolo_eval, yolo_body, tiny_yolo_body from yolo3.utils import letterbox_image from keras.utils import multi_gpu_model  path ='C:/Users/Administrator/Desktop/keras-yolo3-master/semi-auto/JPEGImages/' #待检测图片的位置  # 创建创建一个存储检测结果的dir result_path = './result' if not os.path.exists(result_path):     os.makedirs(result_path)  # result如果之前存放的有文件,全部清除 for i in os.listdir(result_path):     path_file = os.path.join(result_path,i)       if os.path.isfile(path_file):         os.remove(path_file)  #创建一个记录检测结果的文件 txt_path =result_path + '/result.txt' file = open(txt_path,'w')    class YOLO(object):     _defaults = {         "model_path": 'model_data/yolov3-8img.h5',         "anchors_path": 'model_data/yolo_anchors.txt',         "classes_path": 'model_data/coco_classes.txt',         "score" : 0.3,         "iou" : 0.45,         "model_image_size" : (416, 416),         "gpu_num" : 1,     }      @classmethod     def get_defaults(cls, n):         if n in cls._defaults:             return cls._defaults[n]         else:             return "Unrecognized attribute name '" + n + "'"      def __init__(self, **kwargs):         self.__dict__.update(self._defaults) # set up default values         self.__dict__.update(kwargs) # and update with user overrides         self.class_names = self._get_class()         self.anchors = self._get_anchors()         self.sess = K.get_session()         self.boxes, self.scores, self.classes = self.generate()      def _get_class(self):         classes_path = os.path.expanduser(self.classes_path)         with open(classes_path) as f:             class_names = f.readlines()         class_names = [c.strip() for c in class_names]         return class_names      def _get_anchors(self):         anchors_path = os.path.expanduser(self.anchors_path)         with open(anchors_path) as f:             anchors = f.readline()         anchors = [float(x) for x in anchors.split(',')]         return np.array(anchors).reshape(-1, 2)      def generate(self):         model_path = os.path.expanduser(self.model_path)         assert model_path.endswith('.h5'), 'Keras model or weights must be a .h5 file.'          # Load model, or construct model and load weights.         num_anchors = len(self.anchors)         num_classes = len(self.class_names)         is_tiny_version = num_anchors==6 # default setting         try:             self.yolo_model = load_model(model_path, compile=False)         except:             self.yolo_model = tiny_yolo_body(Input(shape=(None,None,3)), num_anchors//2, num_classes)                  if is_tiny_version else yolo_body(Input(shape=(None,None,3)), num_anchors//3, num_classes)             self.yolo_model.load_weights(self.model_path) # make sure model, anchors and classes match         else:             assert self.yolo_model.layers[-1].output_shape[-1] ==                  num_anchors/len(self.yolo_model.output) * (num_classes + 5),                  'Mismatch between model and given anchor and class sizes'          print('{} model, anchors, and classes loaded.'.format(model_path))          # Generate colors for drawing bounding boxes.         hsv_tuples = [(x / len(self.class_names), 1., 1.)                       for x in range(len(self.class_names))]         self.colors = list(map(lambda x: colorsys.hsv_to_rgb(*x), hsv_tuples))         self.colors = list(             map(lambda x: (int(x[0] * 255), int(x[1] * 255), int(x[2] * 255)),                 self.colors))         np.random.seed(10101)  # Fixed seed for consistent colors across runs.         np.random.shuffle(self.colors)  # Shuffle colors to decorrelate adjacent classes.         np.random.seed(None)  # Reset seed to default.          # Generate output tensor targets for filtered bounding boxes.         self.input_image_shape = K.placeholder(shape=(2, ))         if self.gpu_num>=2:             self.yolo_model = multi_gpu_model(self.yolo_model, gpus=self.gpu_num)         boxes, scores, classes = yolo_eval(self.yolo_model.output, self.anchors,                 len(self.class_names), self.input_image_shape,                 score_threshold=self.score, iou_threshold=self.iou)         return boxes, scores, classes               def detect_image(self, image_path):         start = timer() # 开始计时         for filename in os.listdir(path):                     image_path = path+'/'+filename             portion = os.path.split(image_path)             # file.write(portion[1]+' detect_result:n')             image = Image.open(image_path)             image = image.convert('RGB')                      if self.model_image_size != (None, None):                 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)             image_data = np.array(boxed_image, dtype='float32')                  print(image_data.shape) #打印图片的尺寸             image_data /= 255.             image_data = np.expand_dims(image_data, 0)  # Add batch dimension.                  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                 })                  print('Found {} boxes for {}'.format(len(out_boxes), 'img')) # 提示用于找到几个bbox                  font = ImageFont.truetype(font='font/FiraMono-Medium.otf',                         size=np.floor(2e-2 * image.size[1] + 0.2).astype('int32'))             thickness = (image.size[0] + image.size[1]) // 500                  # 保存框检测出的框的个数             # file.write('find  '+str(len(out_boxes))+' target(s) n')                  for i, c in reversed(list(enumerate(out_classes))):                 predicted_class = self.class_names[c]                 box = out_boxes[i]                 score = out_scores[i]                      label = '{} {:.2f}'.format(predicted_class, score)                 draw = ImageDraw.Draw(image)                 label_size = draw.textsize(label, font)                      top, left, bottom, right = box                 top = max(0, np.floor(top + 0.5).astype('int32'))                 left = max(0, np.floor(left + 0.5).astype('int32'))                 bottom = min(image.size[1], np.floor(bottom + 0.5).astype('int32'))                 right = min(image.size[0], np.floor(right + 0.5).astype('int32'))                      # 写入检测位置                             file.write(portion[1]+' '+predicted_class+' ' +str(right)+' ' + str(bottom)+' ' + str(left)+' '+ str(top)+' '+'n')                                  print(label, (left, top), (right, bottom))                      if top - label_size[1] >= 0:                     text_origin = np.array([left, top - label_size[1]])                 else:                     text_origin = np.array([left, top + 1])                      # My kingdom for a good redistributable image drawing library.                 for i in range(thickness):                     draw.rectangle(                         [left + i, top + i, right - i, bottom - i],                         outline=self.colors[c])                 draw.rectangle(                     [tuple(text_origin), tuple(text_origin + label_size)],                     fill=self.colors[c])                 draw.text(text_origin, label, fill=(0, 0, 0), font=font)                 del draw          end = timer()         print('time consume:%.3f s '%(end - start))         return image      def close_session(self):         self.sess.close()   # 图片检测  if __name__ == '__main__':      t1 = time.time()     yolo = YOLO()                image_path ='C:/Users/Administrator/Desktop/keras-yolo3-master/semi-auto/JPEGImages/'  #待检测图片的位置     r_image = yolo.detect_image(image_path)     file.close()      yolo.close_session()  

需要修改的是17行和206行的路径,改为待检测图片的位置

2.2 运行过程和结果

程序运行过程:
基于yolo3的图像半自动打标

运行后结果为result文件夹下的result.txt文件

000009.jpg dog 468 470 34 42  000009.jpg cattle 469 499 41 55  000010.jpg cattle 448 469 0 58  000011.jpg cattle 445 456 22 109  

3. txt2xml.py将result.txt转换为xml文件

3.1 代码

新建在根目录下就好

import copy from lxml.etree import Element, SubElement, tostring, ElementTree import cv2   # 修改为你自己的路径 template_file = 'C:/Users/Administrator/Desktop/keras-yolo3-master/VOCdevkit/VOC2007/Annotations/000001.xml'    #已打标过的xml作为模板 target_dir = 'C:/Users/Administrator/Desktop/keras-yolo3-master/semi-auto/Annotations/'    #xml保存到哪去 image_dir = 'C:/Users/Administrator/Desktop/keras-yolo3-master/semi-auto/JPEGImages/'  # 图片文件夹 train_file = 'C:/Users/Administrator/Desktop/keras-yolo3-master/result/result.txt'  # 存储了图片信息的txt文件   with open(train_file) as f:     trainfiles = f.readlines()  # 标注数据 格式(123.jpg pig x_min y_min x_max y_max)   file_names = [] tree = ElementTree()   for line in trainfiles:     trainFile = line.split()     file_name = trainFile[0]     print(file_name)       # 如果没有重复,则顺利进行。这给的数据集一张图片的多个框没有写在一起。     if file_name not in file_names:         file_names.append(file_name)         lable = trainFile[1]                  #因为要使用labelimg来编辑xml,所以将trainFile[2] float类型转成整型。再将整型转成str类型存到xml文件里面。         xmin = trainFile[2]         ymin = trainFile[3]         xmax = trainFile[4]         ymax = trainFile[5]           tree.parse(template_file)         root = tree.getroot()         root.find('filename').text = file_name           # size         sz = root.find('size')         im = cv2.imread(image_dir + file_name)#读取图片信息           sz.find('height').text = str(1080)         sz.find('width').text = str(1920)         sz.find('depth').text = str(3)           # object 因为我的数据集都只有一个框         obj = root.find('object')           obj.find('name').text = lable         bb = obj.find('bndbox')         bb.find('xmin').text = xmin         bb.find('ymin').text = ymin         bb.find('xmax').text = xmax         bb.find('ymax').text = ymax         # 如果重复,则需要添加object框     else:         lable = trainFile[1]                  xmin = trainFile[2]         ymin = trainFile[3]         xmax = trainFile[4]         ymax = trainFile[5]           xml_file = file_name.replace('jpg', 'xml')         tree.parse(target_dir + xml_file)#如果已经重复         root = tree.getroot()           obj_ori = root.find('object')           obj = copy.deepcopy(obj_ori)  # 注意这里深拷贝           obj.find('name').text = lable         bb = obj.find('bndbox')         bb.find('xmin').text = xmin         bb.find('ymin').text = ymin         bb.find('xmax').text = xmax         bb.find('ymax').text = ymax         root.append(obj)       xml_file = file_name.replace('jpg', 'xml')     tree.write(target_dir + xml_file, encoding='utf-8') 

需要修改路径

3.2 结果

结果得到3个xml文件:
基于yolo3的图像半自动打标

4. 用labelimg人工复查

基于yolo3的图像半自动打标
基于yolo3的图像半自动打标

总结

半自动打标还是挺省事的,啥时候能搞个全自动就好了,太懒!!!

本文转自互联网,侵权联系删除基于yolo3的图像半自动打标

赞(0) 打赏
部分文章转自网络,侵权联系删除b2bchain区块链学习技术社区 » 基于yolo3的图像半自动打标
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

b2b链

联系我们联系我们