3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

「...サクッと画像加工するノリ」の猿まねをやってみた💦

Last updated at Posted at 2022-01-07

1.はじめに

@piacerexさんのQiita記事【「JupyterNotebook + NumPyでサクッと画像加工するノリ」をElixirでやってみた】に触発されて、拙作の cimg_exでもやってみようと思い立った。要は猿まねである🐵

まず最初に、Livebookのインストールならびに起動etc.に関しては、@piacerexさんの記事を参照して頂きたい。そう、手抜きである。以下、Livebookが起動できて、無事ブラウザを接続出来たものとして話を進める。

本記事を通して必要となるモジュールは下記の4つである。
Elixir cellの左上の"Evaluate"ボタンを押すか、cell内でctrl+Enterをキーインしてインストールを実行する。

Mix.install([
  {:cimg, "~> 0.1.6"},
  {:nx, "~> 0.1.0"},
  {:kino, "~> 0.3.1"},
  {:download, "~> 0.0.4"}
])

次に、@piacerexさんの記事に倣って、旧世代の画像処理屋にとっては超有名人のLennaさんの画像をダウンロードしておく。ここまでが前準備だ。

File.rm("Lenna_%28test_image%29.png")

lenna =
  Download.from("https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png")
  |> elem(1)

2.CImgでサクッと猿まねする

猿まねなので、やってみる画像加工の課題は元記事と同じく次の3つだ。

  1. Lennaさん画像をロードして、KinoでLivebookに表示
  2. グレイ画像に変換して表示
  3. 反転画像に変換して表示

課題1のコードは次の通り。CImg.load/1で画像を読み込み、その画像をjpegフォーマットに変換し Kino.Image.new/2に渡しておしまい。

img = CImg.load(lenna)

img
|> CImg.to_jpeg() # CImg画像をjpegバイナリに変換する
|> Kino.Image.new(:jpeg)

image.png

課題2のコードは次の通り。

img
|> CImg.gray() # グレイ画像に変換する
|> CImg.to_jpeg()
|> Kino.Image.new(:jpeg)

image.png

課題3のコードは次の通り。

img
|> CImg.invert() # カラー反転画像に変換する
|> CImg.to_jpeg()
|> Kino.Image.new(:jpeg)

image.png

……記事になる内容が無かった orz

3.Nxを使ってごにょごにょやってみる

このままでは薄っぺらな記事にしかならないので、Nxを使って次の2つの課題をやってみる。要は記事の水増しである。

  1. Lennaさんの画像をR/G/Bそれぞれのカラー・プレーンに分割して表示
  2. Rプレーンを差し替えた画像を合成して表示

これらの課題は、cimg_exが目的とする用途ではたぶん発生しないので、機能として実装していない。ゆえに、Nxを使ってごにょごにょとやることになる。数行のコードで終わるなんてことはない…きっと

課題4に取り掛かろう。
まず CImg画像を Nx.tensorに変換する。CImg.to_flat/2を用いると CImg画像をバイナリにシリアライズすることができる(正しくはNpy形式)。そのバイナリを Nx.from_binary/3に食わして、Nx.reshape/3で整形し Nx.tensor rgbを得る。この時点では、tensorに格納されている画像データは所謂 (N)HWC形式になっている。

rgb =
  CImg.to_flat(img, [{:dtype, "<u1"}]).data  # CImg画像をバイナリにシリアライズする(NHWCオーダー)
  |> Nx.from_binary({:u, 8})
  |> Nx.reshape({512, 512, :auto})

image.png

画像データをR/G/Bの各カラー・プレーンに分割するには、(N)HWC形式よりも(N)CHW形式の画像データの方が都合が良いので、Nx.transpose/2でrgbの軸を入れ替えて(N)CHW形式に変換する。これで tensorの一軸目のインデックスが色を表すことになったので、あとは red=tensor[0], green=tensor[1], blue=tensor[2]の様に分割すればよい。

[red, green, blue] =
  Nx.transpose(rgb, axes: [2, 0, 1]) # NHWCからNCHWに変換する
  |> (&[&1[0], &1[1], &1[2]]).()  # R/G/Bに分割する

image.png

さて、無事に画像データをR/G/Bの tensor - red, green, blue - に分割出来たわけだが、今やそれらのtensorは 24bitカラー情報を持っておらず、カラー・プレーン毎の 8bitの輝度情報しか持っていない。つまり、red, green, blueをそのままCImg画像に戻すと、赤,緑,青の画像にはならないのだ。それぞれで足らない色情報をゼロで補い、24bitカラー情報に加工する必要がある。

加工で必要となる zero tensorを用意しよう。

zero = Nx.broadcast(0, {512, 512}) |> Nx.as_type({:u, 8})

image.png

課題4の総仕上げだ。
tensorの組、赤{red,zero,zero}, 緑{zero,green,zero}, 青{zero,zero,blue}を、それぞれ Nx.concatenate/2(4行目)で合成し、それら3つの合成 tensorを縦に繋げて一つにする(6行目)。これを Nx.to_binary/2でシリアライズし、CImg.create_from_bin/6で CImg画像に戻す。あとは例の如く。(完)

res =
  [red, zero, zero, zero, green, zero, zero, zero, blue]
  |> Enum.map(&Nx.reshape(&1, {512, 512, 1}))  # 4行目のconcatenate/2の為に軸を増やす
  |> Enum.chunk_every(3)
  |> Enum.map(&Nx.concatenate(&1, axis: 2))  # R/G/B [512][512][3] のそれぞれの画像データを合成する
  |> IO.inspect()
  |> Nx.concatenate()  # R/G/BをH方向に繋げて一つの画像データにする
  |> Nx.to_binary()
  |> CImg.create_from_bin(512, 512 * 3, 1, 3, "<u1")  # CImg画像に変換する
  |> CImg.to_jpeg()
  |> Kino.Image.new(:jpeg)

image.png
image.png

課題5は、課題4の応用だ。
Rプレーンのデータを Gプレーンで置き換えてみた。ブルーが映えるモノクロームな画像になった。予想外だ。コードの説明は省略する。

res =
  [green, green, blue]  # RのデータをGのデータで置き換える
  |> Enum.map(&Nx.reshape(&1, {512, 512, 1}))
  |> Nx.concatenate(axis: 2)
  |> IO.inspect()
  |> Nx.to_binary()
  |> CImg.create_from_bin(512, 512, 1, 3, "<u1")
  |> CImg.to_jpeg()
  |> Kino.Image.new(:jpeg)

image.png
image.png

4.まとめ

以上、猿まねとNxでごにょごにょをやってみた。結局中身が無い記事になったよーな…

[注釈]
拙作の cimg_exは、組み込みDeep Learningエンジンと組み合すことを狙いとした、ライト・ウエイトな画像処理モジュールを目指している。そのため、SHIFT局所特徴量検出やCannyエッジ検出、はたまた表示機能やカメラ制御など、現場ではほぼ不要と思われる機能は搭載していない。そう、実はこの記事の様な汎用的な用途には向かないのだ。パッと見には機能が少なく貧相に見えるが、同じく拙作のTensorflow lite拡張 TflInterpと組み合わせていくつか Deep Learningのデモを書いてみたところ、案外これで十分だったりするのだが…

3
2
1

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
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?