[Python]korniaの使い方とtorchvisionとの比較

2022年1月20日木曜日

Artificial Intelligence

本記事では、torchvisionとkorniaを用いた画像処理一覧と処理結果の比較を紹介します。

アイキャッチ

概要

torchvision

torchvisionは、Pytorchと連携可能なコンピュータービジョン用ライブラリです。
画像変換、学習済みモデルのダウンロード、データセットのダウンロードなどの機能が提供されています。

$ pip3 install torch torchvision torchaudio

上記のようにpytorchと一緒にインストールされることが多くpytorchを使うなら一緒に必ずインストールしているライブラリです。

kornia

korniaも同様に、Pytorchと連携可能なコンピュータービジョン用ライブラリです。
torchvisionと異なり、画像変換に特化した機能が提供されています。

torchvisionの後発になるため、画像変換の種類等が拡張されています。

画像変換一覧

korniaとtorchvisionの画像変換をサンプルコードと共に紹介します。

なお、このデモはPythonで実装しています。
Pythonの実装に不安がある方、Pythonを使った機械学習について詳しく勉強したい方は、以下の書籍やオンライン講座などがおすすめです。

本記事では、こちらの画像に様々な画像変換処理を行っていきます。

オリジナル画像

HorizontalFlip

画像を水平方向に反転します。

in_tensor = to_tensor(img)
in_pil = img

# Kornia
RHF = K.augmentation.RandomHorizontalFlip(p=1., return_transform = True)
out_tensor, _ = RHF(in_tensor)
# torchvision
out_pil = tvF.hflip(in_pil)

concat = get_compare_img(to_pil(out_tensor.squeeze()), out_pil)
concat

左側がkornia、右側がtorchvisionです。

水平方向に反転した画像

VerticalFlip

画像を垂直方向に反転します。

in_tensor = to_tensor(img)
in_pil = img

# Kornia
RVF = K.augmentation.RandomVerticalFlip(p=1., return_transform = True)
out_tensor, _ = RVF(in_tensor)
# torchvision
out_pil = tvF.vflip(in_pil)

concat = get_compare_img(to_pil(out_tensor.squeeze()), out_pil)
concat
垂直方向に反転した画像

Rotation

画像を回転します。torchvisionと比較し、Korniaの出力結果はエッジが滑らかです。

in_tensor = to_tensor(img)
in_pil = img

degrees = 45 #@param {type:"slider", min:0, max:360, step:1.0}
# Kornia
RR = K.augmentation.RandomRotation(p=1.,degrees=degrees, return_transform = True)
out_tensor, _ = RR(in_tensor)
# torchvision
out_pil = tvF.rotate(in_pil, angle=RR._params['degrees'].item())

concat = get_compare_img(to_pil(out_tensor.squeeze()), out_pil)
concat
rotate画像

CenterCrop

画像の中心部分をCropping(切り抜き)します。

in_tensor = to_tensor(img)
in_pil = img

xy = (300, 300)
# Kornia
CC = K.augmentation.CenterCrop(p=1.,size=xy, return_transform = True)
out_tensor, _ = CC(in_tensor)
# torchvision
out_pil = tvF.center_crop(in_pil, xy)

concat = get_compare_img(to_pil(out_tensor.squeeze()), out_pil)
concat
CenterCrop画像

Erasing

画像の一部分を除去します。

in_tensor = to_tensor(img)
in_pil = img

# Kornia
RE = K.augmentation.RandomErasing(
    scale=torch.tensor([0.1, 0.2]), 
    ratio=torch.tensor([0.3, 0.3]),
    p=1., return_transform = True)
out_tensor, _ = RE(in_tensor)
# torchvision
out_tv_tensor = tvF.erase(
    tensor_pre_transform_wrapper(in_tensor.unsqueeze(dim=0)).squeeze(), 
    int(RE._params["ys"].item()), int(RE._params["xs"].item()), 
    int(RE._params["heights"].item()), int(RE._params["widths"].item()),
    0
    )

concat = get_compare_img(to_pil(out_tensor.squeeze()), to_pil(out_tv_tensor.squeeze()))
concat
erasing画像

Affine変換

画像の拡大縮小、回転、平行移動などを行列を使って座標を変換します。torchvisionと比較し、Korniaの出力結果はエッジが滑らかです。

in_tensor = to_tensor(img)
in_pil = img

# Kornia
RA = K.augmentation.RandomAffine(
    degrees=120.,
    translate=torch.tensor([0.1, 0.2]),
    scale=torch.tensor([0.5, 0.9]),
    shear=torch.tensor([10., 20.]),
    p=1., return_transform = True)
out_tensor, _ = RA(in_tensor)
# torchvision
out_pil = tvF.affine(
    in_pil, 
    angle=RA._params['angle'].item(), translate=RA._params['translations'].numpy()[0].tolist(),
    scale=RA._params['scale'][0][0], 
    shear=[RA._params['sx'].item(), RA._params['sy'].item()]
    )

concat = get_compare_img(to_pil(out_tensor.squeeze()), out_pil)
concat
affine変換画像

Perspective変換

任意の形の四角形から別の形の四角形に変換します。torchvisionと比較し、Korniaの出力結果はエッジが滑らかです。

in_tensor = to_tensor(img)
in_pil = img

# Kornia
RP = K.augmentation.RandomPerspective(
    p=1., return_transform = True)
out_tensor, _ = RP(in_tensor)
# torchvision
out_pil = tvF.perspective(
    in_pil,
    startpoints=RP._params["start_points"].squeeze().numpy().tolist(),
    endpoints=RP._params["end_points"].squeeze().numpy().tolist()
    )

concat = get_compare_img(to_pil(out_tensor.squeeze()), out_pil)
concat
perspective変換画像

Grayscale

ピクセルの標本値に光度以外の情報が含まれていない画像に変換します。

in_tensor = to_tensor(img)
in_pil = img

# Kornia
RG = K.augmentation.RandomGrayscale(
    p=1., return_transform = True)
out_tensor, _ = RG(in_tensor)
# torchvision
out_pil = tvF.to_grayscale(in_pil)

concat = get_compare_img(to_pil(out_tensor.squeeze()), out_pil)
concat
grayscale画像

コントラスト調整

コントラスト調整を行います。KorniaはOpenCVと同じアプローチを採用しています。

in_tensor = to_tensor(img)
in_pil = img

factor = 1.4 #@param {type:"slider", min:0.0, max:2.0, step:0.1}
# Kornia
# range 0~
out_tensor = K.enhance.adjust_contrast(in_tensor, float(factor))
# torchvision
# range 0~
out_pil = tvF.adjust_contrast(in_pil, float(factor))

concat = get_compare_img(to_pil(out_tensor.squeeze()), out_pil)
concat
コントラスト調整画像

明るさ調整

画像の明るさを調整します。KorniaはOpenCVと同じアプローチを採用しています。

in_tensor = to_tensor(img)
in_pil = img

factor = 0.2 #@param {type:"slider", min:0.0, max:1.0, step:0.1}
# Kornia
# range 0~1
out_tensor = K.enhance.adjust_brightness(in_tensor, float(factor))
# torchvision
# 0:背景、1:入力画像そのまま、1~
out_pil = tvF.adjust_brightness(in_pil, float(factor)+1.0)

concat = get_compare_img(to_pil(out_tensor.squeeze()), out_pil)
concat
明るさ調整

色相調整

赤色(R)、イエロー(Y)、緑色(G)、シアン(C)、青色(B)、マゼンタ(M)それぞれの色調を、色相環の回転方向に調整します。KorniaはOpenCVと同じアプローチを採用しています。

in_tensor = to_tensor(img)
in_pil = img

factor = 0.4 #@param {type:"slider", min:0.0, max:1.0, step:0.1}
# Kornia
# range 0~1
out_tensor = K.enhance.adjust_hue(in_tensor, float(factor))
# torchvision
# range -0.5~0.5
out_pil = tvF.adjust_hue(in_pil, float(factor)-0.5)

concat = get_compare_img(to_pil(out_tensor.squeeze()), out_pil)
concat
色相調整画像

ガンマ調整

画像の階調の応答特性を示す数値の調整します。

in_tensor = to_tensor(img)
in_pil = img

factor = 0.2 #@param {type:"slider", min:0, max:1, step:0.1}
# Kornia
# range 0~1
out_tensor = K.enhance.adjust_gamma(in_tensor, float(factor))
# torchvision
# range 0~1
out_pil = tvF.adjust_gamma(in_pil, float(factor))

concat = get_compare_img(to_pil(out_tensor.squeeze()), out_pil)
concat
ガンマ調整画像

彩度調整

色空間の中央軸からの距離の調整します。無彩色で0です。

in_tensor = to_tensor(img)
in_pil = img

factor = 0.4 #@param {type:"slider", min:0.0, max:2.0, step:0.1}
# Kornia
# range 0~2
out_tensor = K.enhance.adjust_saturation(in_tensor, float(factor))
# torchvision
# range 0~2
out_pil = tvF.adjust_saturation(in_pil, float(factor))

concat = get_compare_img(to_pil(out_tensor.squeeze()), out_pil)
concat
彩度調整画像

ブラー加工

画像をぼやけさせます。

in_tensor = to_tensor(img)
in_pil = img

# Kornia
RMG = K.augmentation.RandomGaussianBlur(
    kernel_size=(21, 21), 
    sigma=(2.0, 2.0),
    p=1., return_transform = True)
out_tensor, _ = RMG(in_tensor)
# torchvision
out_pil = tvF.gaussian_blur(
    in_pil, 
    kernel_size=list(RMG.flags['kernel_size']), 
    sigma=list(RMG.flags['sigma'])
    )

concat = get_compare_img(to_pil(out_tensor.squeeze()), out_pil)
concat
blur画像

モーションブラー加工

画像に動きのあるブレを付与します。torchvisionにモーションブラーを付与する機能はありません。

in_tensor = to_tensor(img)
in_pil = img

# Kornia
RM = K.augmentation.RandomMotionBlur(
    kernel_size=11, angle=30.,
    direction=0.4,
    p=1., return_transform = True)
out_tensor, _ = RM(in_tensor)
# torchvision
out_pil = in_pil

concat = get_compare_img(to_pil(out_tensor.squeeze()), out_pil)
concat
モーションブラー画像

ソラリゼーション

画像に白黒反転加工を行います。
カメラのネガフィルムのような画像になります。

in_tensor = to_tensor(img)
in_pil = img

thresholds = 0.4 #@param {type:"slider", min:0.0, max:2.0, step:0.1}
# Kornia
RS = K.augmentation.RandomSolarize(
    thresholds=thresholds,
    p=1., return_transform = True)
out_tensor, _ = RS(in_tensor)
# torchvision
out_pil = tvF.solarize( in_pil, thresholds )

concat = get_compare_img(to_pil(out_tensor.squeeze()), out_pil)
concat
白黒反転画像

イコライズ

画像の明るさ、カラー成分を平均化します。

in_tensor = to_tensor(img)
in_pil = img

# Kornia
RE = K.augmentation.RandomEqualize(
    p=1., return_transform = True)
out_tensor, _ = RE(in_tensor)
# torchvision
out_pil = tvF.equalize( in_pil )

concat = get_compare_img(to_pil(out_tensor.squeeze()), out_pil)
concat
イコライズ画像

ポスタライゼーション

トーンの連続的なグラデーションをトーンの少ないいくつかの領域に変換します。

in_tensor = to_tensor(img)
in_pil = img

bits=2 #@param {type:"slider", min:0, max:8, step:1}
# Kornia
out_tensor = K.enhance.posterize(in_tensor, bits)

# torchvision
out_pil = tvF.posterize( in_pil, bits )

concat = get_compare_img(to_pil(out_tensor.squeeze()), out_pil)
concat
ポスタライズ画像

シャープネス

画像の輪郭を調整します。

in_tensor = to_tensor(img)
in_pil = img

sharpness=100 #@param {type:"slider", min:0, max:2, step:0.1}
# Kornia
out_tensor = K.enhance.sharpness(in_tensor, sharpness)

# torchvision
out_pil = tvF.adjust_sharpness( in_pil, sharpness )

concat = get_compare_img(to_pil(out_tensor.squeeze()), out_pil)
concat
sharpness画像

まとめ

本記事では、korniaとtorchvisionの画像変換方法を紹介しました。
画像分類や、物体検出の学習時にData Augmentationを行うケースは多々あると思います。

モーションブラーなど自力で実装するとなるとなかなか骨が折れます。ライブラリを活用して楽に開発していきたいものです。

また本記事では、画像変換処理にフォーカスしてご紹介しました。
機械学習について学術的に体系立てて学びたいという方には以下の書籍などがお勧めです。ぜひご一読下さい。


また動かせるだけから理解して応用できるエンジニアの足掛かりに下記のUdemyなどもお勧めです。

AIで副業ならココから!

まずは無料会員登録

プロフィール

メーカーで研究開発を行う現役エンジニア
組み込み機器開発や機会学習モデル開発に従事しています

本ブログでは最新AI技術を中心にソースコード付きでご紹介します


Twitter

カテゴリ

このブログを検索

ブログ アーカイブ

TeDokology