本記事では、PythonのOpneCVというライブラリを用いて、自動で画像を指定の縦横比にしたり、圧縮する方法をご紹介します。
想定読者
・ブログ記事を書くとき、手動で画像のサイズを変えたり圧縮している。Pythonも少しわかる。
・Pythonを勉強していて、簡単なOpenCVの処理を使ってみたい。
最適なブログでの画像の容量とサイズについて
ブログ内の画像の容量が大きいと、反応速度が遅くなり、Google検索エンジンの評価にも影響すると言われています。
一般的には、画像1ファイルあたり100KB以内が1つの目安になります。
画像のサイズについては、Google Discover(俗に言うGoogle砲)で奨励されている画像の幅:1200pxが1つの目安になります。
(引用元:Google Discoverページ)
Google Discover(Google砲)とは、Googleの検索窓の下に列挙されるオススメ記事(赤枠部分)をいう。
本記事では、画像容量が100KB以下で、画像サイズは幅:1200px、高さ:675px(16:9)の画像を自動で作成するプログラムをご紹介します。
Pythonでブログ画像を加工するための実行環境
・Linux
・Python 3.7.6
・Jupyterlab 1.2.6
・cv2:4.3.0
テスト画像としては、Pixabayからダウンロードした下の画像を使っていきます。
ファイル名は「input.jpg」とします。
ダウンロード時は、容量:395KB、サイズ:1920×1357となっております。
Pythonでブログ画像を16:9に切り取り・縮小、100KB以下に圧縮する方法
それでは、実際にPythonのプログラムをみていきます。
Pythonでブログ画像の加工の準備
まずは、Pythonで今回の画像加工に必要なライブラリをインポートします。
import os
import cv2
import matplotlib.pyplot as plt
%matplotlib inline #Jupyter Notebookで実行する際は必要
次にテスト画像を取り込んで、表示します。
img = cv2.imread('input.jpg') #numpy.ndarrayとなる
plt.imshow(img)
print('容量:{}KB'.format(int(os.path.getsize("input.jpg") /1000)))
print('サイズ:{}×{}'.format(img.shape[1], img.shape[0]))
結果は次の通りとなります。
※今回使っているOpenCVのimread()で画像ファイルを読み込むと色の順番がBGR(青、緑、赤)になるので、Jupyter Notebook上は元の画像と違った色で表示されます。
実際の画像は、色が変わることはありません。
これで画像加工の準備は終わりです。
Pythonでブログ画像を16:9に切り取り、縮小
次に、画像の切り取りまたは縮小を行います。
このどちらかの方法によって、画像のサイズ(縦横比)を16:9に変換します。
ここで、画像の切り取りと縮小のイメージを確認しましょう。次の図の通りとなります。
それでは、まず画像の切り取りのプログラムをみていきます。
height = img.shape[0]
width = img.shape[1]
i = int((height-675)/2)
j = int((width-1200)/2)
img2 = img[i:i+675, j:j+1200]
plt.imshow(img2)
cv2.imwrite("output2.jpg", img2)
print('容量:{}KB'.format(int(os.path.getsize("output2.jpg") /1000)))
print('サイズ:{}×{}'.format(img2.shape[1], img2.shape[0]))
画像の切り取りの結果は次のようになります。上下の端が削られているのがわかると思います。
次に画像の縮小のプログラムをみていきまます。
img3 = cv2.resize(img , (1200, 675))
plt.imshow(img3)
cv2.imwrite("output3.jpg", img3)
print('容量:{}KB'.format(int(os.path.getsize("output3.jpg") /1000)))
print('サイズ:{}×{}'.format(img3.shape[1], img3.shape[0]))
画像の縮小の結果は次のようになります。上下で縮んで円の模様が楕円になっているのがわかると思います。
ここまでで画像の切り取りまたは縮小で、画像のサイズを1200px:675pxに変換することができました。
ただ、画像の容量は、切り取りまたは縮小した後でも100KBを超えています。
次は画像の圧縮をみていきます。
Pythonでブログ画像を100KB以下に圧縮
まずは、画像を容量を100KB以下にするための圧縮率を算定する関数を作ります。
イメージとしては、次のグラフの緑の星の部分の圧縮率を見つけ出すという処理になります。
この圧縮率を算定するプログラムは次のようになります。
def to_100kb_ratio(img):
"""
インプット画像のファイルサイズが100KB以下となる最大の圧縮率を返す
Parameter
-------------------
img: インプット画像のnumpy.ndarray
Return
-------------------
画像の容量が100KB以下となる最大の圧縮率
"""
#圧縮率を10%から95%まで5%刻みで指定する。
comp_ratio_list = [i*5 for i in range(2, 20)]
output_size_list = []
tmp = []
for comp_ratio in comp_ratio_list:
#画像imgを圧縮率comp_ratioで書き出し
cv2.imwrite("output.jpg", img, [cv2.IMWRITE_JPEG_QUALITY, comp_ratio])
#圧縮率comp_rateごとに書き出した画像ファイルの容量を要素に追加
output_size = os.path.getsize("output.jpg")
output_size_list.append(output_size)
if output_size <= 100000:
tmp.append(comp_ratio)
return max(tmp)
この関数によって、画像の容量を100KB以下とする最適な圧縮率を算定できます。
次のこの最適な圧縮率で、実際に圧縮するプログラムを書きます。
def to_100kb(img, filename):
"""
インプット画像を100KB以下にする画像を生成する。
Parameter
-------------------
img: インプット画像のnumpy.ndarray
filename: 生成する画像のファイル名
Return
-------------------
なし
"""
cv2.imwrite(filename, img, [cv2.IMWRITE_JPEG_QUALITY, to_100kb_ratio(img)])
プログラムの処理自体は、1行で書けます。
ここまでで画像の容量を100KB以下にするプログラムができました。
最後に、テスト画像を今回は切り取りで100KB以下の画像に加工してみましょう。
※画像の読み込みから一通り書いています。
########## 画像の読み込み ##########
img = cv2.imread('input.jpg') #numpy.ndarrayとなる
########## 画像の切り取り ##########
height = img.shape[0]
width = img.shape[1]
i = int((height-675)/2)
j = int((width-1200)/2)
img2 = img[i:i+675, j:j+1200]
plt.imshow(img2)
cv2.imwrite("output2.jpg", img2)
########## 画像の圧縮 ##########
to_100kb(img2, 'output2.jpg')
print('容量:{}KB'.format(int(os.path.getsize("output2.jpg") /1000)))
print('サイズ:{}×{}'.format(img2.shape[1], img2.shape[0]))
結果は、次の通りとなり、容量が100KB以下で、1200px × 675pxの画像を生成することができました。
いかがでしたでしょうか?
Pythonを用いることで、ブログ用の画像も簡単に加工できそうですよね。
もしこうした方がいいよ〜とか、ここが分からない等ありましたら、Twitterまで連絡をお待ちしています。
最後まで読んでいただき、ありがとうございました。
今回の処理をpyファイルで実行したい