Python3による画像編集についてです!
今回は並べられた画像を、分割して各画像ファイルとして出力する処理を作ってみました!
ソースはGitHubにもアップしてみました。
- どんなことをするのか
- 画像分割するソースのサンプル
- カレントフォルダの取得
- インポートするライブラリ
- 画像情報を扱うクラス
- 画像の切り出し処理と保存
- ImgInfo.show() 情報表示
- マス目の座標を生成する
- 結果
- 参考
- あとがき
どんなことをするのか
例えばこんな感じで、適当なサイズのグリッド状に各画像がくっついたベース画像があるとします。
ゲームのマップチップとかみたいですね。
コレをえいやー!っとして
こんな感じでバラバラの連番ファイルで出力します。
画像分割するソースのサンプル
こんな感じで作ってみました。
コードを表示する
# -*- coding: utf-8 -*- from PIL import Image import os imgName = 'img.png' imgDir = os.getcwd() + '\\' class ImgInfo: def __init__(self, name, sx, sy, ex, ey): self.name = name + '.png' self.sx = sx self.sy = sy self.ex = ex self.ey = ey def carving(self): # 画像を切り出して保存 baseFile = imgDir + imgName img = Image.open(baseFile) imgCrop = img.crop((self.sx, self.sy, self.ex, self.ey)) output = imgDir + self.name imgCrop.save(output) def show(self): # 情報表示 print('[{}] {: >4}, {: >4}, {: >4}, {: >4}'.format(self.name, self.sx, self.sy, self.ex, self.ey)) def getOfsList(num, size): ofs = [] for i in range(0, num): ofs.append(i * size) return ofs # イメージの始点 startX = 5 startY = 5 # イメージの幅、高さ imgW = 120 imgH = 120 # xofs = getOfsList(4, imgW) yofs = getOfsList(4, imgH) # 画像情報 imgs = [] cnt = 0 ycnt = 1 for y in yofs: xcnt = 1 for x in xofs: name = str(cnt).zfill(2) sx = x + startX sy = y + startY ex = (imgW * xcnt) + startX ey = (imgH * ycnt) + startY img = ImgInfo(name, sx, sy, ex, ey) imgs.append(img) cnt += 1 xcnt += 1 ycnt += 1 # 確認 for img in imgs: img.show() # 分割 for img in imgs: img.carving()
それでは詳細を解説していきます。
カレントフォルダの取得
最初に出てきた
import os
を使って、現在位置を取得します。
この2つのどちらかで、カレントフォルダをフルパスで取得することができます。
>>> os.path.abspath(".") 'C:\\work' >>> os.getcwd() 'C:\\work'
このとき終端に「\\」が付きません。
なのでファイル名を繋げて、ファイルのフルパスを作りたいときは、手動で「\\」を付けてあげる必要があります。
インポートするライブラリ
インポートするのはこの2つです。
from PIL import Image import os
PILというのが、画像処理を行う「Pillow」というライブラリです。
これは必須。
osは、ファイルパスを取得するために使用しています。
フォルダの移動
今回は使っていないので余談ですが、
>>> os.chdir("C:\\work\\python")
とすることで、フォルダを移動できます。
コレを実行して、カレントフォルダを表示すると
>>> os.getcwd() 'C:\\work\\python'
と表示されます。
ちゃんと移動していますね!
画像情報を扱うクラス
今回は画像情報を管理するクラスを作ってみました。
class ImgInfo: def __init__(self, name, sx, sy, ex, ey): self.name = name + '.png' self.sx = sx self.sy = sy self.ex = ex self.ey = ey def carving(self): # 画像を切り出して保存 baseFile = imgDir + imgName img = Image.open(baseFile) imgCrop = img.crop((self.sx, self.sy, self.ex, self.ey)) output = imgDir + self.name imgCrop.save(output) def show(self): # 情報表示 print('[{}] {: >4}, {: >4}, {: >4}, {: >4}'.format(self.name, self.sx, self.sy, self.ex, self.ey))
インスタンス生成時に、
- ファイル名(拡張子なし:png固定)
- 画像の開始座標 x, y
- 画像の幅、高さ w, h
を渡すことで、生成できます。
- carving(): 画像の切り出しをして保存
- show(): 情報表示
画像の切り出し処理と保存
ImgInfo.carving()では、画像の切り出しと保存を行っています。
切り出しと保存は3つのステップで行うことができます。
# 画像を開く img = Image.open("開くファイル") # 画像を切り出す imgCrop = img.crop((始点X, 始点Y, 終点X, 終点Y)) # 切り出した画像を保存 imgCrop.save("保存するパス")
img.crop()は、あくまで始点座標と終点座標なのでお間違いなく。
x, y, w, hのつもりで設定するとエラーします。
ImgInfo.show() 情報表示
実行すると、こんな感じで出力されます。
[02.png] 240, 0, 360, 120
print内の「{}」は、format()で与えた変数の値が入ります。
左から順に対応してものが入ります。
「{: >4}」のように記述することで、「空白4つで右寄せ」を指定しています。
マス目の座標を生成する
マス目の座標をいちいち作るのが面倒……
ということで今回はこんな関数を作成しました。
def getOfsList(num, size): ofs = [] for i in range(0, num): ofs.append(i * size) return ofs
マスの数とサイズを渡すと、各マスの座標が配列で返ってきます。
事前にスタート座標とサイズは設定してあるので
# イメージの始点 startX = 5 startY = 5 # イメージの幅、高さ imgW = 120 imgH = 120
座標のオフセットを取得して
xofs = getOfsList(4, imgW) yofs = getOfsList(4, imgH)
ループで処理することで、各座標が生成できます。
cnt = 0 ycnt = 1 for y in yofs: xcnt = 1 for x in xofs: name = str(cnt).zfill(2) sx = x + startX sy = y + startY ex = (imgW * xcnt) + startX ey = (imgH * ycnt) + startY cnt += 1 xcnt += 1 ycnt += 1
全て座標を表示すると、こんな感じの状態になっています。
[00.png] 5, 5, 125, 125 [01.png] 125, 5, 245, 125 [02.png] 245, 5, 365, 125 [03.png] 365, 5, 485, 125 [04.png] 5, 125, 125, 245 [05.png] 125, 125, 245, 245 [06.png] 245, 125, 365, 245 [07.png] 365, 125, 485, 245 [08.png] 5, 245, 125, 365 [09.png] 125, 245, 245, 365 [10.png] 245, 245, 365, 365 [11.png] 365, 245, 485, 365 [12.png] 5, 365, 125, 485 [13.png] 125, 365, 245, 485 [14.png] 245, 365, 365, 485 [15.png] 365, 365, 485, 485
結果
最終的にこのように切り出し処理を行います。
for img in imgs: img.carving()
結果として、このような画像が
このように切り出されます。
成功ですね!
参考
これらを参考にしました。ありがとうございました。
あとがき
ということで、Python3で並べられた画像を分割する処理についてでした!
ちょっと必要になったので作ってみたのですが、ある程度サクッとできたような気がします。
まとめて描いた画像を切り出したい!
とか
切り出し前提でまとめて描きたい!
なんてときに便利です。
あくまで座標計算と、APIの実行だけでできちゃいます。
なのでちょっと変えれば色々と応用できると思いますー!