カオスノカケラ

めもちょう

PyTorchで画像縮小アルゴリズム

pytorch で area average な画像縮小を試してみる.

概要

画像のサイズを変更する画像補間手法は多々存在する. しかしながら,一般によく知られている bilinear や bicubic,nearest-neighbor を 使って画像縮小をすると,巨大な画像を小さくする場合ではジャギーが目立つ. したがって,綺麗に画像縮小を行いたい場合は area average を用いるのがよい. 本稿では pytorch で画像縮小を行う方法について簡単なコードで見ていく.

area averageとは

area average は, サンプリング点同士の間を等分して得られる領域の平均の画素値を計算するアルゴリズムである. bilinearやbicubic は入力画像中でサンプリング点座標近傍の4点や16点しか見ない. 一方で,area average であればサンプリング点がたとえば100画素ぶん離れていれば 100x100 の領域の平均値を出力画素の画素値とする.

f:id:yuuhopro:20200706183208j:plain
アルゴリズムの違い

要するに average pooling である. サンプリング点が離れれば離れるほど, bicubic よりも area を使うほうが良い感じになる.

pytorchの画像リサイズ関数

pytorch では画像をリサイズするための torch.nn.functional.interpolate() が用意されている. 使用できるアルゴリズムは,現時点(ver1.5.1)では

  • nearest
  • linear
  • bilinear
  • bicubic
  • trilinear
  • area

であり,おそらく area が area average に該当する. pytorch 最新版documentation

適当に動かして確認する

まずは画像を適当に用意する.3024x3024のデカイ画像を用意した. デカくて載らないので圧縮済みのものを載せておく.

f:id:yuuhopro:20200706180523j:plain
元画像 3024x3024 掲載のものはjpg品質50に圧縮済み

コード

import numpy as np
import cv2
import torch
import torch.nn.functional as F


if __name__ == '__main__':
    img = cv2.imread('curry.png',cv2.IMREAD_COLOR)

    # pytorchに持ってくる (1,C,H,W)
    tensor = torch.from_numpy(img.astype(np.float32)).permute(2,0,1)[None,:,:,:]
    
    # area average での縮小
    out = F.interpolate(tensor,size=(256,256),mode='area')
    ndarr = out[0].permute(1,2,0).numpy().astype(np.uint8)
    cv2.imwrite('out_area.png',ndarr)

    # bicubic での縮小
    out = F.interpolate(tensor,size=(256,256),mode='bicubic',align_corners=False).clamp(0.0,255.0)
    ndarr = out[0].permute(1,2,0).numpy().astype(np.uint8)
    cv2.imwrite('out_cubic.png',ndarr)

結果

f:id:yuuhopro:20200706180922p:plain
area average 縮小

f:id:yuuhopro:20200706180945p:plain
bicubic 縮小

この写真ではよくわからないかもしれないが, 皿のフチの部分がbicubicはジャギっているのがわかる. 128x128 などもっと低解像度に縮小すればより顕著に現れる.

著作権の関係で載せないが,アニメや漫画の画像であればよりわかりやすくこの現象が見てとれる.

結論

深層学習などで画像を縮小して読み込まなければいけない場合, bicubicなどを使うのではなく area average を使うべきである.