tensorflow - 圖像預處理


tensorflow 中自帶了很多圖像處理的方法,基本都在 tf.image 模塊中,雖然不如 opencv 強大,但也比較常用,這里做個記錄。

 

圖像編解碼

1. 用 tf 的方法讀取圖片后,都需要進行編解碼,才能在 tf 中繼續處理;

2. tf 提供了各種類型圖像的編解碼:decode_gif,decode_png,decode_jepg,decode_image,encode_png 等待,用法類似

tf.image.decode_png(contents, channels=0, dtype=_dtypes.uint8, name=None):channels 指定通道數

 

大體處理過程是:讀取--解碼--轉換成 np --喂給 sess

import tensorflow as tf
import matplotlib.pylab as plt

image = tf.gfile.FastGFile('pic/t4.png', 'rb').read()
print(type(image))      # <class 'bytes'>   格式顯然不對,需要解碼

image = tf.image.decode_png(image)  # 這里暫時沒有指定channels
print(type(image))      # <class 'tensorflow.python.framework.ops.Tensor'>  解碼完是 tensor,不能直接作為 sess.run 的輸入


tf.InteractiveSession()

image = image.eval()
print(type(image))      # <class 'numpy.ndarray'>   轉換成 np

print(image.shape)      # (620, 723, 4)  默認4個通道,不符合 tensorflow 的處理要求,在 decode_png 中可指定通道數為3,這里就變成3個通道了

print(image)            # 0-255 int

plt.imshow(image)
plt.show()

 

數據類型轉換

很多圖像的像素默認是int類型(如上例),但在 tf 中 float 更容易處理,而且 tf 很多函數輸出默認是 float,在 imshow 時會發生錯誤。

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

import matplotlib as mpl
import tensorflow as tf
import matplotlib.pylab as plt

mpl.rcParams['font.sans-serif']=['FangSong']        # 圖片上顯示中文

image = tf.gfile.FastGFile('pic/t4.png', 'rb').read()
image = tf.image.decode_png(image)

tf.InteractiveSession()

image1 = image.eval()
print(image1)           # 默認 0-255 int
# [[[255 247 245 255]
#   [255 248 245 255]


### 經過 tf 函數圖像處理后,無法imshow,因為輸出變成 0-255 float,imshow 只接受 0-1 float 和 0-255 int
image2 = tf.image.resize_images(image, [300, 300], method=0).eval()
print(image2)
# [[[255.   247.   245.   255.  ]
#   [254.   248.41 245.   255.  ]


### 需要進行 數據類型轉換,可以指定轉換類型
image3 = tf.image.convert_image_dtype(image, dtype=tf.float32)  # 這里指定轉成 0-1 float
print(image3)   # Tensor("convert_image:0", shape=(?, ?, ?), dtype=float32)

image4 = tf.image.resize_images(image3, [300, 300], method=0).eval()
print(image4)
# [[[1.         0.9686275  0.9607844  1.        ]
#   [0.9960785  0.9741569  0.9607844  1.        ]

# imshow with RGB data ([0..1] for floats or [0..255] for integers).
plt.subplot(131); plt.imshow(image1); plt.title('original')
plt.subplot(132); plt.imshow(image2); plt.title('不處理直接變形')
plt.subplot(133); plt.imshow(image4); plt.title('先轉換數據類型再變形')
plt.show()

輸出

 

圖像翻轉

包括上下翻轉、左右翻轉、90度翻轉,隨機翻轉,函數見代碼

tf.image.random_flip_left_right:隨機左右翻轉,概率為0.5

tf.image.random_flip_up_down:隨機上下翻轉,概率為0.5

#!/usr/bin/python
# coding:utf-8
import matplotlib.pyplot as plt
import tensorflow as tf

sess = tf.InteractiveSession()

# 讀取圖像數據
img = tf.gfile.FastGFile('./pic/t4.png', 'rb').read()   # 默認讀取是二進制,故必須進行解碼
img_data = tf.image.decode_png(img)

# 將圖像上下翻轉
flipped0 = tf.image.flip_up_down(img_data)
flipped0 = tf.image.convert_image_dtype(flipped0, dtype=tf.float32)     # 本例中此句可有可無

# 將圖像左右翻轉
flipped1 = tf.image.flip_left_right(img_data)
flipped1 = tf.image.convert_image_dtype(flipped1, dtype=tf.uint8)

# 通過交換第一維和第二維來轉置圖像
flipped2 = tf.image.transpose_image(img_data)   # 也就是轉90度,翻轉是轉180度

img_ori = img_data.eval()
print(img_ori.shape)        # (620, 723, 4)  4通道
print(img_ori)              # 0-255 int
plt.subplot(221); plt.imshow(img_ori); plt.title('original')
plt.subplot(222); plt.imshow(flipped0.eval()); plt.title('flip_up_down')
plt.subplot(223); plt.imshow(flipped1.eval()); plt.title('flip_left_right')
plt.subplot(224); plt.imshow(flipped2.eval()); plt.title('transpose_image')
plt.show()

輸出

 

尺寸變換

tf.image.resize_images:輸出為 float

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

methold 取值 決定 圖像大小調整算法

0 - 雙線性插值法(Bilinear interprolation)

1 - 最臨近插值法 (Nearest neighbor interprolation)

2 - 雙三次插值法 (Bicubic interprolation)

3 - 面積插值法 (Area interprolation)

import tensorflow as tf
import matplotlib.pylab as plt


image = tf.gfile.FastGFile('pic/t4.png', 'rb').read()
image = tf.image.decode_png(image, channels=3)              # 注意這里需要設定3通道,默認4通道
image = tf.image.convert_image_dtype(image, dtype=tf.float32)   # 這里變換是為了 imshow,轉換成 0-1 float

image_in = tf.placeholder(dtype=tf.float32, shape=[None, None, 3])

image_new_biliner = tf.image.resize_images(image_in, size=[300, 300], method=0)    # method=tf.image.ResizeMethod.BILINEAR
image_new_near = tf.image.resize_images(image_in, size=[300, 100], method=1)       # method=tf.image.ResizeMethod.NEAREST_NEIGHBOR
image_new_inter = tf.image.resize_images(image_in, [300, 100], method=2)           # method=tf.image.ResizeMethod.BICUBIC
image_new_area = tf.image.resize_images(image_in, [500, 200], method=3)            # method=tf.image.ResizeMethod.AREA

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    image = sess.run(image)
    image1, image2, image3, image4 = sess.run([image_new_biliner, image_new_near, image_new_inter, image_new_area],
                                       feed_dict={image_in: image})
    # print(image1)         輸出為 0-1 float
    plt.subplot(231); plt.imshow(image); plt.title('original')      # imshow with RGB data ([0..1] for floats or [0..255] for integers).
    plt.subplot(232); plt.imshow(image1); plt.title('biliner')
    plt.subplot(233); plt.imshow(image2); plt.title('near')
    plt.subplot(235); plt.imshow(image3); plt.title('inter')
    plt.subplot(236); plt.imshow(image4); plt.title('area')
    plt.show()

輸出

 

圖像裁剪

tf.image.crop_to_bounding_box(image, offset_height, offset_width, target_height, target_width):裁剪框裁剪

參數分別為:輸入圖像,裁剪起點縱坐標,裁剪起點橫坐標,裁剪高度,裁剪寬度

輸出為 float

import tensorflow as tf
import matplotlib.pyplot as plt


image = tf.gfile.FastGFile('pic/t4.png', 'rb').read()
image = tf.image.decode_png(image)
image = tf.image.convert_image_dtype(image, dtype=tf.float32)

image_in = tf.placeholder(dtype=tf.float32)     # 沒有設定shape=[None, None, 3]

image_crop1 = tf.image.crop_to_bounding_box(image_in, 100, 50, 80, 80)
image_crop2 = tf.image.crop_to_bounding_box(image_in, 100, 50, 400, 300)
image_crop3 = tf.image.crop_to_bounding_box(image_in, 0, 0, 300, 300)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

    image = sess.run(image)
    image1, image2, image3 = sess.run([image_crop1, image_crop2, image_crop3], feed_dict={image_in: image})
    plt.subplot(221); plt.imshow(image); plt.title('original')
    plt.subplot(222); plt.imshow(image1); plt.title('crop1')
    plt.subplot(223); plt.imshow(image2); plt.title('crop2')
    plt.subplot(224); plt.imshow(image3); plt.title('crop3')
    plt.show()

輸出

 

tf.image.resize_image_with_crop_pad(image, target_height, target_width):圖像中心不變,將圖像裁剪或填充至指定尺寸

import tensorflow as tf
import matplotlib.pylab as plt


image = tf.gfile.FastGFile('pic/t4.png', 'rb').read()
image = tf.image.decode_png(image)
image = tf.image.convert_image_dtype(image, dtype=tf.float32)

image_in = tf.placeholder(dtype=tf.float32)

crop = tf.image.resize_image_with_crop_or_pad(image_in, 400, 400)
pad = tf.image.resize_image_with_crop_or_pad(image_in, 1000, 1000)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

    image = sess.run(image)
    image1, image2 = sess.run([crop, pad], feed_dict={image_in: image})
    plt.subplot(131); plt.imshow(image); plt.title('original')
    plt.subplot(132); plt.imshow(image1); plt.title('crop')
    plt.subplot(133); plt.imshow(image2); plt.title('pad')
    plt.show()

輸出

 

tf.image.central_crop(image, central_fraction):以圖像中心為依據,按一定比例裁剪圖像

import matplotlib.pyplot as plt
import tensorflow as tf

img = tf.gfile.FastGFile('pic/t4.png', 'rb').read()

with tf.Session() as sess:
    img_data = tf.image.decode_png(img)

    # 函數tf.image.central_crop可以通過比例調整圖像的大小
    resized1 = tf.image.central_crop(img_data, 0.6)
    resized2 = tf.image.central_crop(img_data, 0.3)

    plt.subplot(131); plt.imshow(img_data.eval()); plt.title('original')
    plt.subplot(132); plt.imshow(resized1.eval()); plt.title('0.6')
    plt.subplot(133); plt.imshow(resized2.eval()); plt.title('0.3')
    plt.show()

輸出

 

 

色彩變換

包括調整亮度、對比度、色相、飽和度、規范化,函數見代碼

在指定范圍內隨機調整圖像的 亮度/對比度/色相/飽和度 

tf.image.random_brightness(img_data,max_delta) 

tf.image.random_contrast(img_data, lower, upper) 

tf.image.random_hue(img_data, max_delta) 

tf.image.random_saturation(img_data, lower, upper) 

隨機調整這些屬性,使訓練得到的模型盡可能小的受到無關因素的影響.

import matplotlib as mpl
import matplotlib.pyplot as plt
import tensorflow as tf

mpl.rcParams['font.sans-serif']=['FangSong']        # 圖片上顯示中文

# 讀取圖像數據
img = tf.gfile.FastGFile('pic/t4.png', 'rb').read()

with tf.Session() as sess:
    img_data = tf.image.decode_png(img, channels=3)

    adjusted0 = tf.image.adjust_brightness(img_data, -0.2)      # 將圖像的亮度-0.2
    adjusted1 = tf.image.adjust_contrast(img_data, +3)          # 將圖像的對比度+3
    adjusted2 = tf.image.adjust_hue(img_data, 0.2)              # 將圖像的色相+0.2
    adjusted3 = tf.image.adjust_saturation(img_data, 3)         # 將圖像的飽和度+3
    adjusted4 = tf.image.per_image_standardization(img_data)    # 將圖像線性縮放為零均值和單位范數

    plt.subplot(231), plt.imshow(img_data.eval()), plt.title('original')
    plt.subplot(232), plt.imshow(adjusted0.eval()), plt.title('adjust_brightness 亮度')
    plt.subplot(233), plt.imshow(adjusted1.eval()), plt.title('adjust_contrast 對比度')
    plt.subplot(234), plt.imshow(adjusted2.eval()), plt.title('adjust_hue 色相')
    plt.subplot(235), plt.imshow(adjusted3.eval()), plt.title('adjust_saturation 飽和度')
    plt.subplot(236), plt.imshow(adjusted4.eval()), plt.title('per_image_standardization 規范化')

    plt.show()

輸出

  

圖像增強

隨機圖像變換經常用於圖像增強

import tensorflow as tf
import os
import random

source_file = "./pic/"       #原始文件地址
target_file = "./pic2/"      #修改后的文件地址
num = 50                     #產生圖片次數

if not os.path.exists(target_file):  #如果不存在target_file,則創造一個
    os.makedirs(target_file)

file_list = os.listdir(source_file)   #讀取原始文件的路徑

with tf.Session() as sess:
    for i in range(num):
        # 每次隨機選一張
        a = random.randint(0, len(file_list)-1)          #隨機數字區間
        image_raw_data = tf.gfile.FastGFile(source_file+file_list[a],"rb").read() # 讀取圖片
        print("正在處理:",file_list[a])

        image_data = tf.image.decode_jpeg(image_raw_data)

        # 增強方式
        image_data = tf.image.random_crop(image_data, [100, 100, 3])    #隨機裁剪
        filpped_le_re = tf.image.random_flip_left_right(image_data)     #隨機左右翻轉
        filpped_up_down = tf.image.random_flip_up_down(image_data)      #隨機上下翻轉
        adjust = tf.image.random_brightness(filpped_up_down,0.4)        #隨機調整亮度
        adjust = tf.image.random_contrast(adjust, lower=0.2, upper=1.8) #隨機調整圖像對比度

        image_data = tf.image.convert_image_dtype(adjust,dtype=tf.uint8)

        encode_data = tf.image.encode_jpeg(image_data)

        with tf.gfile.GFile(target_file+str(i)+"_enhance"+".jpeg","wb") as f:
            f.write(encode_data.eval())

print("圖像增強完畢")

 

 

 

 

參考資料:

https://blog.csdn.net/xierhacker/article/details/72385422

https://blog.csdn.net/akadiao/article/details/78541763

https://www.cnblogs.com/Smnustudy/p/10704959.html#top


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM