
マイケル
あーーめんどくさいよ〜〜〜〜!

エレキベア
お困りのようクマね

マイケル
聞いてくれよエレキベア!

マイケル
知っての通り俺はたまに四コマを描いてるんだけどさ・・・

マイケル
ClipStudioで出力した上の画像から・・・

マイケル
こんな感じで毎回切り出してるんだけど
描く度に切り出すのがすごくめんどくさいんだ・・・!
描く度に切り出すのがすごくめんどくさいんだ・・・!

エレキベア
毎回手作業でやってるクマか・・・
そんなのツール作って自動化してしまえばいいクマよ
そんなのツール作って自動化してしまえばいいクマよ

マイケル
ツール自動化・・・なるほど!
そういえばなんか前も作ったね!
そういえばなんか前も作ったね!
【Python】pyautoguiを使ってKindle書籍を自動でスクショするツールを作ってみた!

エレキベア
そのとおりクマ。
PythonにもOpenCVという画像編集ライブラリ
があるから、今回も作れると思うクマ
PythonにもOpenCVという画像編集ライブラリ
があるから、今回も作れると思うクマ

マイケル
よーし、じゃあさっそく作ってみよう!!
仕様を考える

マイケル
まずは仕様を決めていきます!
いつも手作業でどのように画像を編集しているか考えてみます!
いつも手作業でどのように画像を編集しているか考えてみます!

マイケル
僕の場合は下記の手順でした。
- 適当なサイズにリサイズする。
- 画像の不要な部分を削除する。
- 出力したいサイズで画像を切り取る。

エレキベア
それなら、リサイズや切り取るサイズを明確
にした上で実装を進めるクマ!
にした上で実装を進めるクマ!

マイケル
そうだね!今回は
リサイズを元の画像の28%、
切り取るサイズを2048 * 1055で作っていこう!
リサイズを元の画像の28%、
切り取るサイズを2048 * 1055で作っていこう!

エレキベア
やったるクマ〜〜〜〜〜
画像編集の実装

マイケル
それではさっそく実装していきます!

マイケル
今回の仕様を実現するため、前述で出てきた
PythonのOpenCVという画像編集ライブラリの
下記機能を使って実装しました!
PythonのOpenCVという画像編集ライブラリの
下記機能を使って実装しました!
- 画像のリサイズ
- 画像の切り取り
- 画像の塗りつぶし

マイケル
作成したコードの完成形は下記になります!
import cv2
import numpy as np
import os
#########################
# 変数定義
# (環境に応じて変更する)
#########################
# フォルダパス
input_path = './input'
output_path = './output'
# 出力ファイル名
output1_name = "_1"
output2_name = "_2"
# 四コマサイズ(1055 * 2048)
sliceWidth, sliceHeight = 1055, 2048
#########################
# 出力処理
#########################
# 入力フォルダのファイルを処理(隠しファイルは除く)
file_list = [filename for filename in os.listdir(input_path) if not filename.startswith('.')]
for filename in file_list:
# 拡張子の判定
plex = ".png"
if ".jpg" in filename:
plex = ".jpg"
# 出力パスの定義
input_file_path = input_path + "/" + filename
output1_path = output_path + "/" + filename.replace(plex, output1_name + plex)
output2_path = output_path + "/" + filename.replace(plex, output2_name + plex)
#########################
# 左半分の出力
#########################
# 画像リサイズ(28%)
img = cv2.imread(input_file_path)
orgHeight, orgWidth = img.shape[:2]
resizeHeight, resizeWidth = int(orgHeight * 0.28), int(orgWidth * 0.28)
resizeImg = cv2.resize(img, (resizeWidth, resizeHeight))
# 画像切り抜き(切り抜きサイズで縦中央、左端からの範囲)
startWidth, startHeight = 0, int((resizeHeight - sliceHeight) / 2)
endWidth, endHeight = startWidth + sliceWidth, startHeight + sliceHeight
sliceImg1 = resizeImg[startHeight: endHeight, startWidth: endWidth]
# 右側5分の1を白で塗りつぶす
count = np.array([[sliceWidth - int(sliceWidth / 5), 0],
[sliceWidth - int(sliceWidth / 5), sliceHeight],
[sliceWidth, sliceHeight],
[sliceWidth, 0]])
cv2.fillPoly(sliceImg1, pts=[count], color=(255, 255, 255))
# 画像出力
cv2.imwrite(output1_path, sliceImg1)
#########################
# 右半分の出力
#########################
# 画像リサイズ(28%)
img = cv2.imread(input_file_path)
orgHeight, orgWidth = img.shape[:2]
resizeHeight, resizeWidth = int(orgHeight * 0.28), int(orgWidth * 0.28)
resizeImg = cv2.resize(img, (resizeWidth, resizeHeight))
# 画像切り抜き(切り抜きサイズで縦中央、左端からの範囲)
startWidth, startHeight = resizeWidth - sliceWidth, int((resizeHeight - sliceHeight) / 2)
endWidth, endHeight = startWidth + sliceWidth, startHeight + sliceHeight
sliceImg2 = resizeImg[startHeight: endHeight, startWidth: endWidth]
# 左側5分の1を白で塗りつぶす
count = np.array([[0, 0],
[0, sliceHeight],
[int(sliceWidth / 5), sliceHeight],
[int(sliceWidth / 5), 0]])
cv2.fillPoly(sliceImg2, pts=[count], color=(255, 255, 255))
# 画像出力
cv2.imwrite(output2_path, sliceImg2)

マイケル
それでは細かくみていきましょう!
環境変数の定義

マイケル
まずは冒頭の変数定義!
こちらには環境に合わせて入力・出力フォルダパス、
切り取りサイズを設定しましょう!
こちらには環境に合わせて入力・出力フォルダパス、
切り取りサイズを設定しましょう!
#########################
# 変数定義
# (環境に応じて変更する)
#########################
# フォルダパス
input_path = './input'
output_path = './output'
# 出力ファイル名
output1_name = "_1"
output2_name = "_2"
# 四コマサイズ(1055 * 2048)
sliceWidth, sliceHeight = 1055, 2048

マイケル
そして入力フォルダ内のファイルを読み込んでループで回します。
#########################
# 出力処理
#########################
# 入力フォルダのファイルを処理(隠しファイルは除く)
file_list = [filename for filename in os.listdir(input_path) if not filename.startswith('.')]
for filename in file_list:
# 拡張子の判定
plex = ".png"
if ".jpg" in filename:
plex = ".jpg"
# 出力パスの定義
input_file_path = input_path + "/" + filename
output1_path = output_path + "/" + filename.replace(plex, output1_name + plex)
output2_path = output_path + "/" + filename.replace(plex, output2_name + plex)

エレキベア
読み込んだファイルごとに編集処理を行うクマね

マイケル
そのとおり!
それとファイルリスト取得時に「if not filename.startswith(‘.’)」
を指定してあげると、隠しファイル(「.」から始まるファイル)は対象外にすることができるよ!
それとファイルリスト取得時に「if not filename.startswith(‘.’)」
を指定してあげると、隠しファイル(「.」から始まるファイル)は対象外にすることができるよ!
画像のリサイズ

マイケル
ここから読み込んだファイル単位で画像処理を行います!
# 画像リサイズ(28%)
img = cv2.imread(input_file_path)
orgHeight, orgWidth = img.shape[:2]
resizeHeight, resizeWidth = int(orgHeight * 0.28), int(orgWidth * 0.28)
resizeImg = cv2.resize(img, (resizeWidth, resizeHeight))

マイケル
cv2.resize()にリサイズした縦幅と横幅を指定して、リサイズしましょう!

エレキベア
今回は28%にするから0.28をかけているクマね
画像の切り取り

マイケル
次に切り取りたいサイズを指定して切り取ります。
resizeImg[【縦開始位置】: 【縦終了位置】, 【横開始位置】: 【横終了位置】]

マイケル
切り取り処理自体は上記の通り、画像配列をスライスして行います!
切り取る範囲は、実際の画像を見て記述しましょう!
切り取る範囲は、実際の画像を見て記述しましょう!
↑切り取る範囲
# 画像切り抜き(切り抜きサイズで縦中央、左端からの範囲)
startWidth, startHeight = 0, int((resizeHeight - sliceHeight) / 2)
endWidth, endHeight = startWidth + sliceWidth, startHeight + sliceHeight
sliceImg1 = resizeImg[startHeight: endHeight, startWidth: endWidth]

マイケル
切り取った結果は、下記のようになります!

エレキベア
サイズは問題ないクマが
隣のコマまで映り込んじゃってるクマね・・・
隣のコマまで映り込んじゃってるクマね・・・

マイケル
範囲の中にかぶっちゃったんだね・・・
それじゃあ次はこの隣のコマを消していこう!
それじゃあ次はこの隣のコマを消していこう!
画像の塗りつぶし

マイケル
というわけで、隣のコマを削除するため
下記範囲(5分の1)を白色で塗りつぶします!
下記範囲(5分の1)を白色で塗りつぶします!

マイケル
cv2.fillPoly()を使用して塗りつぶします!
# 右側5分の1を白で塗りつぶす
count = np.array([[sliceWidth - int(sliceWidth / 5), 0],
[sliceWidth - int(sliceWidth / 5), sliceHeight],
[sliceWidth, sliceHeight],
[sliceWidth, 0]])
cv2.fillPoly(sliceImg1, pts=[count], color=(255, 255, 255))

マイケル
塗りつぶし範囲はnp.array()で取得したものを使用しますが、
切り取り処理と異なり、各座標点から取得する点に気をつけてください!
切り取り処理と異なり、各座標点から取得する点に気をつけてください!
count = np.array([[左上座標],
[左下座標],
[右下座標],
[右上座標]])

マイケル
塗りつぶした結果は下記になります!

エレキベア
なかなか綺麗に消せたクマね〜〜〜
画像の出力

マイケル
最後に画像出力!
加工した画像をcv2.imwrite()を使用して出力します!
加工した画像をcv2.imwrite()を使用して出力します!
# 画像出力
cv2.imwrite(output1_path, sliceImg1)

エレキベア
これで指定したフォルダに画像が出力されるクマね

マイケル
あとは右側のコマ切り取りも
範囲指定を変えて同じように作成すればOKだね!
範囲指定を変えて同じように作成すればOKだね!
おまけ:一コマだけ切り取る

マイケル
最後におまけとして一コマ分だけ切り取るパターンも載せておきます!
処理内容自体はこれまでと同じですね。
処理内容自体はこれまでと同じですね。
・・・略・・・
output1_title_name = "_title_1"
output2_title_name = "_title_2"
# タイトルサイズ(650 * 430)
sliceTitleWidth, sliceTitleHeight = 650, 430
# 入力フォルダのファイルを処理(隠しファイルは除く)
file_list = [filename for filename in os.listdir(input_path) if not filename.startswith('.')]
for filename in file_list:
・・・略・・・
output_title1_path = output_path + "/" + filename.replace(plex, output1_title_name + plex)
output_title2_path = output_path + "/" + filename.replace(plex, output2_title_name + plex)
・・・略・・・
#########################
# タイトルの出力処理
#########################
# 画像切り抜き(切り抜きサイズで縦中央、左端からの範囲)
startWidth, startHeight = int((sliceWidth / 2) - (sliceTitleWidth / 2)), int(sliceHeight / 7.5)
endWidth, endHeight = startWidth + sliceTitleWidth, startHeight + sliceTitleHeight
titleImg1 = sliceImg1[startHeight: endHeight, startWidth: endWidth]
titleImg2 = sliceImg2[startHeight: endHeight, startWidth: endWidth]
# 画像出力
cv2.imwrite(output_title1_path, titleImg1)
cv2.imwrite(output_title2_path, titleImg2)

マイケル
出力結果はこちら!

エレキベア
慣れればいろんなパターンも作れるクマね
実行してみる

マイケル
それでは実際に四コマファイル達を読み込んでみましょう!

マイケル
入力フォルダ、出力フォルダ、実行用にshellも用意して・・・

マイケル
入力ファイルを格納して実行!!!

マイケル
このように全ファイル加工ができました!

エレキベア
やったクマ〜〜〜〜!!
おわりに

マイケル
というわけで今回はPythonを使った画像編集についてでした!

エレキベア
画像加工も数行でできるから便利クマね〜〜〜

マイケル
今回のパターンだけじゃなく他にもいろいろできるみたいだから
触って試してみてください!
触って試してみてください!

マイケル
それでは今日はこの辺で!
アデュー!!
アデュー!!

エレキベア
クマ〜〜〜〜〜〜〜〜〜
【Python】OpenCVを使って画像編集を自動化する 〜完〜