tensorflow 按區域提取實例
需求
- 輸入一張圖片,按照規定正方形尺寸(如30*30 像素) 對輸入圖片進行提取,類似於口 ,田兩個文字 一張圖變成四張,四張圖能夠變成一張圖。
數據與思路
數據資源
-
輸入圖爲534*300
-
提取尺寸爲30*30
思路
-
根據輸入情況來看 534 不能夠被30 整除,需要對534這個寬度進行調整 。300則被30整除不需要進行特殊處理。
- 遇到除不盡的處理方式 : (被提取圖片的寬度或高度 // 提取尺寸 +1 )* 提取尺寸
-
經過第一步操作得到一個新的尺寸 , (540,300) 我們需要將原尺寸填充到這個尺寸中。tensorflow 內置了這個功能 , **tf.image.resize_image_with_crop_or_pad ** 這個函數的作用是將一個圖片填充到一個新的尺寸中,且兩個圖的中心不變。
- 上圖中紅色部分爲經過 **tf.image.resize_image_with_crop_or_pad **處理後的圖形尺寸,白色部分爲原始尺寸。
-
經過第二部獲得一張新的圖片,我們最終操作的也就是這個圖片 , 所使用的函數 tf.image.crop_to_bounding_box
def crop_to_bounding_box(image, offset_height, offset_width, target_height,target_width): """ image = 圖片內容 offset_height = 開始的h offset_width = 開始的w target_height 縱向位移長度 target_width 橫向位移長度 """
最終需要計算下圖中綠色的角點位置作爲 offset_height , offset_width 的參數,target_height , target_width 則是提取尺寸
-
保存數據
- 使用 imageio 庫進行保存,**imageio.imwrite(“保存地址”, tf.eval()) 這就保存完成 **
代碼以及結果
#! /usr/bin/env python
# -*- coding: utf-8 -*-
# __file__: huifer
import tensorflow as tf
import imageio
from PIL import Image
import os
BASE_PATH = os.path.join(os.path.abspath(os.curdir), 'data')
BASE_PATH_res = os.path.join(os.path.abspath(os.curdir), 'result')
def get_pic_size(path):
"""
獲取圖片尺寸
:param path: 圖片路徑
:return: (高度,寬度)
"""
decode_jpeg_data = tf.placeholder(dtype=tf.string)
decode_jpeg = tf.image.decode_jpeg(decode_jpeg_data, channels=3)
image_data = tf.gfile.FastGFile(path, 'rb').read()
with tf.Session() as sess:
image = sess.run(decode_jpeg, feed_dict={decode_jpeg_data: image_data})
return (image.shape[0], image.shape[1])
def _size(pic, split):
"""
處理圖片尺寸 , 不能整除向上取一位
:param pic: 圖片的尺寸 ,寬度或者高度
:param split: 切割尺寸,寬度或者高度
:return: 圖片尺寸 ,寬度或者高度
"""
if pic % split == 0:
return pic
else:
return (pic // split + 1) * split
def get_new_size(pic_size, split_size):
"""
計算新的圖片尺寸
:param pic_size: 原始圖片尺寸(高,寬)
:param split_size: 切割圖片尺寸(高,寬)
:return:
"""
return (_size(pic_size[0], split_size[0]), _size(pic_size[1], split_size[1]))
def fill_pic(path, new_size, new_path):
"""
填充圖片到指定的新尺寸
:return:
"""
# tf.train.string_input_producer 接收參數是一個文件列表['1.jpg','2.jpg'] , 由於實際操作中可能多個每個圖片最後填充結果不一致,
# 所以在這個測試用例中直接將一個地址放在列表中
filename_queue = tf.train.string_input_producer([path])
reader = tf.WholeFileReader()
key, value = reader.read(filename_queue)
images = tf.image.decode_jpeg(value)
with tf.Session() as sess:
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(coord=coord)
# 填充圖片底色黑色
reshapeimg = tf.image.resize_image_with_crop_or_pad(images, new_size[0], new_size[1])
reimg1 = reshapeimg.eval()
imageio.imwrite(new_path, reimg1)
coord.request_stop()
coord.join(threads)
print('填充完成')
def split_pic(split_path, new_size, split_size):
"""
切圖
:param split_path:被切割圖片地址
:param new_size: 新的圖片尺寸(被切割圖片的尺寸)
:param split_size: 切割尺寸
:return:
"""
image_raw_data = tf.gfile.FastGFile(split_path, 'rb').read()
with tf.Session() as sess:
img_data = tf.image.decode_jpeg(image_raw_data)
for h in range(new_size[0] // split_size[0]):
for w in range(new_size[1] // split_size[1]):
# print(h * split_size[0], w * split_size[1])
s = tf.image.crop_to_bounding_box(image=img_data, offset_height=h * split_size[0],
offset_width=w * split_size[1],
target_height=split_size[0],
target_width=split_size[1])
reimage1 = s.eval()
imageio.imwrite("data/w={}h={}.jpg".format(w, h), reimage1)
print("切圖ok")
def merge_pic(x, y, picSize):
"""
合併下載地圖
:param x: x 範圍
:param y: y 範圍
:return:
"""
try:
# 構造平圖矩陣
li = []
for xi in x:
lis = []
for yi in y:
fileName = os.path.join(BASE_PATH, "w={}h={}.jpg".format(xi, yi))
lis.append(fileName)
li.append(lis)
oca = len(x)
ocb = len(y)
toImage = Image.new('RGBA', (oca * picSize[0], ocb * picSize[1]))
for i in range(oca):
for j in range(ocb):
fromImge = Image.open(li[i][j])
picx = picSize[0] * i
picy = picSize[1] * j
loc = (picx, picy)
toImage.paste(fromImge, loc)
toImage.save(os.path.join(BASE_PATH_res, "rs.png"))
print("構造完成輸出圖片")
except Exception as e:
print(e)
pass
def run():
"""
規則尺寸100*100 20*20 這類
:return:
"""
# 最原始的圖片(尺寸可能存在問題)
path = '1.jpg'
# 1. 獲取舊圖片的尺寸
old_pic_size = get_pic_size(path)
# 定義切割尺寸
split_size = (50, 50)
# 2. 將舊的圖片填充到能夠被自定義的切割尺寸整除的大小
# 新圖片的地址
new_path = "233.jpg"
# 計算新的圖片尺寸大小
new_size = get_new_size(old_pic_size, split_size)
# 填充開始
fill_pic(path, new_size, new_path)
# 切割圖片
split_pic(new_path, new_size, split_size)
# 合併圖片
merge_pic(x=range(new_size[1] // split_size[1]), y=range(new_size[0] // split_size[0]), picSize=split_size)
print("流程結束")
if __name__ == '__main__':
run()
pass
-
填充結果
-
切割結果
-
合併結果
注
本文代碼不支持 寬度高度不一樣的提取框