【TensorFlow学习笔记】目标识别篇(四):基于Tensorflow object detection API 打造属于自己的物体检测模型(填坑之路)


1、数据集准备

1.1 准备训练和验证数据集

1)本案采用的水杯识别,从公司办公座位拍了上百张水杯照片,当然网上很多物体的大量数据集,可自行选择下载并使用。

得到的训练集和测试集,分别在\models-master\research\object_detection\test_images文件夹下创建train和test文件夹,把对应的数据集拷贝进去。如下:
在这里插入图片描述

1.2 增强数据

但是我们只截取了大概800张左右的图,这个量级在训练时肯定是不够的,所以我们需要使用数据增强(无非是旋转加噪调量度)来增加我们的训练样本

相较于Augmentor,imgaug具有更多的功能,比如对影像增强的同时,对keypoint, bounding box进行相应的变换。例如在目标检测的过程中,训练集包括影像及其对应的bounding box文件,在对影像增强的时候,同时解算出bounding box 相应变换的坐标生成对应的bounding box文件。

  • 安装依赖库
pip install six numpy scipy matplotlib scikit-image opencv-python imageio
  • 安装imgaug

方式一(安装github最新版本):

pip install git+https://github.com/aleju/imgaug

方式二(安装pypi版本):

pip install imgaug

Bounding Boxes实现
读取原影像bounding boxes坐标
读取xml文件并使用ElementTree对xml文件进行解析,找到每个object的坐标值。

def change_xml_annotation(root, image_id, new_target):
new_xmin = new_target[0]
new_ymin = new_target[1]
new_xmax = new_target[2]
new_ymax = new_target[3]

in_file = open(os.path.join(root, str(image_id) + '.xml'))  # 这里root分别由两个意思
tree = ET.parse(in_file)
xmlroot = tree.getroot()
object = xmlroot.find('object')
bndbox = object.find('bndbox')
xmin = bndbox.find('xmin')
xmin.text = str(new_xmin)
ymin = bndbox.find('ymin')
ymin.text = str(new_ymin)
xmax = bndbox.find('xmax')
xmax.text = str(new_xmax)
ymax = bndbox.find('ymax')
ymax.text = str(new_ymax)
tree.write(os.path.join(root, str("%06d" % (str(id) + '.xml'))))

生成变换序列
产生一个处理图片的Sequential。

#影像增强
seq = iaa.Sequential([
iaa.Flipud(0.5), # vertically flip 20% of all images
iaa.Fliplr(0.5), # 镜像
iaa.Multiply((1.2, 1.5)), # change brightness, doesn’t affect BBs
iaa.GaussianBlur(sigma=(0, 3.0)), # iaa.GaussianBlur(0.5),
iaa.Affine(
translate_px={“x”: 15, “y”: 15},
scale=(0.8, 0.95),
rotate=(-30, 30)
) # translate by 40/60px on x/y axis, and scale to 50-70%, affects BBs
])
bounding box 变化后坐标计算
先读取该影像对应xml文件,获取所有目标的bounding boxes,然后依次计算每个box变化后的坐标。

seq_det = seq.to_deterministic() # 保持坐标和图像同步改变,而不是随机
#读取图片
img = Image.open(os.path.join(IMG_DIR, name[:-4] + ‘.jpg’))
#sp = img.size
img = np.asarray(img)
#bndbox 坐标增强
for i in range(len(bndbox)):
bbs = ia.BoundingBoxesOnImage([
ia.BoundingBox(x1=bndbox[i][0], y1=bndbox[i][1], x2=bndbox[i][2], y2=bndbox[i][3]),
], shape=img.shape)

bbs_aug = seq_det.augment_bounding_boxes([bbs])[0]
boxes_img_aug_list.append(bbs_aug)

# 此处运用了一个max,一个min (max是为了方式变化后的box小于1,min是为了防止变化后的box的坐标超出图片,在做faster r-cnn训练的时候,box的坐标会减1,若坐标小于1,就会报错,当然超出图像范围也会报错)
n_x1 = int(max(1, min(img.shape[1], bbs_aug.bounding_boxes[0].x1)))
n_y1 = int(max(1, min(img.shape[0], bbs_aug.bounding_boxes[0].y1)))
n_x2 = int(max(1, min(img.shape[1], bbs_aug.bounding_boxes[0].x2)))
n_y2 = int(max(1, min(img.shape[0], bbs_aug.bounding_boxes[0].y2)))
if n_x1 == 1 and n_x1 == n_x2:
    n_x2 += 1
if n_y1 == 1 and n_y2 == n_y1:
    n_y2 += 1
if n_x1 >= n_x2 or n_y1 >= n_y2:
    print('error', name)
new_bndbox_list.append([n_x1, n_y1, n_x2, n_y2])

#存储变化后的图片
image_aug = seq_det.augment_images([img])[0]
path = os.path.join(AUG_IMG_DIR,
str("%06d" % (len(files) + int(name[:-4]) + epoch * 250)) + ‘.jpg’)
image_auged = bbs.draw_on_image(image_aug, thickness=0)
Image.fromarray(image_auged).save(path)

#存储变化后的XML–此处可根据需要更改文件具体的名称
change_xml_list_annotation(XML_DIR, name[:-4], new_bndbox_list, AUG_XML_DIR,
len(files) + int(name[:-4]) + epoch * 250)
print(str("%06d" % (len(files) + int(name[:-4]) + epoch * 250)) + ‘.jpg’)
new_bndbox_list = []
使用示例
数据准备
输入数据为两个文件夹一个是需要增强的影像数据(JPEGImages),一个是对应的xml文件(Annotations)。注意:影像文件名需和xml文件名相对应!

Annotations

JPEGImages

设置文件路径
IMG_DIR = “…/create-pascal-voc-dataset/examples/VOC2007/JPEGImages”
XML_DIR = “…/create-pascal-voc-dataset/examples/VOC2007/Annotations”

AUG_XML_DIR = “./Annotations” # 存储增强后的XML文件夹路径
try:
shutil.rmtree(AUG_XML_DIR)
except FileNotFoundError as e:
a = 1
mkdir(AUG_XML_DIR)

AUG_IMG_DIR = “./JPEGImages” # 存储增强后的影像文件夹路径
try:
shutil.rmtree(AUG_IMG_DIR)
except FileNotFoundError as e:
a = 1
mkdir(AUG_IMG_DIR)
设置增强次数
AUGLOOP = 10 # 每张影像增强的数量
设置增强参数
通过修改Sequential函数参数进行设置,具体设置参考imgaug使用文档

seq = iaa.Sequential([
iaa.Flipud(0.5), # v翻转
iaa.Fliplr(0.5), # 镜像
iaa.Multiply((1.2, 1.5)), # 改变明亮度
iaa.GaussianBlur(sigma=(0, 3.0)), # 高斯噪声
iaa.Affine(
translate_px={“x”: 15, “y”: 15},
scale=(0.8, 0.95),
rotate=(-30, 30)
) # translate by 40/60px on x/y axis, and scale to 50-70%, affects BBs
])
输出
运行augmentation.py ,运行结束后即可得到增强的影像和对应的xml文件夹

import xml.etree.ElementTree as ET
import pickle
import os
from os import getcwd
import numpy as np
from PIL import Image
import shutil
import matplotlib.pyplot as plt

import imgaug as ia
from imgaug import augmenters as iaa


ia.seed(1)


def read_xml_annotation(root, image_id):
    in_file = open(os.path.join(root, image_id))
    tree = ET.parse(in_file)
    root = tree.getroot()
    bndboxlist = []

    for object in root.findall('object'):  # 找到root节点下的所有country节点
        bndbox = object.find('bndbox')  # 子节点下节点rank的值

        xmin = int(bndbox.find('xmin').text)
        xmax = int(bndbox.find('xmax').text)
        ymin = int(bndbox.find('ymin').text)
        ymax = int(bndbox.find('ymax').text)
        # print(xmin,ymin,xmax,ymax)
        bndboxlist.append([xmin, ymin, xmax, ymax])
        # print(bndboxlist)

    bndbox = root.find('object').find('bndbox')
    return bndboxlist


# (506.0000, 330.0000, 528.0000, 348.0000) -> (520.4747, 381.5080, 540.5596, 398.6603)
def change_xml_annotation(root, image_id, new_target):
    new_xmin = new_target[0]
    new_ymin = new_target[1]
    new_xmax = new_target[2]
    new_ymax = new_target[3]

    in_file = open(os.path.join(root, str(image_id) + '.xml'))  # 这里root分别由两个意思
    tree = ET.parse(in_file)
    xmlroot = tree.getroot()
    object = xmlroot.find('object')
    bndbox = object.find('bndbox')
    xmin = bndbox.find('xmin')
    xmin.text = str(new_xmin)
    ymin = bndbox.find('ymin')
    ymin.text = str(new_ymin)
    xmax = bndbox.find('xmax')
    xmax.text = str(new_xmax)
    ymax = bndbox.find('ymax')
    ymax.text = str(new_ymax)
    tree.write(os.path.join(root, str("%06d" % (str(id) + '.xml'))))


def change_xml_list_annotation(root, image_id, new_target, saveroot, id):
    in_file = open(os.path.join(root, str(image_id) + '.xml'))  # 这里root分别由两个意思
    tree = ET.parse(in_file)
    elem = tree.find('filename')
    elem.text = (str("%06d" % int(id)) + '.jpg')
    tree.find('path').text = (saveroot+'/'+ str("%06d" % int(id)) + '.jpg')  #  change file path to rot degree name
    xmlroot = tree.getroot()
    index = 0

    for object in xmlroot.findall('object'):  # 找到root节点下的所有country节点
        bndbox = object.find('bndbox')  # 子节点下节点rank的值

        # xmin = int(bndbox.find('xmin').text)
        # xmax = int(bndbox.find('xmax').text)
        # ymin = int(bndbox.find('ymin').text)
        # ymax = int(bndbox.find('ymax').text)

        new_xmin 
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我会尽力回答你的问题。对于您的问题,我理解您想问我如何调用U-NET模型,以下是我给出的回答。 首先,U-NET模型是一个用于图像分割的深度学习模型,它使用卷积神经网络来学习图像中不同区域的特征,并将它们分割成不同的类别。在TensorFlow 2.0中,我们可以使用tf.keras API来实现U-NET模型。 以下是一个简单的U-NET模型的实现代码: ```python import tensorflow as tf from tensorflow.keras.layers import * def conv_block(inputs, filters, kernel_size=(3, 3), activation='relu', padding='same'): x = Conv2D(filters, kernel_size, activation=activation, padding=padding)(inputs) x = BatchNormalization()(x) x = Conv2D(filters, kernel_size, activation=activation, padding=padding)(x) x = BatchNormalization()(x) return x def unet(input_shape=(256, 256, 3)): inputs = Input(shape=input_shape) c1 = conv_block(inputs, 64) p1 = MaxPooling2D((2, 2))(c1) c2 = conv_block(p1, 128) p2 = MaxPooling2D((2, 2))(c2) c3 = conv_block(p2, 256) p3 = MaxPooling2D((2, 2))(c3) c4 = conv_block(p3, 512) p4 = MaxPooling2D((2, 2))(c4) c5 = conv_block(p4, 1024) u6 = Conv2DTranspose(512, (2, 2), strides=(2, 2), padding='same')(c5) u6 = concatenate([u6, c4]) c6 = conv_block(u6, 512) u7 = Conv2DTranspose(256, (2, 2), strides=(2, 2), padding='same')(c6) u7 = concatenate([u7, c3]) c7 = conv_block(u7, 256) u8 = Conv2DTranspose(128, (2, 2), strides=(2, 2), padding='same')(c7) u8 = concatenate([u8, c2]) c8 = conv_block(u8, 128) u9 = Conv2DTranspose(64, (2, 2), strides=(2, 2), padding='same')(c8) u9 = concatenate([u9, c1]) c9 = conv_block(u9, 64) outputs = Conv2D(1, (1, 1), activation='sigmoid')(c9) model = tf.keras.Model(inputs=[inputs], outputs=[outputs]) return model ``` 在这个实现中,我们使用了Conv2D、BatchNormalization、MaxPooling2D和Conv2DTranspose等层来构建U-NET模型。我们还定义了一个conv_block函数来简化代码。 使用这个实现代码,我们可以通过以下方式调用U-NET模型: ```python model = unet() ``` 这将返回一个U-NET模型的实例,我们可以使用该实例来进行训练和预测。 希望这个回答对您有所帮助。如果您还有其他问题,请随时问我。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值