【Python】OpenCVを使って画像編集を自動化する

Python
マイケル
マイケル
あーーめんどくさいよ〜〜〜〜!
エレキベア
エレキベア
お困りのようクマね
マイケル
マイケル
聞いてくれよエレキベア!
マイケル
マイケル
知っての通り俺はたまに四コマを描いてるんだけどさ・・・
20200824 たまご父さん
マイケル
マイケル
ClipStudioで出力した上の画像から・・・
20200824 たまご父さん 1
マイケル
マイケル
こんな感じで毎回切り出してるんだけど
描く度に切り出すのがすごくめんどくさいんだ・・・!
エレキベア
エレキベア
毎回手作業でやってるクマか・・・
そんなのツール作って自動化してしまえばいいクマよ
マイケル
マイケル
ツール自動化・・・なるほど!
そういえばなんか前も作ったね!


【Python】pyautoguiを使ってKindle書籍を自動でスクショするツールを作ってみた!

エレキベア
エレキベア
そのとおりクマ。
PythonにもOpenCVという画像編集ライブラリ
があるから、今回も作れると思うクマ
マイケル
マイケル
よーし、じゃあさっそく作ってみよう!!

スポンサーリンク

仕様を考える

マイケル
マイケル
まずは仕様を決めていきます!
いつも手作業でどのように画像を編集しているか考えてみます!
マイケル
マイケル
僕の場合は下記の手順でした。
Screenshot 2020 08 30 21 56 12

  1. 適当なサイズにリサイズする。
  2. 画像の不要な部分を削除する。
  3. 出力したいサイズで画像を切り取る。

エレキベア
エレキベア
それなら、リサイズや切り取るサイズを明確
にした上で実装を進めるクマ!
マイケル
マイケル
そうだね!今回は
リサイズを元の画像の28%
切り取るサイズを2048 * 1055で作っていこう!
エレキベア
エレキベア
やったるクマ〜〜〜〜〜

画像編集の実装

マイケル
マイケル
それではさっそく実装していきます!
マイケル
マイケル
今回の仕様を実現するため、前述で出てきた
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(‘.’)」
を指定してあげると、隠しファイル(「.」から始まるファイル)は対象外にすることができるよ!

画像のリサイズ

マイケル
マイケル
ここから読み込んだファイル単位で画像処理を行います!

    # 画像リサイズ(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[【縦開始位置】: 【縦終了位置】, 【横開始位置】: 【横終了位置】]
マイケル
マイケル
切り取り処理自体は上記の通り、画像配列をスライスして行います!
切り取る範囲は、実際の画像を見て記述しましょう!
Screenshot 2020 08 30 21 56 37
↑切り取る範囲

    # 画像切り抜き(切り抜きサイズで縦中央、左端からの範囲)
    startWidth, startHeight = 0, int((resizeHeight - sliceHeight) / 2)
    endWidth, endHeight = startWidth + sliceWidth, startHeight + sliceHeight
    sliceImg1 = resizeImg[startHeight: endHeight, startWidth: endWidth]
マイケル
マイケル
切り取った結果は、下記のようになります!
Slice
エレキベア
エレキベア
サイズは問題ないクマが
隣のコマまで映り込んじゃってるクマね・・・
マイケル
マイケル
範囲の中にかぶっちゃったんだね・・・
それじゃあ次はこの隣のコマを消していこう!

画像の塗りつぶし

マイケル
マイケル
というわけで、隣のコマを削除するため
下記範囲(5分の1)を白色で塗りつぶします!
Screenshot 2020 08 30 21 56 50
マイケル
マイケル
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([[左上座標],
                      [左下座標],
                      [右下座標],
                      [右上座標]])
マイケル
マイケル
塗りつぶした結果は下記になります!
20200824 たまご父さん 1
エレキベア
エレキベア
なかなか綺麗に消せたクマね〜〜〜

画像の出力

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

    # 画像出力
    cv2.imwrite(output1_path, sliceImg1)
エレキベア
エレキベア
これで指定したフォルダに画像が出力されるクマね
マイケル
マイケル
あとは右側のコマ切り取りも
範囲指定を変えて同じように作成すれば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)
マイケル
マイケル
出力結果はこちら!
20200824 たまご父さん title 2
エレキベア
エレキベア
慣れればいろんなパターンも作れるクマね

実行してみる

マイケル
マイケル
それでは実際に四コマファイル達を読み込んでみましょう!
Screenshot 2020 08 30 20 30 26
マイケル
マイケル
入力フォルダ、出力フォルダ、実行用にshellも用意して・・・
Screenshot 2020 08 30 20 30 30
マイケル
マイケル
入力ファイルを格納して実行!!!
Screenshot 2020 08 30 20 30 44
Screenshot 2020 08 30 22 51 55
マイケル
マイケル
このように全ファイル加工ができました!
エレキベア
エレキベア
やったクマ〜〜〜〜!!

おわりに

マイケル
マイケル
というわけで今回はPythonを使った画像編集についてでした!
エレキベア
エレキベア
画像加工も数行でできるから便利クマね〜〜〜
マイケル
マイケル
今回のパターンだけじゃなく他にもいろいろできるみたいだから
触って試してみてください!
マイケル
マイケル
それでは今日はこの辺で!
アデュー!!
エレキベア
エレキベア
クマ〜〜〜〜〜〜〜〜〜

【Python】OpenCVを使って画像編集を自動化する 〜完〜

コメント