yolov3-keras版本训练自己的数据全过程

1、下载文件包:https://github.com/qqwweee/keras-yolo3

2、为此模型建立anaconda虚拟环境。

conda creat -n yolo python=3.6

安装相应的环境,conda install 安装即可
版本号对应:

  • python 3.6.9
  • cuda 9.2
  • cudnn 7.3.1
  • tensorflow-gpu 1.12.0
  • keras 2.2.4

3、安装依赖

pip install Pillow
pip install matplotlib
conda install ffmpeg
pip install opencv-contrib-python

4、下载权重文件
https://pjreddie.com/media/files/yolov3.weights
也可以用命令行下载:

wget https://pjreddie.com/media/files/yolov3.weights

如果特别慢可以百度网盘下载:链接:https://pan.baidu.com/s/1vFlOhClLDcyvUfu0JatVtA
提取码:k7lo
5、转化权重为keras模型
将权重文件转换成.h5文件(代码包中有convert.py文件负责,生成的.h5文件在model_data中)
命令行输入:

python convert.py yolov3.cfg yolov3.weights model_data/yolo.h5

然后可以测试一下环境或者权重是否成功匹配好:
命令号输入:

python yolo_video.py --image

然后输入图片名字(单张)
6、准备数据集
①建立一下名字和对应关系的文件夹

#在keras-yolo3下创建
VOCdevkit
└── VOC2012
    ├── Annotations  (存标注好的xml文件,标注可用labelImg)
    ├── ImageSets
    │   ├── Layout
    │   ├── Main (存放4个txt文件,装着图片名字,train.txt test.txt trainval.txt val.txt预先建好)
    │   └── Segmentation
    ├── JPEGImages  (放图片)
    └── labels

没有备注的没用上。
②按比例分配测试图片和训练图片
写一个test.py用来分配1:9数据(Main中),执行完此程序Main中的四个txt文件中会有图片名字。

import os
import random

trainval_percent = 0.1
train_percent = 0.9
xmlfilepath = '/home/sys507/sun/VOCdevkit/VOC2012/Annotations'
txtsavepath = '/home/sys507/sun/VOCdevkit/VOC2012/ImageSets/Main'
total_xml = os.listdir(xmlfilepath)

num = len(total_xml)
list = range(num)
tv = int(num * trainval_percent)
tr = int(tv * train_percent)
trainval = random.sample(list, tv)
train = random.sample(trainval, tr)

ftrainval = open('/home/sys507/sun/VOCdevkit/VOC2012/ImageSets/Main/trainval.txt', 'w')
ftest = open('/home/sys507/sun/VOCdevkit/VOC2012/ImageSets/Main/test.txt', 'w')
ftrain = open('/home/sys507/sun/VOCdevkit/VOC2012/ImageSets/Main/train.txt', 'w')
fval = open('/home/sys507/sun/VOCdevkit/VOC2012/ImageSets/Main/val.txt', 'w')

for i in list:
    name = total_xml[i][:-4] + '\n'
    if i in trainval:
        ftrainval.write(name)
        if i in train:
            ftest.write(name)
        else:
            fval.write(name)
    else:
        ftrain.write(name)

ftrainval.close()
ftrain.close()
fval.close()
ftest.close()

③修该voc_annotation中的类别并执行此文件
修改成自己的类和对应的生成文件名字
在这里插入图片描述
修改完执行,可用pycharm直接执行,也可命令行

python voc_annotation.py

执行后会在主目录生成3个txt文件
在这里插入图片描述
④生成适合自己数据的anchor
执行k-means.py文件,会在主目录生成yolo_anchor.txt文件。
⑤修改model_data中voc_classes.txt和coco_classes.txt中个的类别,换成自己的类别。
7、开始训练
先在主目录建立一个名字为logs的文件夹,然后在里面再建立一个名为000的文件夹,用于存储最后的权重。
修改train,py中对应路径、初始训练权重、batch尺寸、迭代次数 ,讯改完执行train.py文件,开始训练。最后
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述
备注:也可以用以下代码替换带原有的train.py代码,这个就是全部层数都训练,源文件是先训练后三层(冻结前面249层),然后再训练全部层。但是这个代码有个缺点就是不能保存中间权重,只有最终权重。

"""
Retrain the YOLO model for your own dataset.
"""
import numpy as np
import keras.backend as K
from keras.layers import Input, Lambda
from keras.models import Model
from keras.callbacks import TensorBoard, ModelCheckpoint, EarlyStopping

from yolo3.model import preprocess_true_boxes, yolo_body, tiny_yolo_body, yolo_loss
from yolo3.utils import get_random_data


def _main():
    annotation_path = '2012_train.txt'
    log_dir = 'logs/000/'
    classes_path = 'model_data/voc_classes.txt'
    anchors_path = 'yolo_anchors.txt'
    class_names = get_classes(classes_path)
    anchors = get_anchors(anchors_path)
    input_shape = (416, 416)  # multiple of 32, hw
    model = create_model(input_shape, anchors, len(class_names))
    train(model, annotation_path, input_shape, anchors, len(class_names), log_dir=log_dir)


def train(model, annotation_path, input_shape, anchors, num_classes, log_dir='logs/'):
    model.compile(optimizer='adam', loss={
        'yolo_loss': lambda y_true, y_pred: y_pred})
    logging = TensorBoard(log_dir=log_dir)
    checkpoint = ModelCheckpoint(log_dir + "ep{epoch:03d}-loss{loss:.3f}-val_loss{val_loss:.3f}.h5",
                                 monitor='val_loss', save_weights_only=True, save_best_only=True, period=1)
    batch_size = 10
    val_split = 0.05
    with open(annotation_path) as f:
        lines = f.readlines()
    np.random.shuffle(lines)
    num_val = int(len(lines) * val_split)
    num_train = len(lines) - num_val
    print('Train on {} samples, val on {} samples, with batch size {}.'.format(num_train, num_val, batch_size))

    model.fit_generator(data_generator_wrap(lines[:num_train], batch_size, input_shape, anchors, num_classes),
                        steps_per_epoch=max(1, num_train // batch_size),
                        validation_data=data_generator_wrap(lines[num_train:], batch_size, input_shape, anchors,
                                                            num_classes),
                        validation_steps=max(1, num_val // batch_size),
                        epochs=200,
                        initial_epoch=0)
    model.save_weights(log_dir + 'trained_weights.h5')


def get_classes(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(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 create_model(input_shape, anchors, num_classes, load_pretrained=False, freeze_body=False,
                 weights_path='trained_weights.h5'):
    K.clear_session()  # get a new session
    image_input = Input(shape=(None, None, 3))
    h, w = input_shape
    num_anchors = len(anchors)
    y_true = [Input(shape=(h // {0: 32, 1: 16, 2: 8}[l], w // {0: 32, 1: 16, 2: 8}[l], \
                           num_anchors // 3, num_classes + 5)) for l in range(3)]

    model_body = yolo_body(image_input, num_anchors // 3, num_classes)
    print('Create YOLOv3 model with {} anchors and {} classes.'.format(num_anchors, num_classes))

    if load_pretrained:
        model_body.load_weights(weights_path, by_name=True, skip_mismatch=True)
        print('Load weights {}.'.format(weights_path))
        if freeze_body:
            # Do not freeze 3 output layers.
            num = len(model_body.layers) - 7
            for i in range(num): model_body.layers[i].trainable = False
            print('Freeze the first {} layers of total {} layers.'.format(num, len(model_body.layers)))

    model_loss = Lambda(yolo_loss, output_shape=(1,), name='yolo_loss',
                        arguments={'anchors': anchors, 'num_classes': num_classes, 'ignore_thresh': 0.5})(
        [*model_body.output, *y_true])
    model = Model([model_body.input, *y_true], model_loss)
    return model


def data_generator(annotation_lines, batch_size, input_shape, anchors, num_classes):
    n = len(annotation_lines)
    np.random.shuffle(annotation_lines)
    i = 0
    while True:
        image_data = []
        box_data = []
        for b in range(batch_size):
            i %= n
            image, box = get_random_data(annotation_lines[i], input_shape, random=True)
            image_data.append(image)
            box_data.append(box)
            i += 1
        image_data = np.array(image_data)
        box_data = np.array(box_data)
        y_true = preprocess_true_boxes(box_data, input_shape, anchors, num_classes)
        yield [image_data, *y_true], np.zeros(batch_size)


def data_generator_wrap(annotation_lines, batch_size, input_shape, anchors, num_classes):
    n = len(annotation_lines)
    if n == 0 or batch_size <= 0: return None
    return data_generator(annotation_lines, batch_size, input_shape, anchors, num_classes)


if __name__ == '__main__':
    _main()

如果报错:

Hint: If you want to see a list of allocated tensors when OOM happens, add report_tensor_allocations_upon_oom to RunOptions for current allocation info.

就是显存不足,改小batch,如果改到1还是不行,那就是环境有问题了。
8、测试图片并计算mAP
①下载测试文件包:https://github.com/Cartucho/mAP
如果慢可以百度网盘下载:链接:https://pan.baidu.com/s/1dyG_0UpziwNfjBO4xbOEyA
提取码:yzqw
复制这段内容后打开百度网盘手机App,操作更方便哦

②准备测试数据

--mAP
  --input
    --images-optional          放测试图片
    --ground-truth             放图片对应的xml文件
    --detection-results        放测试结果(程序生成)

执行:

cd mAP/scripts/extra
python convert_gt_xml.py

用于提取xml中的数据变成txt。代码运行完后,测试数据的GT坐标会保存在对应的txt文件内,XML文件会另存在目录中的backup文件夹内;
③建立检测文件yolo_detect.py并修改参数
建立yolo_detect.py文件,放在主目录下,与yolo.py同级。
代码如下:

# -*- coding: utf-8 -*-
"""
Class definition of YOLO_v3 style detection model on image and video
"""

import colorsys
import os
import sys
from timeit import default_timer as timer

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
import os
from keras.utils import multi_gpu_model

class YOLO(object):
    _defaults = {
        "model_path": 'trained_weights.h5', ##训练好的模型的路径
        "anchors_path": 'yolo_anchors.txt',
        "classes_path": 'model_data/voc_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]
        print('classes:{}'.format(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):
        start = timer()

        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'))

        font = ImageFont.truetype(font='font/FiraMono-Medium.otf',
                    size=np.floor(3e-2 * image.size[1] + 0.5).astype('int32'))
        thickness = (image.size[0] + image.size[1]) // 300

        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'))
            print(label, (left, top), (right, bottom))
            #new_f=open("/home/shan/xws/pro/keras-yolo3/detection-results/"+tmp_file.replace(".jpg", ".txt"), "a")
            new_f.write("%s %s %s %s %s\n" %  (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(end - start)
        return image

    def close_session(self):
        self.sess.close()

if __name__ == '__main__':
    # yolo=YOLO()
    # path = '1.jpg'
    # try:
    #     image = Image.open(path)
    # except:
    #     print('Open Error! Try again!')
    # else:
    #     r_image = yolo.detect_image(image)
    #     r_image.show()
    # yolo.close_session()
    #strat1=timer()
    dirname="/home/sys507/sun/mAP-master/input/images-optional/" ##该目录为测试照片的存储路径,每次测试照片的数量可以自己设定
    path=os.path.join(dirname)
    pic_list=os.listdir(path)
    count=0
    yolo=YOLO()
    for filename in pic_list:
        tmp_file=pic_list[count]
        new_f=open("/home/sys507/sun/mAP-master/input/detection-results/"+tmp_file.replace(".jpg", ".txt"), "a")  #预测坐标生成txt文件保存的路径
        abs_path=path+pic_list[count]
        image = Image.open(abs_path)
        r_image = yolo.detect_image(image)
        count=count+1
    #end1=timer()
    print(count)
    yolo.close_session()

修改路径等参数。
在这里插入图片描述
④执行yolo_detect.py

python yolo_detect.py

测试完后将测试结果(.txt)保存在mAP项目的input/detection-results文件夹下。
⑤计算mAP保存检测图片(带框)
执行main.py文件即可:

python main.py

测试结果会自动保存在result目录下(各种数据图什么的)

另:
①如果想直接测试图片,可以使用一下代码:

# -*- coding: utf-8 -*-
"""
功能:keras-yolov3 进行批量测试 并 保存结果
项目来源:https://github.com/qqwweee/keras-yolo3
"""

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 = '2012_test.txt'
path = 'model_data/test/'  # 待检测图片的位置

# 创建创建一个存储检测结果的dir
result_path = 'model_data/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/trained_weights_final.h5',
        "anchors_path": 'model_data/yolo_anchors.txt',
        "classes_path": 'model_data/voc_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):
        start = timer()  # 开始计时

        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(
                predicted_class + '  score: ' + str(score) + ' \nlocation: top: ' + str(top) + '、 bottom: ' + str(
                    bottom) + '、 left: ' + str(left) + '、 right: ' + str(right) + '\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()
    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)
        r_image = yolo.detect_image(image)
        file.write('\n')
        #r_image.show() #显示检测结果
        image_save_path = 'model_data/result/result_' + portion[1]
        print('detect result save to....:' + image_save_path)
        r_image.save(image_save_path)

    time_sum = time.time() - t1
    file.write('time sum: ' + str(time_sum) + 's')
    print('time sum:', time_sum)
    file.close()
    yolo.close_session()

②可能遇到的错误:
1)权重转化的时候报错:

Traceback (most recent call last):
  File "convert.py", line 262, in <module>
    _main(parser.parse_args())
  File "convert.py", line 83, in _main
    unique_config_file = unique_config_sections(config_path)
  File "convert.py", line 53, in unique_config_sections
    output_stream.write(line)
TypeError: unicode argument expected, got 'str'

修改办法:

头添加:outputstream=io.StringIO
    output_stream = io.StringIO()
改成
    output_stream = io.BytesIO()

2)也是权重转化时报错:

File "convert.py", line 22
SyntaxError: Non-ASCII character '\xe6' in file convert.py on line 22, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details

修改办法:

在头文件前加入:(中文问题)
# -*- coding: utf-8 -*

3)试验运行yolo.py时报错:

Traceback (most recent call last):
  File "yolo.py", line 19, in <module>
    from keras.utils import multi_gpu_model
ImportError: cannot import name multi_gpu_model

解决办法:

备注上:#from keras.utils import multi_gpu_model
或者:pip install git+git://github.com/fchollet/keras.git --upgrade
升级keras版本。

4)执行python voc_annotation时报错:

Traceback (most recent call last):
  File "voc_annotation.py", line 31, in <module>
    convert_annotation(year, image_id, list_file)
  File "voc_annotation.py", line 15, in convert_annotation
    difficult = obj.find('difficult').text
AttributeError: 'NoneType' object has no attribute 'text'

解决办法:
difficult中的D大写,原xml中是大写的。
然后在运行,主目录会多三个txt文档。或者把带difficult的都备注掉。
5)执行python voc_annotation时报错:

ValueError: invalid literal for int() with base 10: '45.70000076293945'

解决办法:
原因是数字字符串不能直接转int类型,需要转为float类型后才能转int类型:

b = (int(float(xmlbox.find('xmin').text)), int(float(xmlbox.find('ymin').text)),
             int(float(xmlbox.find('xmax').text)), int(float(xmlbox.find('ymax').text)))

6)测试时报错:

v2.error: OpenCV(3.4.2) /tmp/build/80754af9/opencv-suite_1535558553474/work/modules/highgui/src/window.cpp:632: error: (-2:Unspecified error) The function is not implemented. Rebuild the library with Windows, GTK+ 2.x or Carbon support. If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, then re-run cmake or configure script in function 'cvShowImage'

解决办法:

sudo apt-get install build-essential cmake libgtk2.0-dev libtiff4-dev  libjasper-dev libavformat-dev libswscale-dev libavcodec-dev  libjpeg62-dev pkg-config ffmpeg

又报错:

正在读取软件包列表... 完成
正在分析软件包的依赖关系树       
正在读取状态信息... 完成       
没有可用的软件包 libtiff4-dev,但是它被其它的软件包引用了。
这可能意味着这个缺失的软件包可能已被废弃,
或者只能在其他发布源中找到
然而下列软件包会取代它:
  libtiff5-dev:i386 libtiff5-dev

E: 软件包 libtiff4-dev 没有可安装候选

解决办法:
重新安装opencv

删除XML文件中某些类别的对应信息代码:

import xml.etree.cElementTree as ET
import os

path_root = ['/home/sys507/sun/VOCdevkit/VOC2012/Annotations']

CLASSES = [ "traindoor"]
for anno_path in path_root:
    xml_list = os.listdir(anno_path)
    for axml in xml_list:
        path_xml = os.path.join(anno_path, axml)
        tree = ET.parse(path_xml)
        root = tree.getroot()

        for child in root.findall('object'):
            name = child.find('name').text
            if not name in CLASSES:
                root.remove(child)

        tree.write(os.path.join('/home/sys507/sun/VOCdevkit/VOC2012/A', axml))

mAP参考:https://blog.csdn.net/plSong_CSDN/article/details/89502117


版权声明:本文为qq_43211132原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。