从零开始dataset

目标检测的dataset

首先我们需要先将数据集做一个整理的txt,文件叫做ann.txt吧
首先是图片路径,xmin,ymin,xmax,ymax,类别
请添加图片描述

最简单的dataset就构造出来了

import numpy as np
from torch.utils.data import Dataset
from PIL import Image

class MyDataSet(Dataset):
    # 初始化
    def __init__(self,annotations_file):
        # 定义一个列表,里面有图片名称,bbox,类别
        self.annotations=annotations_file
        self.length=len(annotations_file)
    # 长度
    def __len__(self):
        return self.length

    # 返回第index个数据
    def __getitem__(self, index):
        # index:序号
        # 得到diindex数据的图片数据和y,y包括了(bbox,label)
        img,y=self.get_data(self.annotations[index])
        # 将img转成(c,h,w)
        img=np.transpose(img,(2,0,1))
        '''
            由于拿到的y数据是字符串类型的,所以需要重新构造一个(len(y),5)的矩阵存储
        '''
        box_data = np.zeros((len(y), 5))
        if len(y) > 0:
            box_data[:len(y)] = y

        box         = box_data[:, :4]
        label       = box_data[:, -1]
        return img,box,label
    def get_data(self,annotations_file):
        line=annotations_file.split()
        img_data=Image.open(line[0])
        # 输出图片大小要一致,此时只是简单的resize一下
        img_data=img_data.resize((360,360))
        bbox=np.array([box.split(',') for box in line[1:]])
        img_data=np.array(img_data,np.float32)
        return img_data,bbox

# DataLoader中collate_fn使用
# collate_fn:如何取样本的,我们可以定义自己的函数来准确地实现想要的功能,
# 将img一个batch合并,bbox一个batch合并,label一个batch合并
def frcnn_dataset_collate(batch):
    images = []
    bboxes = []
    labels = []
    for img, box, label in batch:
        images.append(img)
        bboxes.append(box)
        labels.append(label)
    images = np.array(images)
    return images, bboxes, labels

来运行一下看看效果

path='ann.txt'
train_line=[]
with open(path) as f:
    train_line=f.readlines()
myd=MyDataSet(train_line)
from torch.utils.data import DataLoader
myloader=DataLoader(myd,batch_size=16,shuffle=False,num_workers=0,collate_fn=frcnn_dataset_collate)
for i,(img,bbox,label) in enumerate(myloader):
    print(f'第{i}个batch的数据')
    print(f"img的维度:{np.array(img).shape}")
    print(f'16个batch的bbox{len(bbox)},每个batch的bbox维度:{bbox[0].shape}')
    print(f'16个batch的label:{len(label)},每个batch的bbox维度{label[0].shape}')
    break
输出:0个batch的数据
img的维度:(16, 3, 360, 360)
16个batch的bbox16,每个batch的bbox维度:(11, 4)
16个batch的label:16,每个batch的bbox维度(11,)

1

对于图片我们还是要进行一些处理,例如如果图片不是三通道怎么办,图片的resize失真怎么办,我们在get_data方法中进行优化

首先来解决通道问题

        '''
            1.如果图片不是三通道的,那么需要转成三通道
        '''
        if np.shape(img_data)[2]!=3:
            img_data = img_data.convert('RGB')

然后解决resize失真,使用灰条填充,尽量填充较少

import matplotlib.pyplot as plt
import numpy as np
from PIL import Image
path='data/coco128/images/train2017/000000000009.jpg'
img=Image.open(path)
# (480, 640, 3)
h,w=600,600
# PIL.Image打开的图片是(w,h,c)的格式
iw,ih=img.size
scale=min(h/ih,w/iw)
print(scale)
nh=int(ih*scale)
nw=int(iw*scale)
dx = (w-nw)//2
dy = (h-nh)//2
print(nh,nw,dx,dy)
# 缩放到(nw,nh)
img=img.resize((nw,nh),Image.BICUBIC)
img.show()
# new : 这个函数创建一幅给定模式(mode)和尺寸(size)的图片。如果省略 color 参数,
# 则创建的图片被黑色填充满,如果 color 参数是 None 值,则图片还没初始化。
# 创建一个全是灰色的图片
new_image = Image.new('RGB', (w, h), (128, 128, 128))
# python中PIL库中的paste函数的作用为将一张图片覆盖到另一张图片的指定位置去
new_image.paste(img, (dx, dy))
plt.imshow(new_image)
plt.savefig('img/img2')
# image_data = np.array(new_image, np.float32)

创建的都是灰色的图片new_image

请添加图片描述
将原图复制上去,就实现了添加灰条的操作
请添加图片描述

将上面代码补充进get_data函数中就可:

    def get_data(self,annotations_file):
        line=annotations_file.split()
        img_data=Image.open(line[0])
        '''
            1.如果图片不是三通道的,那么需要转成三通道
        '''
        if np.shape(img_data)[2]!=3:
            img_data = img_data.convert('RGB')
        # 输出图片大小要一致,此时只是简单的resize一下
        # img_data=img_data.resize((360,360))
        '''
            resize就会发生图片尺寸的变化,训练不会像原图那样好,bbox也会发生变化,该如何处理呢
            图片缩放会导致失真,那么能不能不缩放也达到我们想要的尺寸呢,或者最小限度的失真
            我们将图片的最大的长度保留下来,把短边用灰边填充
            
            scale就是图片(ih,iw)变化成(h,w)的最小比例,(nh,nw)就是我们按照这个比例resize的图片大小
            当然(nh,nw)和(h,w)有空白,空白我们就用灰条填充
        '''
        h,w=360,360#想要的尺寸
        iw,ih=img_data.size
        # 比列
        scale = min(w / iw, h / ih)
        nw = int(iw * scale)
        nh = int(ih * scale)
        dx = (w - nw) // 2
        dy = (h - nh) // 2

        img=img_data.resize((nw,nh),Image.BICUBIC)
        new_image=Image.new('RGB', (w, h), (128, 128, 128))
        new_image.paste(img,(dx,dy))

        bbox=np.array([box.split(',') for box in line[1:]])
        img_data=np.array(img_data,np.float32)
        return img_data,bbox

2

既然图片大小调整了,那么bbox的位置也发生变化了,需要对bbox的坐标也进行调整

if len(box) > 0:
    np.random.shuffle(box)
    # 图片大小都是按照scale变化的,bbox也应该如此
    box[:,[0,2]]=box[:,[0,2]]*nw/iw+dx
    box[:,[1,3]]=box[:,[1,3]]*nh/ih+dy
    box[:, 0:2][box[:, 0:2] < 0] = 0
    box[:, 2][box[:, 2] > w] = w
    box[:, 3][box[:, 3] > h] = h

加入到get_data函数中

    def get_data(self,annotations_file):
        line=annotations_file.split()
        img_data=Image.open(line[0])
        '''
            1.如果图片不是三通道的,那么需要转成三通道
        '''
        if np.shape(img_data)[2]!=3:
            img_data = img_data.convert('RGB')
        # 输出图片大小要一致,此时只是简单的resize一下
        # img_data=img_data.resize((360,360))
        '''
            resize就会发生图片尺寸的变化,训练不会像原图那样好,bbox也会发生变化,该如何处理呢
            图片缩放会导致失真,那么能不能不缩放也达到我们想要的尺寸呢,或者最小限度的失真
            我们将图片的最大的长度保留下来,把短边用灰边填充
            
            scale就是图片(ih,iw)变化成(h,w)的最小比例,(nh,nw)就是我们按照这个比例resize的图片大小
            当然(nh,nw)和(h,w)有空白,空白我们就用灰条填充
        '''
        h,w=360,360#想要的尺寸
        iw,ih=img_data.size
        # 比列
        scale = min(w / iw, h / ih)
        nw = int(iw * scale)
        nh = int(ih * scale)
        dx = (w - nw) // 2
        dy = (h - nh) // 2

        img=img_data.resize((nw,nh),Image.BICUBIC)
        new_image=Image.new('RGB', (w, h), (128, 128, 128))
        new_image.paste(img,(dx,dy))

        bbox=np.array([box.split(',') for box in line[1:]])
        if len(bbox) > 0:
            np.random.shuffle(bbox)
            # 图片大小都是按照scale变化的,bbox也应该如此
            bbox[:, [0, 2]] = bbox[:, [0, 2]] * nw / iw + dx
            bbox[:, [1, 3]] = bbox[:, [1, 3]] * nh / ih + dy
            bbox[:, 0:2][bbox[:, 0:2] < 0] = 0
            bbox[:, 2][bbox[:, 2] > w] = w
            bbox[:, 3][bbox[:, 3] > h] = h
        img_data=np.array(img_data,np.float32)
        return img_data,bbox

3

对于训练时图片可以进行增强,进行旋转,明亮度变化等操作,使得网络认识不同状态的图片,扩充数据集。

#左右旋转
flip=np.random.random()<.5
if flip:
    new_image=new_image.transpose(Image.FLIP_LEFT_RIGHT)
h,s,v=np.random.random(),np.random.random(),np.random.random()
#HSV调节
img=cv2.cvtColor(np.array(new_image),cv2.COLOR_RGB2HSV)
a=np.random.random()<.5
if a:
    img[...,0]=img[...,0]*h
    img[...,1]=img[...,1]*s
    img[...,2]=img[...,2]*v
    img=cv2.cvtColor(img,cv2.COLOR_HSV2RGB)*255
    img=Image.fromarray(img)
    img.show()

添加到get_data函数中

    def get_data(self,annotations_file):
        line=annotations_file.split()
        img_data=Image.open(line[0])
        '''
            1.如果图片不是三通道的,那么需要转成三通道
        '''
        if np.shape(img_data)[2]!=3:
            img_data = img_data.convert('RGB')
        # 输出图片大小要一致,此时只是简单的resize一下
        # img_data=img_data.resize((360,360))
        '''
            resize就会发生图片尺寸的变化,训练不会像原图那样好,bbox也会发生变化,该如何处理呢
            图片缩放会导致失真,那么能不能不缩放也达到我们想要的尺寸呢,或者最小限度的失真
            我们将图片的最大的长度保留下来,把短边用灰边填充
            
            scale就是图片(ih,iw)变化成(h,w)的最小比例,(nh,nw)就是我们按照这个比例resize的图片大小
            当然(nh,nw)和(h,w)有空白,空白我们就用灰条填充
        '''
        h,w=360,360#想要的尺寸
        iw,ih=img_data.size
        # 比列
        scale = min(w / iw, h / ih)
        nw = int(iw * scale)
        nh = int(ih * scale)
        dx = (w - nw) // 2
        dy = (h - nh) // 2

        img=img_data.resize((nw,nh),Image.BICUBIC)
        new_image=Image.new('RGB', (w, h), (128, 128, 128))
        new_image.paste(img,(dx,dy))

        bbox=np.array([box.split(',') for box in line[1:]])
        if len(bbox) > 0:
            np.random.shuffle(bbox)
            # 图片大小都是按照scale变化的,bbox也应该如此
            bbox[:, [0, 2]] = bbox[:, [0, 2]] * nw / iw + dx
            bbox[:, [1, 3]] = bbox[:, [1, 3]] * nh / ih + dy
            bbox[:, 0:2][bbox[:, 0:2] < 0] = 0
            bbox[:, 2][bbox[:, 2] > w] = w
            bbox[:, 3][bbox[:, 3] > h] = h
        img_data=np.array(img_data,np.float32)
        # 只有训练时才会进行图片增强,测试和预测时不用
        # slef.train可以自己定义传入,我就不写了
        if not self.train:
            return img_data,bbox
        flip = np.random.random() < .5
        if flip:
            new_image = new_image.transpose(Image.FLIP_LEFT_RIGHT)
        img_data = np.array(img_data, np.float32)
        h, s, v = np.random.random(), np.random.random(), np.random.random()
        img_data = cv2.cvtColor(np.array(new_image,np.float32), cv2.COLOR_RGB2HSV)
        a = np.random.random() < .5
        if a:
            img[..., 0] = img[..., 0] * h
            img[..., 1] = img[..., 1] * s
            img[..., 2] = img[..., 2] * v
            img_data = cv2.cvtColor(img, cv2.COLOR_HSV2RGB)
        return img_data,bbox

到这儿基本的dataset已经完成了,当然还有其他的数据增强可以自己添加,后面可以写dataloader部分的代码了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值