天天看点

多目标检测与识别 YOLOV3 解读2 样本制作YOLOv3

YOLOv3

1.1样本制作

前一篇文章已经总结了,要检测识别多目标,需要这几样东西。

1.建议框和真实框的相对位置 2 中心点 3 iou(建议框和真实框) 4 cls(类别)

如果自己做样本,就先用标注软件得到框的左上角和右下角的坐标点,然后算出中心点的坐标和宽高。由于yolov3输入图片大小必须是416 * 416的。所以得到中心点和宽高不能直接resize,而是先应该用cx/size(0),cy/size(1),w/size(0),h/size(1),(cx,cy是中心点的坐标,size(0)是整张图片的宽,size(1)是整张图片的高)然后就可以resize,resize后所有的中心点和宽高都乘以416这样,就得到416*416图片下的位置。然后怎么得到中心点的偏移?,我们就用中心点的位置除以缩放比例,整数部分就是中心点所在网格的位置,小数部分就是中心点相对于网格左上角的偏移。建议框和真实框的位置关系就分别用宽高比表示。这里为什么要加log,因为宽高比是0-1之间的网络返回结果很可能是负数,那么通过log反算回去一定是正数。还有iou我们就通过建议框和真实框的交并比来算。类别就用one-hot.这样就得到了样本。

在这里插入代码片
import torchvision
import numpy as np
import cfg
import os
from PIL import Image
import math

transforms = torchvision.transforms.Compose([
    torchvision.transforms.Resize((416, 416)),
    torchvision.transforms.ToTensor()
])


def one_hot(cls_num, v):
    b = np.zeros(cls_num)
    b[v] = 1.
    return b


class MyDataset():

    def __init__(self):
        # super(MyDataset, self).__init__()
        with open(cfg.LABEL_FILE_PATH) as f:
            self.dataset = f.readlines()
            # print(self.dataset)

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

    def __getitem__(self, index):

        labels = {}
        # dataset[index]index 是第几个图片的标签
        # print(self.dataset[index])
        line = self.dataset[index]
        strs = line.split()
        _img_data = Image.open(os.path.join(cfg.IMG_BASE_DIR, strs[0]))

        # transforms = torchvision.transforms.ToTensor()
        # trans = transforms(_img_data)
        # print(trans.size())
        img_data = transforms(_img_data)
        # img_data.show()
        # _boxes = transforms(_img_data)

        # 把标签转化成数组格式
        _boxes = np.array([float(x) for x in strs[1:]])
        # 5个5个的划分变成5个数组就是5个框
        boxes = np.split(_boxes, len(_boxes) // 5)

        for feature_size, anchor in cfg.ANCHORS_GROUP.items():  # 一个feature_size有三个anchor

            # 定13,26,52的特征图形状 一个anchor对应一个类别
            labels[feature_size] = np.zeros(shape=(feature_size, feature_size, 3, 5+cfg.CLASS_NUM))

            # 计算特征图多对应的偏移量和索引
            for box in boxes:
            # 这里的box就是上面提到的cx/size(0),cy/size(1),w/size(0),h/size(1)
                cls, cx, cy, w, h = box
                # print(box)
                cx = cx * 416
                cy = cy * 416
                # print(cx, cy)
                w = w * 416
                h = h * 416
                # print(cx, cy, w, h)
                # math.modf 返回两个值小数部分为偏移量,整数部分为索引
                cx_offset, cx_index = math.modf(cx * feature_size / cfg.Img_HEIGHT)
                cy_offset, cy_index = math.modf(cy * feature_size / cfg.Img_HEIGHT)

                for i, d in enumerate(anchor):  # 每次循环完有三个anchor
                    # 返回每个anchor框的面积
                    # print(anchor)
                    anchor_area = cfg.ANCHORS_GROUP_AREA[feature_size][i]
                    # 真实的宽高除以先验框的宽高

                    p_w, p_h = w / d[0], h / d[1]

                    # 真实的面积
                    p_area = w * h
                    # 真实框在先验宽里面所以iou为小除以大
                    # 计算置信度(同心框的IOU(交并))
                    # inter = np.minimum(w, anchor[0]) * np.minimum(h, anchor[1])  # 交集
                    # conf = inter / (p_area + anchor_area - inter)
                    iou = min(p_area, anchor_area) / max(p_area, anchor_area)  # 这个iou不是为了筛选是为了一个中心点预测三个物体
                    # print(iou)
                    # print(d)

                    # cy_index==h cx_index==w,i为第几个建议框 返回的是iou 中心点和宽高 和类别的置信度 注意shape 为 h w class
                    # cx_offset, cy_offset拿到特征图每个网格相对于左上角偏移的位置
                    labels[feature_size][int(cy_index), int(cx_index), i] = np.array(
                        [cx_offset, cy_offset, np.log(p_w), np.log(p_h), iou, *one_hot(cfg.CLASS_NUM, int(cls))])

        return labels[13].astype(np.float32), labels[26].astype(np.float32),labels[52].astype(np.float32), img_data
           

继续阅读