本記事では、PythonのOpneCVというライブラリを用いて、画像を好きなサイズに切り取り、圧縮したり、圧縮するプログラムをご紹介します。
想定読者
・OpenCVを使って、画像のサイズに変えたり、圧縮するプログラムを作りたい。
・Pythonで自分で関数を作って、インポートして使ってみたい。
Python/OpenCVで画像の切り取り、縮小、圧縮をするための実行環境
今回は、以下の実行環境でプログラムを実行しています。
・Linux
・Python 3.7.6
・Jupyterlab 1.2.6
・cv2:4.3.0
テスト画像としては、Pixabayからダウンロードした下の画像を使っていきます。
ファイル名は「input.jpg」とします。
ダウンロード時は、容量:395KB、サイズ:1920×1357となっております。
Python/OpenCVで画像の切り取り、縮小、圧縮をするプログラム
今回は、Python/OpenCVで画像を切り取り、縮小、圧縮するプログラムを1つのpyファイルで書き、それをJupyterNotebookで利用することを想定しています。
pyファイルの名前は、「image_edit.py」とし、pyファイルを実行するNotebookファイルは、「image_edit_run.ipynb」とします。
今回、実行するフォルダは、下図の通りとなります。
ちなみに、画像の切り取りと縮小の違いについては、次のページを見ればイメージがつきます。
Python/OpenCVで画像を切り取るプログラム
それでは、画像を切り取るプログラムをから見ていきます。
cut関数として作成します。
ここでは、画像の中央部分で切り取る仕様としています。デフォルトでは、1200×675のサイズで切り取られます。
関数の引数に、対象の画像ファイル名、加工後のファイル名、そして任意で切り取りたい幅と高さを指定します。
import os
import cv2
def cut(input_filename, output_filename, width=1200, height=675):
"""
インプット画像を指定の大きさに(デフォルト:1200×675)に切り取りする。
Parameter
-------------------
img : インプット画像のファイル名
filename : 生成する画像のファイル名
width : 変更したい画像の幅
height : 変更したい画像の高さ
Return
-------------------
なし
"""
#画像の読み込み
img = cv2.imread(input_filename)
#インプット画像のサイズを変数に入れる
i_height = img.shape[0]
i_width = img.shape[1]
#切り取る部分の左上の頂点を決める
i = int((i_height-height)/2)
j = int((i_width-width)/2)
#頂点から指定のサイズでスライスし、画像を書き出す
img2 = img[i:i+height, j:j+width]
cv2.imwrite(output_filename, img2)
Python/OpenCVで画像を縮小するプログラム
次に画像を縮小するプログラムを見ていきます。
shrink関数として作成します。
引数は、切り取りのcut関数と同様としています。
def shrink(input_filename, output_filename, width=1200, height=675):
"""
インプット画像を指定の大きさに(デフォルト:1200×675)に縮小する。
Parameter
-------------------
img: インプット画像のファイル名
filename: 生成する画像のファイル名
width : 変更したい画像の幅
height : 変更したい画像の高さ
Return
-------------------
なし
"""
#画像の読み込み
img = cv2.imread(input_filename)
#指定のサイズに画像をリサイズし、書き出す
img2 = cv2.resize(img , (width, height))
cv2.imwrite(output_filename, img2)
Python/OpenCVで画像を圧縮するプログラム
最後に画像を圧縮するプログラムです。
今回は、to_100kb関数として100KB以下に圧縮するプログラムを書いています。
下のプログラムの100000の部分を、好きなバイト数に変更できます。
引数は、対象の画像ファイル名、加工後のファイル名です。
def to_100kb(input_filename, output_filename):
"""
インプット画像を100KB以下にする画像を生成する。
Parameter
-------------------
img: インプット画像のnumpy.ndarray
filename: 生成する画像のファイル名
Return
-------------------
なし
"""
#インプット画像の拡張子を取得
extension = input_filename.split('.')[-1]
#画像の読み込み
img = cv2.imread(input_filename)
#圧縮率を10%から95%まで5%刻みの値のリストを作る
comp_ratio_list = [i*5 for i in range(2, 20)]
#リストの初期化
output_size_list = []
tmp_list = []
#一時ファイルのファイル名
tmp_filename = "tmp." + extension
#100KB以下になる最大の圧縮率を探す
for comp_ratio in comp_ratio_list:
#画像imgを圧縮率comp_ratioで書き出し
cv2.imwrite(tmp_filename, img, [cv2.IMWRITE_JPEG_QUALITY, comp_ratio])
#圧縮率comp_rateごとに書き出した画像ファイルの容量を、output_size_listに追加
output_size = os.path.getsize(tmp_filename)
output_size_list.append(output_size)
#容量あ100KB以下の場合は、tmp_listに追加
if output_size <= 100000:
tmp_list.append(comp_ratio)
#一時ファイルを削除する
os.remove(tmp_filename)
# 100KB以下になる最大の圧縮率(tem_listの最大値)で圧縮し画像を書き出し
cv2.imwrite(output_filename, img, [cv2.IMWRITE_JPEG_QUALITY, max(tmp_list)])
実際にOpenCVのプログラムを実行してみる
それでは、「image_edit_run.ipynb」で上記のプログラムを実行してみたいと思います。
1行目では、pyファイル名を記載します。
それ以降は、image.関数名として処理を実行します。
3行目と5行目では、画像のサイズを指定して、切り取り・縮小を行っています。
2行目〜5行目で切り取り・縮小された画像は次の通りとなります。
そして、6行目の処理で、正常に100KB以下に圧縮されたことがわかります。
これで今回は以上となります。
いかがでしたでしょうか?
PythonのOpenCVを用いることで、画像の切り取り、縮小、圧縮を手軽にできそうですよね。
もしこうした方がいいよ〜とか、ここが分からない等ありましたら、Twitterまで連絡をお待ちしています。
最後まで読んでいただき、ありがとうございました。