Numpyで分割サイズを指定して画像を均等にグリッド化させる
前書き
大きめの画像から物体認識を実装する際、
やはり画像をグリッドごとに分割すべきです。
そんな時画像のピクセル数を指定して分割したいと思ったので、
記事を書いてみました。
画像処理ライブラリ「Pillow」
Pillowとは画像処理ライブラリで、
対抗馬になりうるのはOpenCVです。
どちらも使ってみましたが、ドキュメントを読みながら書いていく感じです。
やりたかったこと
大きめの画像をn等分や余りなく等分するスクリプトはよく見るが、
pxを指定しながら分割し、余りが存在する場合は余りのサイズで分割する
グリッド化は余りみない気がしたので、自分で書きました。
上記だと黄色の部分は300px×300pxで、
基本的には黒色の画像全体を300pxの正方形でグリッド化したかったのです。
しかし余りが発生するのでそこはサイズに応じて分割しました(オレンジ・茶・赤)。
実際のコード
PILで読み込んだ画像を、
配列操作しやすくするためにNumpy配列に変換し、再びPILに変換しています。
import os import sys import math import numpy as np from PIL import Image # 300pxずつ分割したい separate_w, separate_h = 300, 300 # 分割関数 def split_image_unequal(w, h, img, div_w, div_h, filename): # 幅の分割矩形数分だけ for i in range(w//div_w+1): # 矩形の幅 sep_w = div_w # 余りが発生した時は余った分のサイズで if i == w//div_w : sep_w = (w-(w//div_w)*div_w)-1 # 高さの分割矩形数分だけ for j in range(h//div_h+1): # 矩形の高さ sep_h = div_h # 余りが発生した時は余った分のサイズで if j == h//div_h : sep_h = (h-(h//div_h)*div_h)-1 # numpyArrayなのでスライス(w,h,channelの3次元) sep_img = img[div_w*i:div_w*i+sep_w+1, div_h*j:div_h*j+sep_h+1, :] # PILに変換 pil_img = Image.fromarray(sep_img) # ファイルに保存 pil_img.save('./image/separate/%s_%d_%d.jpg'%(filename, i+1, j+1)) print('i: %d, j: %d,[縦: (%d %d), 横: (%d %d)]'%(i,j,div_w*i,div_w*i+sep_w,div_h*j,div_h*j+sep_h)) def separate(img, w, h, filename): print('width: %d, height: %d'% (int(w), int(h))) # 関数には画像幅、画像高さ、画像(Numpy配列)、矩形幅、矩形高さ、ファイル名 return split_image_unequal(w, h, img, separate_w, separate_h, filename)
使い方
# ディレクトリ内の画像ファイルパス(string) for file in files: # ファイルパスを読み込んでPIL変換 img = Image.open(file) # ファイル名(拡張子の前を抽出) ftitle = img.filename ffile = ftitle.split('/')[-1] fname = ffile.split(".")[-2] print(fname) # Numpy配列化 img_np = np.array(img) w,h = img_np.shape[0], img_np.shape[1] # separate関数には画像(Numpy配列)、幅、高さ、ファイル名 separate_img = separate(img_np, w, h, fname)