TensorFlow学习(十):图像预处理



更新时间:

2018.6.2
增加了通过 tf.image 进行数据增强的内容,非常重要,可以直接跳到第四节。

之前做的一些任务都是从.csv文件里面读取数据来处理,这些元素都已经是处理好的值了,所以很方便。但是更多时候,我们是要从硬盘上的图片直接来做处理,所以,这里需要用到一些基本的图像处理有关的函数了。OpenCV肯定是可以使用的,但是tensorflow本身也提供了一些好用的函数。
因为通过Tensorflow完成图像有关的任务太多了,所以了解一点Tensorflow中自带的图像处理有关的函数是很有必要的。
Tensorflow中内置的图像处理的函数肯定没有OpenCV那么多那么强大啦,但是仅仅是作为简单的预处理的话,完全是够用了。

主要使用的模块就是tf.image,所以首先要是先把官方文档列出来:Module: tf.image,然后接下来就是按照图片处理的顺序来分别讲解各个函数的使用。
本节的完整测试代码,可以在我的GitHub:LearningTensorFlow/12.ImageProcess/上找到。

一.图像的编解码

Ⅰ.概览

下面是tensorflow自带编解码部分的函数,这里一起列出来,但是并不会全部都详细讲,因为使用方式大同小异,在例子中只是详细讲其中一个,其他的都可以类比或者看文档写出来,实在是很简单,就不需要多花笔墨。

decode_gif(…): Decode the first frame of a GIF-encoded image to a uint8 tensor.
decode_jpeg(…): Decode a JPEG-encoded image to a uint8 tensor.
decode_png(…): Decode a PNG-encoded image to a uint8 or uint16 tensor.
decode_image(…): Convenience function for decode_gif, decode_jpeg, and decode_png.
encode_jpeg(…): JPEG-encode an image.
encode_png(…): PNG-encode an image.

在这一步,要是只是想把某个或者某些个文件读到ndarray中去,推荐更加高效的做法,就是使用matplot.image中的imread()方法,或者opencv中的方法,都是很简单无脑的。
比如在这里,我文件夹下面有个叫做“1.jpg”的文件,那么就可以用比较简单的方法得到:
这里写图片描述

二.数据转化和形状变换

这一步的目的是什么呢?首先,很多图像像素默认是int类型的,在tensorflow里面,float类型的数据更加适合处理,然后形状来说,我们知道,对于图片来说,一个网络的输入尺寸是固定的,而训练的时候图片的尺寸确不一定是固定的,所以有必要用各种方式把图片尺寸转换为固定的适合网络输入的格式。

Ⅰ.数据类型转化

convert_image_dtype(image,dtype,saturate=False,name=None)

作用:把图片元素类型,转成想要的类型,返回转换后的图片,注意,要是转成了float类型之后,像素值会在 [0,1)这个范围内
参数:
image: 图像
dtype: 待转换类型
saturate: If True, clip the input before casting (if necessary).
name: 可选操作名

with graph.as_default():
    #convert type
    pic=tf.image.convert_image_dtype(image=pic,dtype=tf.float32)
with session.as_default():
    pic_run=session.run(pic)
    print("type of pic:",pic_run.dtype)
    print(pic_run)
    plt.imshow(pic_run)

结果:
这里写图片描述

Ⅱ.形状变换

resize_images(images,size,method=ResizeMethod.BILINEAR,align_corners=False)

作用:使用指定的方法来改变形状
参数:
images: 4维tensor,形状为 [batch, height, width, channels] 或者3维tensor,形状为 [height, width, channels].
size: 1维 int32类型的 Tensor,包含两个元素:new_height, new_width.
method: 改变形状的方法,默认是ResizeMethod.BILINEAR.

ResizeMethod.BILINEAR: 双线性插值(Bilinear interpolation.)
ResizeMethod.NEAREST_NEIGHBOR: 最近邻插值(Nearest neighbor interpolation.)
ResizeMethod.BICUBIC: 双三次插值(Bicubic interpolation.)
ResizeMethod.AREA: 面积插值(Area interpolation.)

align_corners: bool. If true, exactly align all 4 corners of the input and output. Defaults to false.

还有其他类似的函数带有剪裁和形状改变的功能,,如

resize_image_with_crop_or_pad(…): Crops and/or pads an image to a target width and height.
central_crop(…): Crop the central region of the image.
crop_and_resize(…): Extracts crops from the input image tensor and bilinearly resizes them (possibly
crop_to_bounding_box(…): Crops an image to a specified bounding box.

因为使用上面差不多,所以就不一个个详细介绍了,可以看文档,选择合适的方法来使用.

Ⅲ.图像翻转

上面介绍了尺寸的问题,然后就是翻转的问题了.为什么要翻转呢?以这幅图为例:
这里写图片描述
神经网络其实是很”笨”的,要是你提供的图片都是像上面那样朝向左边,那么当出现一幅朝向右边的图片的时候,它很可能无法识别.
所以,可以人为的多加一些翻转上去,使得各个角度的图片都有一点,无形中,扩充了数据量,还缓解了识别错误的问题.
翻转有一些常见的函数,

flip_left_right(…): 左右翻转
flip_up_down(…): 上下翻转
transpose_image(…): 对角线翻转
random_flip_left_right(…): 随机左右翻转
random_flip_up_down(…): 随机上下翻转

同样,使用方法都是差不多的,这里值以第一个为例子,其他的类比使用就行了.
flip_left_right(image)

作用:左右翻转一幅图片,返回一个形状和原图片相同的图片(翻转后)
参数:
image: 3维tensor,形状为[height, width, channels].

这里写图片描述

三.颜色变换

和前面使用翻转可以来”增加数据集”以外,调节颜色属性也是同样很有用的方法,这里主要有调整亮度,对比度,饱和度,色调等方法.如下:
亮度:

adjust_brightness(…): 调整亮度
random_brightness(…): 随机调整亮度

对比度:

adjust_contrast(…): 调整对比度
random_contrast(…): 随机调整亮度

饱和度:

adjust_saturation(…): 调整饱和度
random_saturation(…): 随机调整饱和度

色调:

adjust_hue(…): 调整色调
random_hue(…): 随机调整色调

这里只举一个调节亮度的例子,其他大同小异,可以试一下看结果
adjust_brightness(image,delta)

作用:调节亮度
参数:
image: tensor,原图片
delta: 标量,待加到像素值上面的值.

这里写图片描述

四.数据增强相关

数据增强的作用就不多说了,tensorflow的数据预处理部分也给出了一些数据增强的方法,表面上看上去也许只是普通的图片变换,但是这些方法在一方面来说能够非常有效的扩充“数据集”。
这几个方法就是tf.image里面带有random的一些方法。也就是随机怎样怎样,上面其实已经列国了,这里再列出来一遍,大家可以根据需要来选择可能用到的.

random_brightness(…): Adjust the brightness of images by a random factor.

random_contrast(…): Adjust the contrast of an image by a random factor.

random_flip_left_right(…): Randomly flip an image horizontally (left to right).

random_flip_up_down(…): Randomly flips an image vertically (upside down).

random_hue(…): Adjust the hue of an RGB image by a random factor.

random_saturation(…): Adjust the saturation of an RGB image by a random factor.

本节只详细介绍三个非常有用的的函数,两个是翻转图像的,分别是random_flip_left_right(...)random_flip_up_down(...) 看名字就知道是左右翻转和上下翻转,还有一个是tf.image.sample_distorted_bounding_box 是随机截取图像。

tf.image.sample_distorted_bounding_box(image_size,bounding_boxes,seed=Noneseed2=None,min_object_covered=0.1,aspect_ratio_range=None,area_range=None,max_attempts=None,use_image_if_no_bounding_boxes=None,name=None)

Generate a single randomly distorted bounding box for an image.

Bounding box annotations are often supplied in addition to ground-truth labels in image recognition or object localization tasks. A common technique for training such a system is to randomly distort an image while preserving its content, i.e. data augmentation. This Op outputs a randomly distorted localization of an object, i.e. bounding box, given an image_size, bounding_boxes and a series of constraints.

The output of this Op is a single bounding box that may be used to crop the original image. The output is returned as 3 tensors: begin, size and bboxes. The first 2 tensors can be fed directly into tf.slice to crop the image. The latter may be supplied to tf.image.draw_bounding_boxes to visualize what the bounding box looks like.

Bounding boxes are supplied and returned as [y_min, x_min, y_max, x_max]. The bounding box coordinates are floats in [0.0, 1.0] relative to the width and height of the underlying image.

For example,

# Generate a single distorted bounding box.
begin, size, bbox_for_draw = tf.image.sample_distorted_bounding_box(
    tf.shape(image),
    bounding_boxes=bounding_boxes,
    min_object_covered=0.1)

# Draw the bounding box in an image summary.
image_with_box = tf.image.draw_bounding_boxes(tf.expand_dims(image, 0),
                                              bbox_for_draw)
tf.summary.image('images_with_box', image_with_box)

# Employ the bounding box to distort the image.
distorted_image = tf.slice(image, begin, size)

Note that if no bounding box information is available, setting use_image_if_no_bounding_boxes = true will assume there is a single implicit bounding box covering the whole image. If use_image_if_no_bounding_boxes is false and no bounding boxes are supplied, an error is raised.

Args:
image_size: A Tensor. Must be one of the following types: uint8, int8, int16, int32, int64. 1-D, containing [height, width, channels].
bounding_boxes: A Tensor of type float32. 3-D with shape [batch, N, 4] describing the N bounding boxes associated with the image.
seed: An optional int. Defaults to 0. If either seed or seed2 are set to non-zero, the random number generator is seeded by the given seed. Otherwise, it is seeded by a random seed.
seed2: An optional int. Defaults to 0. A second seed to avoid seed collision.
min_object_covered: A Tensor of type float32. Defaults to 0.1. The cropped area of the image must contain at least this fraction of any bounding box supplied. The value of this parameter should be non-negative. In the case of 0, the cropped area does not need to overlap any of the bounding boxes supplied.
aspect_ratio_range: An optional list of floats. Defaults to [0.75, 1.33]. The cropped area of the image must have an aspect ratio = width / height within this range.
area_range: An optional list of floats. Defaults to [0.05, 1]. The cropped area of the image must contain a fraction of the supplied image within in this range.
max_attempts: An optional int. Defaults to 100. Number of attempts at generating a cropped region of the image of the specified constraints. After max_attempts failures, return the entire image.
use_image_if_no_bounding_boxes: An optional bool. Defaults to False. Controls behavior if no bounding boxes supplied. If true, assume an implicit bounding box covering the whole input. If false, raise an error.
name: A name for the operation (optional).
Returns:
A tuple of Tensor objects (begin, size, bboxes).

begin: A Tensor. Has the same type as image_size. 1-D, containing [offset_height, offset_width, 0]. Provide as input to tf.slice.
size: A Tensor. Has the same type as image_size. 1-D, containing [target_height, target_width, -1]. Provide as input to tf.slice.
bboxes: A Tensor of type float32. 3-D with shape [1, 1, 4] containing the distorted bounding box. Provide as input to tf.image.draw_bounding_boxes.