LoginSignup
5
1

Elixir Image と Nx と evision で相互変換

Last updated at Posted at 2023-02-12

はじめに

Elixir の Image モジュールは軽量、高速な画像処理モジュールです

Elixir には他にも画像を扱うことのできるモジュールとして、 Nx と evision があります

Image は libvips というライブラリを利用していて、 Vix.Vips.Image という構造体で画像を扱います

Nx は画像を横×縦×チャネル(RGBなどの色空間)のテンソル Nx.Tensor として扱います

evision は OpenCV のラッパーになっていて、画像は行列(マトリックス) Evision.Mat として扱います

Image モジュールにはこれらの相互変換用関数が用意されているため、これら全ては連携可能です

いつものように Livebook を使います

実装したノートブックはコチラ

実行環境

  • Elixir: 1.14.2 OTP 24
  • Livebook: 0.9.3

以下のリポジトリーの Docker コンテナ上で起動しています

Docker が使える環境であれば簡単に実行できます

https://docs.docker.com/engine/install/

Docker Desktop を無償利用できない場合は Rancher Desktop を使ってください

https://rancherdesktop.io/

セットアップ

必要なモジュールをインストールします

Mix.install([
  {:image, "~> 0.35"},
  {:nx, "~> 0.5"},
  {:evision, "~> 0.1"},
  {:req, "~> 0.3"},
  {:kino, "~> 0.9"}
])

Req は画像を Web からダウンロードするのに使っています

画像の読込

毎度の如くレナさんの画像をダウンロードしてきます

まず最初は Image.from_binary で読み込み、 Vix.Vips.Image の形にしておきます

lenna_img =
  "https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png"
  |> Req.get!()
  |> then(& &1.body)
  |> Image.from_binary!()

image.gif

Vix.Vips.Image の場合、画像自体と属性情報のタブが表示されます

Image から Nx

Image.to_nxVix.Vips.Image から Nx.Tensor に変換します

{:ok, nx_lenna_img} = Image.to_nx(lenna_img)

nx_lenna_img

実行結果は以下のようにテンソルになっています

#Nx.Tensor<
  u8[width: 512][height: 512][bands: 3]
  [
    [
      [226, 137, 125],
      [226, 137, 125],
      ...
    ],
    ...
  ]
>

一応、テンソルを画像として表示します(画像上は何も変わりません)

lenna_img
|> Image.to_nx!()
|> Kino.Image.new()

lenna

Nx から Image

Image.from_nxNx.Tensor から Vix.Vips.Image に変換します

{:ok, image_lenna_img} = Image.from_nx(nx_lenna_img)

image_lenna_img

image.png

Image から evision

Image.to_evisionVix.Vips.Image から Evision.Mat に変換します

{:ok, evision_lenna_img} = Image.to_evision(lenna_img)

evision_lenna_img

evision.gif

Evision.Mat の場合は画像自体、行列としての情報、テンソルとしての情報をタブ表示します

evision から Image

Image.from_evisionEvision.Mat から Vix.Vips.Image に変換します

{:ok, image_lenna_img} = Image.from_evision(evision_lenna_img)

image_lenna_img

image.png

組み合わせ処理

単に変換するだけだと画像としては何も変わらないので、 evision と Image の組み合わせ処理を実装してみます

Image で四角形を描いた後、 evision で台形変換をしてみます

input =
  Nx.tensor(
    [
      [0, 0],
      [0, 512],
      [512, 0],
      [512, 512]
    ],
    type: :f32
  )

output =
  Nx.tensor(
    [
      [192, 256],
      [0, 512],
      [320, 256],
      [512, 512]
    ],
    type: :f32
  )

perspective_mat = Evision.getPerspectiveTransform(input, output)

lenna_img
|> Image.Draw.rect!(190, 200, 180, 200, fill: false, color: :red, stroke_width: 24)
|> Image.to_evision()
|> elem(1)
|> Evision.warpPerspective(perspective_mat, {512, 512})
|> Image.from_evision()
|> elem(1)

lenna_daikei.png

レナさんが何だか強そうになりました

まとめ

Image も evision もそれぞれ多様な関数を持っているので、組み合わせれば大概のことは実装できますね

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1