tensorflow 按區域提取實例

tensorflow 按區域提取實例

需求

  • 輸入一張圖片,按照規定正方形尺寸(如30*30 像素) 對輸入圖片進行提取,類似於口 ,田兩個文字 一張圖變成四張,四張圖能夠變成一張圖。

數據與思路

數據資源

  1. 輸入圖爲534*300

    在這裏插入圖片描述

  2. 提取尺寸爲30*30

思路

  1. 根據輸入情況來看 534 不能夠被30 整除,需要對534這個寬度進行調整 。300則被30整除不需要進行特殊處理。

    1. 遇到除不盡的處理方式 : (被提取圖片的寬度或高度 // 提取尺寸 +1 )* 提取尺寸
  2. 經過第一步操作得到一個新的尺寸 , (540,300) 我們需要將原尺寸填充到這個尺寸中。tensorflow 內置了這個功能 , **tf.image.resize_image_with_crop_or_pad ** 這個函數的作用是將一個圖片填充到一個新的尺寸中,且兩個圖的中心不變。

    1557803159599

    • 上圖中紅色部分爲經過 **tf.image.resize_image_with_crop_or_pad **處理後的圖形尺寸,白色部分爲原始尺寸。
  3. 經過第二部獲得一張新的圖片,我們最終操作的也就是這個圖片 , 所使用的函數 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 則是提取尺寸

    1557803862915

  4. 保存數據

    • 使用 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
  • 填充結果

    在這裏插入圖片描述

  • 切割結果

    1557804046697

  • 合併結果

    在這裏插入圖片描述

本文代碼不支持 寬度高度不一樣的提取框

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章