图像预处理
通过对图像的预处理,可以尽量避免模型受到无关因素的影响。在大部分图像识别问题中,通过图像预处理过程可以提高模型的准确率
图像预处理有很多过程。这里只介绍函数。方便使用。
- 图像读取原始
- tf.gfile.FastGFile().read()
- 图像格式的编码解码 :图像不直接记录图像上的不同位置,不同颜色的亮度。而是记录压缩编码之后的结果。所以要还原成三维矩阵,需要解码。
- tf.image.decode_jpeg()
- tf.image.encode_jpeg()
- 转换函数 tf.image.convert_image_dtype
- 图像大小调整
- tf.image.resize_images(image,[size],method)
- method 0:双线性插值 1:最近邻居法 2: 双三次插值法 3:面积差值法
- 对于图像缩放算法来说,最近临插值算法是最简单的。最近临插值算法的原理是在原图像中找到最近临的一个点,然后把这个点的像素值插入到目标图像中,最近临插值算法优点是算法简单,易于实现,但是缺点是由于相邻像素点的像素值相同,容易出现色块现象。
那么如何在原图像中找这个目标点呢,算法公式如下:
src_x = dst_x * (src_width / dst_width); src_y = dst_y * (src_height / dst_height);
那么算出来呢,可能会是小数点,需要四舍五入取整,那么下面来看一个例子(一个3*3的矩阵):
234 38 22 67 44 12 89 65 63
这里呢,我们需要将上面的一个3*3矩阵变换成一个4*4的矩阵,我们根据上面的公式来计算一下,首先是目标点为(0,0),那么原图像的坐标点为(0,0),那么这个坐标点的值就应该为234,然后再来看(0,1)这个坐标点,那么纵坐标点还是0,但是横坐标点变成了1*(3/4) = 0.75,四舍五入得1,那么得到的原图像坐标为(0,1),那么这个坐标点值就应该为38,同理,最后得到的矩阵结果如下:
234 38 22 22 67 44 12 12 89 65 63 63 89 65 63 63
- tf.image.resize_image_with_crop_pad 自动裁剪或者填充
- 图像翻转
- tf.image.flip_up_down()
- tf.image.filp_left_right()
- tf.image.transpose_image()
- 图像色彩调整
- 亮度调整 tf.image.adjust_brightness(image,brightness)
- 随机亮度调整 tf.image.random_brightness(image,max_delta)
- 同理调整,tf.image.adjust_contrast,tf.image.adjust_hue,tf.image.
saturation. - 图像标准化 tf.image.per_image_whitening(image)
标注框
- tf.image.draw_bounding_boxes(batch,boxes) 这个函数要求图像矩阵的数字为实数,而且输入是一个batch的数据,即多张图像组成的四维矩阵,所以将编码后的图像矩阵加一维。
- tf.expand_dims() 这个加的维度大家自己要看api去理解
tf.image.sample_distorted_bounding_box(size,boxes) 随机截取图像信息
随机翻转图像,随机调整颜色,随机截图图像中的有信息含量的部分,这些事提高模型健壮性的一种方式。这样可以使是训练得到的模型不受被识别物体大小的影响。
下面贴出完整代码:
'''编码与解码 图像解码与编码:一张RGB三通道的彩色图像可以看成一个三维矩阵,矩阵中的不位置上的数字代表图像的像素值。 然后图像在存储时并不是直接记录这些矩阵中的数字,而是经过了压缩编码。 所以将一张图像还原成一个三维矩阵的过程就是解码的过程,反之就是编码了。 其实如果大家熟悉opencv的话,imread和imwrite就是一个解码和编码的过程。 TensorFlow提供了常用图片格式的解码和编码操作,下面用一个jpeg的图像演示:''' import matplotlib.pyplot as plt import tensorflow as tf plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签 #tf.gfile.FastGFile读取或保存图像文件 image_raw_data = tf.gfile.FastGFile("lena.jpeg",'rb').read() with tf.Session() as sess: #图形解码(可以解码jpeg, png,编码为encode_jpeg) img_data = tf.image.decode_jpeg(image_raw_data) print(img_data.eval()) plt.imshow(img_data.eval()) plt.title('原图') plt.show()
#图像大小调整 import numpy as np with tf.Session() as sess: #设定图片大小,method有4种插值,0-双线性插值 1-最近邻居法 2-双三次插值法 3-面积差值法 resized = tf.image.resize_images(img_data, [300, 300], method=0) print("Digital dtype: %s" % resized.dtype) # TensorFlow的函数处理图片后存储的数据是float32格式的,需要转换成uint8才能正确打印图片。 lena = np.asarray(resized.eval(), dtype="uint8") print(resized.get_shape()) plt.imshow(lena) plt.title('调整大小到[300,300]') plt.show()
#图形剪切或填充 with tf.Session() as sess: #自动裁剪或者填充(都是操作图片中间部分) croped = tf.image.resize_image_with_crop_or_pad(img_data, 300,200) padded = tf.image.resize_image_with_crop_or_pad(img_data, 700, 500) # 按比例调整图像大小,第二个参数为(0,1]的实数。 center_crop=tf.image.central_crop(img_data, 0.5) #裁剪给定区域{起点高度,起点宽度,框高,框宽} crop_to_bounding_box=tf.image.crop_to_bounding_box(img_data,0,0,200,300) plt.imshow(croped.eval()) # 填充给定区域 pad_to_bounding_box=tf.image.pad_to_bounding_box(img_data,0,0,200,300) plt.title('cropped') plt.show() plt.imshow(padded.eval()) plt.title('padded') plt.show() plt.imshow(center_crop.eval()) plt.title('center_crop') plt.show() plt.imshow(crop_to_bounding_box.eval()) plt.title('crop_to_bounding_box') plt.show() plt.imshow(pad_to_bounding_box.eval()) plt.title('pad_to_bounding_box') plt.show()
#图形翻转变换 with tf.Session() as sess: #上下翻转 flipped = tf.image.flip_up_down(img_data) #左右反转 flipped1 = tf.image.flip_left_right(img_data) #对角翻转 transposed = tf.image.transpose_image(img_data) plt.imshow(flipped.eval()) plt.title('上下翻转') plt.show() plt.imshow(flipped1.eval()) plt.title('左右反转') plt.show() plt.imshow(transposed.eval()) plt.title('对角翻转') plt.show()
#调整亮度 with tf.Session() as sess: #亮度调整 adjusted = tf.image.adjust_brightness(img_data, -0.5) adjusted1 = tf.image.adjust_brightness(img_data, 0.5) #随机亮度调整 adjusted2 = tf.image.random_brightness(img_data, max_delta=0.5) plt.imshow(adjusted.eval()) plt.title('亮度调整-0.5') plt.show() plt.imshow(adjusted1.eval()) plt.title('亮度调整+0.5') plt.show() plt.imshow(adjusted2.eval()) plt.title('随机亮度调整') plt.show()
#调整对比度 with tf.Session() as sess: #对比度调整 adjusted = tf.image.adjust_contrast(img_data, -5) adjusted1 = tf.image.adjust_contrast(img_data, 5) #随机调整对比度 adjusted2 = tf.image.random_contrast(img_data, 0,5) plt.imshow(adjusted.eval()) plt.title('对比度-5') plt.show() plt.imshow(adjusted1.eval()) plt.title('对比度+5') plt.show() plt.imshow(adjusted2.eval()) plt.title('对比度随机调整,在[-max_delta,max_delta]范围内') plt.show()
#调整色相 with tf.Session() as sess: # 在[-maxdelta,maxdelta]范围内随机调整图像的色相 maxdelat 在0-0.5的范围内 adjusted3 = tf.image.random_hue(img_data, max_delta=0.4) plt.imshow(adjusted.eval()) plt.title('调整色相') plt.show()
#调整饱和度 with tf.Session() as sess: adjusted = tf.image.adjust_saturation(img_data, -5) adjusted1 = tf.image.adjust_saturation(img_data, 5) adjusted2 = tf.image.random_saturation(img_data,3,7) plt.imshow(adjusted2.eval()) plt.title('调整饱和度') plt.show()
#处理标注框 with tf.Session() as sess: boxes = tf.constant([[[0.05, 0.05, 0.9, 0.7],[0.35,0.47,0.5,0.56]]]) begin, size, bbox_for_draw = tf.image.sample_distorted_bounding_box(tf.shape(img_data), bounding_boxes=boxes) # 通过标注框可视化随机截取得到的图像 batched = tf.expand_dims(tf.image.convert_image_dtype(img_data, tf.float32), 0) image_with_box = tf.image.draw_bounding_boxes(batched, bbox_for_draw) plt.imshow(image_with_box[0].eval()) plt.title('通过标注框可视化随机截取得到的图像') plt.show() # 截取随机出来的图像,因为算法带有随机成分,所以每次的结果都可能不相同 distorted_image = tf.slice(img_data, begin, size) plt.imshow(distorted_image.eval()) plt.title('截取出来的图像') plt.show()