YoloV3笔记(二):

YoloV3笔记(二):

文章目录


最近对YoloV3进行了一段学习,在此记录下学习笔记。

  (注:此文主要讲解对数据的处理与代码的实现。)

首先,分享学习资源:

YOLO-V3硬核讲解(第三部分-YOLO-V3数据制作+代码实现)_哔哩哔哩_bilibili

直接上代码讲解:

1.XML文件处理 Data_solve.py

​    首先,做为小白的我这次通过学习才知道了困扰我好久的.XML文件怎么来的,这里教学视频中推荐了标注精灵这个软件,可对图片进行标注,建立对应的XML文件,这里给出学习资源:

深度学习数据标注(告别labelme和labelimg)_哔哩哔哩_bilibili

还不懂XML文件怎么创建的可观看以上视频。

# 获取图像标签等信息
import math
import xml.etree.ElementTree as et
import os

class_num = {
    'person':0,
    'horse':1,
    'bicycle':2
}
# 定义一个字典用于键值对对应

xml_dir = 'Data/image_voc'      # XML文件的地址
xml_filenames = os.listdir(xml_dir)     # 获取文件夹中所有XML文件路径
with open('data.text','a') as f:

    for xml_filename in xml_filenames:
        xml_filename_path = os.path.join(xml_dir,xml_filename)  # 遍历拼接所有XML文件的路径

        #       以下元素树形式
        """
        这里简单提提元素树:
        
        找到根节点后,则可以进行各种操作

		查找子节点:

		递归查找所有子节点:obj.iter('Name')。

		非递归查找所有子节点:obj.findall('Name')
		
        """
        tree = et.parse(xml_filename_path)  #用于读取XML文件内容
        root = tree.getroot()               # 获取根节点
        filename = root.find('filename')
        names = root.findall('object/name')
        boxs = root.findall('object/bndbox')
        #  找到XML文件下所有的name和box

        data = []
        data.append(filename.text)

        for name,box in zip(names,boxs):
            cls = class_num[name.text]  #种类 取下标
            #  计算中心点偏移量
            cx,cy,w,h = math.floor((int(box[2].text)-int(box[0].text))/2),math.floor((int(box[3].text)-int(box[1].text))/2),int(box[2].text)-int(box[0].text),int(box[3].text)-int(box[1].text)

            data.append(cls)  #  类别数 可字典查询
            data.append(cx)
            data.append(cy)
            data.append(w)
            data.append(h)
            # 将算出来的数据存储在data中
        _str = ''
        for i in data:
            _str = _str + ' ' +str(i)
            #  将处理后的数据按’ ‘分割开以后,写入data.txt文件中
        f.write(_str+'\n')
f.close()


代码完成后效果如下:

YoloV3笔记(二):

2.对图片格式进行处理,防止缩放图片改变 utils.py

​    因为直接将480*364的图片进行缩放会使图像发生变化
​    所以采取取图像最大边做正方形,将图片“贴入”其中,未黏贴位置采用灰度补充,实现等比缩放

from PIL import Image
from config import *


def make_416_Image(image_path):
    img = Image.open(image_path) #读取文件
    w,h = img.size[0],img.size[1]   #取宽高
    print(w,h)
    temp = max(w,h)   #找最长边
    mask = Image.new(mode = 'RGB',size = (temp,temp),color = (0,0,0))  #  最大边做灰度图
    mask.paste(img) #贴图
    return mask

if __name__ == '__main__':
    mask = make_416_Image('Data/images/000017.jpg')
    mask.show()

3.定义三个框(13×13,26×26,52×52) config.py

DATA_WIDTH = 416  #宽
DATA_HEIGHT = 416  #高

CLASS_NUM = 3      #种类数

antors = {
    13:[[168,302],[27,221],[336,284]],
    26:[[129,209],[85,413],[44,42]],
    52:[[129,209],[85,413],[44,42]]
}

#  kmeans的方法  分出9个框 将差值不同的数据分类
# 13*13 26*26 52*52 各有三个框

ANTORS_AREA = {
    13:[x*y for x,y in antors[13]],
    26:[x*y for x,y in antors[26]],
    52:[x*y for x,y in antors[52]]
}

print(ANTORS_AREA[13])

​    用Kmeans的方法归类数据(不断计算更新中心点的距离,计算IOU)。(网上很多讲解,可以去b站取取经)

​    IOU = 交集/并集,越大说明差异越小。

​    简单来说,Kmeans(就是把挨得近的数据点划分到一起)进行的是如下操作,:
​    1.定义有多少类(簇)
​    2.将每一个类的类心随机定义在一个点上
​    3.将每个点与距离其最近的类关联起来
​    4.对每个簇找到的所有点取中心点
​    5.更新簇的中心
​    6.重复去上操作,直到簇心变化不大。
​    比如这里说有一个点A(2.5,5.0),它身边有两个簇心(2.5,0) (0,5.0),因为A距离(2.5,0)这个簇心的距离比较近,所以A归(2.5,0)这一类。

​    在Yolov3中,kmeans操作就是不断更新anchor框的中心点,直到得到最适合我们数据的anchor框,即得到最可能的框对应的类别是什么。

4.Dataset.py文件(主要数据处理)

​    本代码以三分类为例(人、马、自行车),以三分类为例那需要多少的通道呢?

​    答案:(5+3)*3 = 24

​    其中,什么是5+3?

​    5分别代表:置信度C,X、Y、H、W的偏移量 3代表三分类

​    那什么又是*3呢?

​    正如我们所知,YoloV3以三个框(大13×13、中26×26、小52×52)识别图片,每个框中都具备(5+3)即上述那么多元素。

​    在我看来,yolov3检测分为两步:
​    1、确定检测对象位置(偏移量)
​    2、对检测对象类别

#   数据处理
import math

import numpy as np
import torch
from torch.utils.data import Dataset
from PIL import Image
import os
from utils import *
from torchvision import transforms
from config import *

tf = transforms.Compose([
    transforms.ToTensor()  #归一化
])

def one_hot(cls_num,i):
    rst = np.zeros(cls_num)  # 生成用0填充的数组的,共有cls_num列
    rst[i] = 1
    return rst
# 独热编码处理类别数

class YoloDataset(Dataset):
    def __init__(self):
        f = open('data.text','r')  #以读的方式打开data.text
        self.Dataset = f.readlines()

    def __len__(self):
        return len(self.Dataset)

    def __getitem__(self, index):
        data = self.Dataset[index].strip() #注意  这里.strip()用于去除data.text文件中第一列的空格,否则读取时会报错
        Temp_data = data.split()  #按空格拆分数据
        _boxes = np.array([float(x) for x in Temp_data[1:]])  # 取数组方便切割
        boxes = np.split(_boxes,len(_boxes)//5) #每隔5个数据切割一次
        img = make_416_Image(os.path.join('Data/images', Temp_data[0]))
        # 看utils.py文件讲解
        w,h = img.size
        case = 416/w  #用于偏差计算
        img = img.resize((416,416))  #改变图片格式为416*416
        img_data = tf(img)  #归一化
        labels = {} #定义字典

        for feature_size,_antors in antors.items():
            labels[feature_size] = np.zeros((feature_size,feature_size,3,5+CLASS_NUM))
            #   在一个尺度下画框
            for box in boxes:
                cls,cx,cy,w,h = box
                cx,cy,w,h = cx*case,cy*case,w*case,h*case  # 缩放
                _x,x_index = math.modf(cx*feature_size/DATA_WIDTH)
                _y,y_index = math.modf(cy*feature_size/DATA_WIDTH)
                # 计算偏移量和格子数

                for i,antor in enumerate(_antors):
                    area = w*h
                    iou = min(area,ANTORS_AREA[feature_size][i]/max(area,ANTORS_AREA[feature_size][i]))
                    """
                    置信度计算 锚框的交集除以并集  feature_size定义第几个框4
                    min为交集   max为并集
                    """
                    p_w, p_h = w / (antor[0]), h / (antor[1])
                    # W H的偏移量

                    labels[feature_size][int(x_index),int(y_index),i] = np.array([iou,_x,_y,np.log(p_w),np.log(p_h),*one_hot(CLASS_NUM,int(cls))])
                    # 取对数保证数据都为正值 *代表变量为可变参数,不定长

        return labels[13],labels[26],labels[52],img_data

if __name__ == '__main__':
    Dataset = YoloDataset()

​    其中,偏移量的计算:

​    偏移量:x/(416/13)   x/(416/26)   x/(416/52)

上一篇:java随机生成日期myql随机查询数据


下一篇:YOLOv3用到的tricks介绍