计算机视觉———— 训练数据获取与处理

一、数据集的获取

  通常,我们的数据来源于各个比赛平台。首先是AIStudio中的数据集,大部分经典数据集例如百度AI Studio ,Kaggle、天池、讯飞等平台(通过关键词搜索获取需要的数据集),或者是Github。还有一些小的平台,需要大家自己去看。通常来说,数据集用于学术目的,有些数据需要申请才能获得链接。

1.1 Kaggle有趣比较火热的数据集

url :https://www.kaggle.com/c/house-prices-advanced-regression-techniques/data?select=test.csv

House Prices-Advanced Regression Techniques      预测销售价格

Cat and Dog                         猫狗分类

Machine Learning from Disaster      预测泰坦尼克号的生存情况并熟悉机器学习基础知识

1.2 天池

阿里数据:https://tianchi.aliyun.com/dataset/dataDetail?dataId=74952

Barley Remote Sensing Dataset大麦遥感检测数据集     遥感影像分割

耶鲁人脸数据库                   目标检测任务(人脸检测)

1.3 DataFountain

URL:https://www.datafountain.cn/datasets/6070

花卉分类数据集                       图像分类

1.4 其他常用的数据集官网

科大讯飞官网

COCO数据集

url:https://cocodataset.org/#download

1.5 完整流程概述

1.5.1 图像处理完整流程

    1. 图片数据获取
    1. 图片数据清洗

  ----初步了解数据,筛选掉不合适的图片

    1. 图片数据标注
    1. 图片数据预处理data preprocessing。

  ----标准化 standardlization

    一 中心化 = 去均值 mean normallization

      一 将各个维度中心化到0

      一 目的是加快收敛速度,在某些激活函数上表现更好

     一 归一化 = 除以标准差

      一 将各个维度的方差标准化处于[-1,1]之间

      一 目的是提高收敛效率,统一不同输入范围的数据对于模型学习的影响,映射到激活函数有效梯度的值域

    1. 图片数据准备data preparation(训练+测试阶段)

  ----划分训练集,验证集,以及测试集

    1. 图片数据增强data augjmentation(训练阶段 )

  ----CV常见的数据增强

       · 随机旋转

       · 随机水平或者重直翻转

       · 缩放

       · 剪裁

       · 平移

       · 调整亮度、对比度、饱和度、色差等等

       · 注入噪声

       · 基于生成对抗网络GAN做数搪增强AutoAugment等

计算机视觉———— 训练数据获取与处理_第1张图片

计算机视觉———— 训练数据获取与处理_第2张图片

1.5.2 纯数据处理完整流程

  • 数据预处理与特征工程

  • 1.感知数据

  ----初步了解数据

  ----记录和特征的数量特征的名称

  ----抽样了解记录中的数值特点描述性统计结果

  ----特征类型

  ----与相关知识领域数据结合,特征融合

  • 2.数据清理

  ----转换数据类型

  ----处理缺失数据

  ----处理离群数据

  • 3.特征变换

  ----特征数值化

  ----特征二值化

  ----OneHot编码

  ----特征离散化特征

  ----规范化

    区间变换

    标准化

    归一化

  • 4.特征选择

  ----封装器法

    循序特征选择

    穷举特征选择

    递归特征选择

  ----过滤器法

  ----嵌入法

  • 5.特征抽取

  ----无监督特征抽取

    主成分分析

    因子分析

  ----有监督特征抽取

拓展小知识:

   皮尔森相关系数是用来反应俩变量之间相似程度的统计量,在机器学习中可以用来计算特征与类别间的相似度,即可判断所提取到的特征和类别是正相关、负相关还是没有相关程度。 Pearson系数的取值范围为[-1,1],当值为负时,为负相关,当值为正时,为正相关,绝对值越大,则正/负相关的程度越大。若数据无重复值,且两个变量完全单调相关时,spearman相关系数为+1或-1。当两个变量独立时相关系统为0,但反之不成立。

当两个变量的标准差都不为零时,相关系数才有定义,Pearson相关系数适用于:

(1)、两个变量之间是线性关系,都是连续数据。

(2)、两个变量的总体是正态分布,或接近正态的单峰分布。

(3)、两个变量的观测值是成对的,每对观测值之间相互独立。

二、数据处理

2.1 官方数据COCO 处理为 VOC

# 创建索引
from pycocotools.coco import COCO 
import os
import shutil
from tqdm import tqdm
import skimage.io as io
import matplotlib.pyplot as plt
import cv2
from PIL import Image, ImageDraw
from shutil import move
import xml.etree.ElementTree as ET  
from random import shuffle

# 保存路径
savepath = "VOCData/"
img_dir = savepath + 'images/'          #images 存取所有照片
anno_dir = savepath + 'Annotations/'    #Annotations存取xml文件信息
datasets_list=['train2017', 'val2017']
 
classes_names = ['person']
# 读取COCO数据集地址  Store annotations and train2017/val2017/... in this folder
dataDir = './'

#写好模板,里面的%s与%d  后面文件输入输出流改变   -------转数据集阶段--------
headstr = """        

    VOC
    %s
    
        My Database
        COCO
        flickr
        NULL
    
    
        NULL
        company
    
    
        %d
        %d
        %d
    
    0
"""
objstr = """
    
        %s
        Unspecified
        0
        0
        
            %d
            %d
            %d
            %d
        
    
"""
 
tailstr = '''

'''
 
 
# if the dir is not exists,make it,else delete it
def mkr(path):
    if os.path.exists(path):
        shutil.rmtree(path)
        os.mkdir(path)
    else:
        os.mkdir(path)
 
 
mkr(img_dir)
mkr(anno_dir)
 
 
def id2name(coco):   #   生成字典 提取数据中的id,name标签的值  ---------处理数据阶段---------
    classes = dict()
    for cls in coco.dataset['categories']:
        classes[cls['id']] = cls['name']
    return classes
 
 
def write_xml(anno_path, head, objs, tail):  #把提取的数据写入到相应模板的地方 
    f = open(anno_path, "w")
    f.write(head)
    for obj in objs:
        f.write(objstr % (obj[0], obj[1], obj[2], obj[3], obj[4]))
    f.write(tail)
 
 
def save_annotations_and_imgs(coco, dataset, filename, objs):
    # eg:COCO_train2014_000000196610.jpg-->COCO_train2014_000000196610.xml
    anno_path = anno_dir + filename[:-3] + 'xml'
    img_path = dataDir + dataset + '/' + filename
    dst_imgpath = img_dir + filename
 
    img = cv2.imread(img_path)
    if (img.shape[2] == 1):
        print(filename + " not a RGB image")
        return
    shutil.copy(img_path, dst_imgpath)
 
    head = headstr % (filename, img.shape[1], img.shape[0], img.shape[2])
    tail = tailstr
    write_xml(anno_path, head, objs, tail)
 
 
def showimg(coco, dataset, img, classes, cls_id, show=True):
    global dataDir
    I = Image.open('%s/%s/%s' % (dataDir, dataset, img['file_name']))# 通过id,得到注释的信息
    annIds = coco.getAnnIds(imgIds=img['id'], catIds=cls_id, iscrowd=None)
    anns = coco.loadAnns(annIds)
    # coco.showAnns(anns)
    objs = []
    for ann in anns:
        class_name = classes[ann['category_id']]
        if class_name in classes_names:
            if 'bbox' in ann:
                bbox = ann['bbox']
                xmin = int(bbox[0])
                ymin = int(bbox[1])
                xmax = int(bbox[2] + bbox[0])
                ymax = int(bbox[3] + bbox[1])
                obj = [class_name, xmin, ymin, xmax, ymax]
                objs.append(obj)
 
    return objs

for dataset in datasets_list:
    # ./COCO/annotations/instances_train2014.json
    annFile = '{}/annotations/instances_{}.json'.format(dataDir, dataset)
 
    # COCO API for initializing annotated data
    coco = COCO(annFile)
    '''
    COCO 对象创建完毕后会输出如下信息:
    loading annotations into memory...
    Done (t=0.81s)
    creating index...
    index created!
    至此, json 脚本解析完毕, 并且将图片和对应的标注数据关联起来.
    '''
    # show all classes in coco
    classes = id2name(coco)
    print(classes)
    # [1, 2, 3, 4, 6, 8]
    classes_ids = coco.getCatIds(catNms=classes_names)
    print(classes_ids)
    for cls in classes_names:
        # Get ID number of this class
        cls_id = coco.getCatIds(catNms=[cls])
        img_ids = coco.getImgIds(catIds=cls_id)
        # imgIds=img_ids[0:10]
        for imgId in tqdm(img_ids):
            img = coco.loadImgs(imgId)[0]
            filename = img['file_name']
            objs = showimg(coco, dataset, img, classes, classes_ids, show=False)
            save_annotations_and_imgs(coco, dataset, filename, objs)

out_img_base = 'VOCData/images'
out_xml_base = 'VOCData/Annotations'
img_base = 'VOCData/images/'
xml_base = 'VOCData/Annotations/'

if not os.path.exists(out_img_base):
    os.mkdir(out_img_base)

if not os.path.exists(out_xml_base):
    os.mkdir(out_xml_base)

for img in tqdm(os.listdir(img_base)):
    xml = img.replace('.jpg', '.xml')
    src_img = os.path.join(img_base, img)
    src_xml = os.path.join(xml_base, xml)
    dst_img = os.path.join(out_img_base, img)
    dst_xml = os.path.join(out_xml_base, xml)
    if os.path.exists(src_img) and os.path.exists(src_xml):
        move(src_img, dst_img)
        move(src_xml, dst_xml)

def extract_xml(infile):

    with open(infile,'r') as f:  #解析xml中的name标签
        xml_text = f.read()
        root = ET.fromstring(xml_text)
        classes = []
        for obj in root.iter('object'):
            cls_ = obj.find('name').text
            classes.append(cls_)
        return classes


if __name__ == '__main__':
    base = 'VOCData/Annotations/'
    Xmls=[]
    # Xmls = sorted([v for v in os.listdir(base) if v.endswith('.xml')]) 
    for v in os.listdir(base):
        if v.endswith('.xml'):
            Xmls.append(str(v))
    # iterable -- 可迭代对象。key -- 主要是用来进行比较的元素,只有一个参数,具体的函数的参数就是取自于可迭代对象中,指定可迭代对象中的一个元素来进行排序。reverse -- 排序规则,reverse = True 降序 , reverse = False 升序(默认)。
    print('-[INFO] total:', len(Xmls))
    # print(Xmls)

    labels = {'person': 0}

    for xml in Xmls:
        infile = os.path.join(base, xml)
        # print(infile)

        cls_ = extract_xml(infile)
        for c in cls_:
            if not c in labels:
                print(infile, c)
                raise
            labels[c] += 1

    for k, v in labels.items():
        print('-[Count] {} total:{} per:{}'.format(k, v, v/len(Xmls)))

2.2按VOC格式划分数据集,train : val = 0.85 : 0.15生成标签label_list.txt

"""
按VOC格式划分数据集,train : val = 0.85 : 0.15
生成标签label_list.txt
"""
import os
import shutil
import skimage.io as io

from tqdm import tqdm
from random import shuffle

dataset = 'dataset/VOCData/'
train_txt = os.path.join(dataset, 'train_val.txt')
val_txt = os.path.join(dataset, 'val.txt')
lbl_txt = os.path.join(dataset, 'label_list.txt')

classes = [
        "person"
    ]

with open(lbl_txt, 'w') as f:
    for l in classes:
        f.write(l+'\n')

xml_base = 'Annotations'
img_base = 'images'

xmls = [v for v in os.listdir(os.path.join(dataset, xml_base)) if v.endswith('.xml')]
shuffle(xmls)

split = int(0.85 * len(xmls)) #划分训练集与验证集

with open(train_txt, 'w') as f:
    for x in tqdm(xmls[:split]):
        m = x[:-4]+'.jpg'
        xml_path = os.path.join(xml_base, x)
        img_path = os.path.join(img_base, m)
        f.write('{} {}\n'.format(img_path, xml_path))
    
with open(val_txt, 'w') as f:
    for x in tqdm(xmls[split:]):
        m = x[:-4]+'.jpg'
        xml_path = os.path.join(xml_base, x)
        img_path = os.path.join(img_base, m)
        f.write('{} {}\n'.format(img_path, xml_path))

2.2 自定义数据集进行训练

2.2.1 常见标注工具

  对于图像分类任务,我们只要将对应的图片是哪个类别划分好即可。对于检测任务和分割任务,目前比较流行的数据标注工具是labelimg、labelme,分别用于检测任务与分割任务的标注。

标注工具Github地址:

labelimg :https://github.com/tzutalin/labelImg

 labelme :https://github.com/wkentaro/labelme

PPOCRLabel: https://github.com/PaddlePaddle/PaddleOCR

三、数据处理方法

3.1 图像的本质

  我们常见的图片其实分为两种,一种叫位图,另一种叫做矢量图。如下图所示:

计算机视觉———— 训练数据获取与处理_第3张图片

位图的特点:

  •   由像素点定义一放大会糊

  •   文件体积较大

  •   色彩表现丰富逼真

计算机视觉———— 训练数据获取与处理_第4张图片

矢量图的特点:

  •   超矢量定义

  •   放太不模糊

  •   文件体积较小

  •   表现力差

 3.2 数据增强手段

import paddle
import paddlex as pdx
import numpy as np
import paddle.nn as nn
import paddle.nn.functional as F
import PIL.Image as Image
import cv2 
import os

from random import shuffle
from paddlex.det import transforms as T
from PIL import Image, ImageFilter, ImageEnhance

import matplotlib.pyplot as plt # plt 用于显示图片

path='dataset/MaskCOCOData/JPEGImages/maksssksksss195.png'
img = Image.open(path)
plt.imshow(img)          #根据数组绘制图像
plt.show()               #显示图像


# 灰度图
img = np.array(Image.open(path).convert('L'), 'f')
plt.imshow(img,cmap="gray")          #根据数组绘制图像
plt.show()               #显示图像

#小Tips:jupyter notebook中plt显示灰度图异常,需要使用plt.imshow(gray,cmap="gray")方法正常显示灰度图。

img = cv2.imread(path)
plt.subplot(221)
plt.imshow(img,cmap="gray")
# matplotlib 按照RGB顺序展示原图
plt.imshow(cv2.cvtColor(img,cv2.COLOR_BGR2RGB)) 
plt.subplot(222)
# cv2默认的GBR显示图






def preprocess(dataType="train"):
    if dataType == "train":
        transform = T.Compose([
            T.MixupImage(mixup_epoch=10),   #对图像进行mixup操作,模型训练时的数据增强操作,目前仅YOLOv3模型支持该transform
            # T.RandomExpand(),        #随机扩张图像
            # T.RandomDistort(brightness_range=1.2, brightness_prob=0.3),       #以一定的概率对图像进行随机像素内容变换
            # T.RandomCrop(),          #随机裁剪图像
            # T.ResizeByShort(),  #根据图像的短边调整图像大小
            T.Resize(target_size=608, interp='RANDOM'),   #调整图像大小,[’NEAREST’, ‘LINEAR’, ‘CUBIC’, ‘AREA’, ‘LANCZOS4’, ‘RANDOM’]
            # T.RandomHorizontalFlip(),  #以一定的概率对图像进行随机水平翻转
            T.Normalize()  #对图像进行标准化
            ])
        return transform
    else:
        transform = T.Compose([
            T.Resize(target_size=608, interp='CUBIC'), 
            T.Normalize()
            ])
        return transform


train_transforms = preprocess(dataType="train")
eval_transforms  = preprocess(dataType="eval")



# 定义训练和验证所用的数据集
# API地址:https://paddlex.readthedocs.io/zh_CN/develop/data/format/detection.html?highlight=paddlex.det
train_dataset = pdx.datasets.VOCDetection(
    data_dir='./dataset/MaskVOCData',
    file_list='./dataset/MaskVOCData/train_list.txt',
    label_list='./dataset/MaskVOCData/label_list.txt',
    transforms=train_transforms,
    shuffle=True)
eval_dataset = pdx.datasets.VOCDetection(
    data_dir='./dataset/MaskVOCData',
    file_list='./dataset/MaskVOCData/val_list.txt',
    label_list='./dataset/MaskVOCData/label_list.txt',
    transforms=eval_transforms)
plt.imshow(img)
plt.subplot(223)
# 32*32的缩略图
plt.imshow(cv2.resize(img, (32, 32)))

#图像处理示例  目标视野里比较多重叠,或者有点模糊的适用 
path='dataset/MaskCOCOData/JPEGImages/maksssksksss443.png'
img = Image.open(path)
plt.imshow(img)        
plt.show()  


#锐化
img = img.filter(ImageFilter.SHARPEN)
img = img.filter(ImageFilter.SHARPEN)
plt.imshow(img)        
plt.show()          

#亮度变换
bright_enhancer = ImageEnhance.Brightness(img)    # 传入调整系数亮度
img = bright_enhancer.enhance(1.6)
plt.imshow(img)        
plt.show() 

#提高对比度
contrast_enhancer = ImageEnhance.Contrast(img)    # 传入调整系数对比度
img = contrast_enhancer.enhance(1.9)
plt.imshow(img)        
plt.show() 

 3.3 为什么做数据增强

是因为很多深度学习的模型复杂度太高了,且在数据量少的情况下,比较容易造成过拟合(通俗来说就是训练的这个模型它太沉浸在这个训练样本当中的一些特质上面了),表现为的这个模型呢受到了很多无关因素的影响。 所得出的结果就是在没有看到过的样本上对它做出预测呢就表现的不太好。

计算机视觉———— 训练数据获取与处理_第5张图片

四、模型训练与评估

import matplotlib
matplotlib.use('Agg') 
os.environ['CUDA_VISIBLE_DEVICES'] = '0'
%matplotlib inline
import warnings
warnings.filterwarnings("ignore")

#num_classes有些模型需要加1 比如faster_rcnn
num_classes = len(train_dataset.labels)

model = pdx.det.PPYOLO(num_classes=num_classes, )

model.train(
    num_epochs=70,
    train_dataset=train_dataset,
    train_batch_size=16,
    eval_dataset=eval_dataset,
    learning_rate=3e-5,
    warmup_steps=90,
    warmup_start_lr=0.0,
    save_interval_epochs=7,
    lr_decay_epochs=[42, 70],
    save_dir='output/PPYOLO',
    use_vdl=True)

你可能感兴趣的:(opencv,机器学习,python,计算机视觉,目标检测,人工智能)