ゲーム開発
Unity
UnrealEngine
C++
Blender
ゲーム数学
ゲームAI
グラフィックス
サウンド
アニメーション
GBDK
制作日記
IT関連
ツール開発
フロントエンド関連
サーバサイド関連
WordPress関連
ソフトウェア設計
おすすめ技術書
音楽
DTM
楽器・機材
ピアノ
ラーメン日記
四コマ漫画
その他
おすすめアイテム
おもしろコラム
  • ゲーム開発
    • Unity
    • UnrealEngine
    • C++
    • Blender
    • ゲーム数学
    • ゲームAI
    • グラフィックス
    • サウンド
    • アニメーション
    • GBDK
    • 制作日記
  • IT関連
    • ツール開発
    • フロントエンド関連
    • サーバサイド関連
    • WordPress関連
    • ソフトウェア設計
    • おすすめ技術書
  • 音楽
    • DTM
    • 楽器・機材
    • ピアノ
  • ラーメン日記
    • 四コマ漫画
      • その他
        • おすすめアイテム
        • おもしろコラム
      1. ホーム
      2. 20200831_01

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

      ツール開発Python自動化画像編集
      2020-08-31

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


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

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

      仕様を考える

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

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

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

      画像の塗りつぶし

      マイケル
      マイケル
      というわけで、隣のコマを削除するため
      下記範囲(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(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)
      
      マイケル
      マイケル
      出力結果はこちら!
      エレキベア
      エレキベア
      慣れればいろんなパターンも作れるクマね

      実行してみる

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

      おわりに

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

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


      ツール開発Python自動化画像編集
      2020-08-31

      関連記事
      【Unity】Timeline × Excelでスライドショーを効率よく制作する
      2024-10-31
      【Node.js】廃止されたAmazonアソシエイト画像リンクをAmazon Product Advertising API経由で復活させる
      2024-01-08
      【Electron × Vue3】カテゴリ情報のCSVデータを操作するツールを作る
      2023-12-31
      【Electron × Vue3】画像をリサイズして任意の場所に保存するツールを作る
      2023-12-31
      【Electron × Vue3】Electron × Vue3 × TypeScript × Vite でツール開発環境を整える
      2023-12-31
      【Flutter3】Googleスプレッドシートと連携した英単語学習アプリを作る
      2022-12-11
      【Python】Pythonスクリプトをexe、app化する【cx_Breeze】
      2021-08-29
      【Python】Pillowを使ってピクセル操作!画像フィルタをかけてみる
      2021-02-17