はじめに
画像フォルダ内に種々雑多の形の画像があって,PC用やスマホ用の壁紙を探すのにちょっとした手間を感じたことはありませんか?求める条件の画像を選び出す簡単なプログラムを今回は書きました。
使うサードパーティーパッケージ
- OpenCV
画像処理をあれこれするためのオープンソースライブラリ。
各動作環境に合わせてインストールしてください。
実際のプログラム
import cv2
import sys
import shutil
from pathlib import Path
# 絶対パスで入力する
target_dir = Path(sys.argv[1])
save_dir = Path(sys.argv[2])
# もし保存用ディレクトリが無かったら作成しておく
if not save_dir.exists():
save_dir.mkdir()
# 条件にマッチする画像ファイルをリストに追加
# 今回はPC用の画像
target_pic_list = []
for pic_path in target_dir.glob('*.jpeg'):
try:
pic = cv2.imread(str(pic_path))
vert_pixel, hori_pixel = pic.shape[0], pic.shape[1]
ratio = hori_pixel/vert_pixel
except:
continue
if (1.6 < ratio < 1.8):
target_pic_list.append(pic_path)
# リスト内の画像を保存用ディレクトリにコピー
for pic_path in target_pic_list:
pic_name = pic_path.name
shutil.copy(pic_path, save_dir/pic_name)
コマンドライン引数として検索対象のディレクトリと保存用のディレクトリを絶対パスで与えています。そして検索対象ディレクトリ内の画像をOpenCVによって読み取り,画像の縦横のピクセルを取得します。それを条件文で処理して,欲しい画像の形状や画質を指定し,保存用のディレクトリへとコピーするというのが全体の流れです。
プログラムの簡単な解説をします。
今回はディレクトリ操作のためにPath
オブジェクトを利用しています。
glob()メソッドにより,正規表現に似たような記法でディレクトリ内のファイルをジェネレーターとして取得することができます。
# 今回はjpegファイルを指定
for pic_path in target_dir.glob('*.jpeg'):
そしてOpenCVで各画像を読み込みます
# Pathオブジェクトは受け取れないのでstr()で文字列に直している
pic = cv2.imread(str(pic_path))
shapeプロパティには,タプルで(縦のピクセル,横のピクセル,画像の色のチャンネル数)が入っています。
例えば以下のkuma.pngについて,
pic = cv2.imread('kuma.png')
print(pic.shape)
# (384,512,3)
この情報をもとに条件文を記述して画像を選択します。
今回はPCモニターの横と縦の比(だいたい1.6〜1.8)に合うような条件としました。
高画質の画像のみ欲しい場合には縦横どっちかのピクセルに下限を与えてもいいかもしれないですね。
vert_pixel, hori_pixel = pic.shape[0], pic.shape[1]
ratio = hori_pixel/vert_pixel
if (1.6 < ratio < 1.8):
target_pic_list.append(pic_path)
最後に条件を通過した画像をコピーします。
ここで簡単にPathオブジェクトについて説明します。
Pathオブジェクトはnameプロパティでファイル名(かディレクトリ名)を取得できます。
p = Path('/hoge/fuga/foo/bar.txt')
print(p.name)
# bar.txt
またPathオブジェクト同士(または文字列)を/
で区切ることで新たなPathオブジェクトを作成できることを利用しています。これがPathオブジェクトの便利な点ですね。
p1 = Path('/hoge/fuga')
p2 = Path('foo/bar.txt')
p1 / p2
# (macの場合)PosixPath('/hoge/fuga/foo/bar.txt')
p1 / 'foo/bar.txt'
# (macの場合)PosixPath('/hoge/fuga/foo/bar.txt')
これらをもとに保存先のパスを作成し,shutil.copy()メソッドでコピーしています。
for pic_path in target_pic_list:
pic_name = pic_path.name
shutil.copy(pic_path, save_dir/pic_name)
まとめ
OpenCVやshutil,pathlib.Pathなどのツールを使って(そこそこ)便利なツールを作れたと思います。(僕自身そうですが)初心者の方のライブラリの勉強になるかもですね。