Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Evision による画像処理

image_processing.livemd

Evision による画像処理

Mix.install([
  {:req, "~> 0.5"},
  {:evision, "~> 0.2"},
  {:kino, "~> 0.14"},
  {:nx, "~> 0.9"}
])

画像生成

[
  [
    [255, 0, 0],
    [255, 128, 0],
    [255, 255, 0]
  ],
  [
    [0, 255, 0],
    [0, 255, 128],
    [0, 255, 255]
  ],
  [
    [0, 0, 255],
    [128, 0, 255],
    [255, 0, 255]
  ]
]
|> Nx.tensor(type: {:u, 8})
# Evision のマトリックスに変換
|> Evision.Mat.from_nx_2d()
# 見やすいように拡大
|> Evision.resize({300, 300}, interpolation: Evision.Constant.cv_INTER_AREA())

画像のダウンロード

img_binary =
  "https://www.elixirconf.eu/assets/images/ryo-wakabayashi.jpg"
  |> Req.get!()
  |> Map.get(:body)
img = Evision.imdecode(img_binary, Evision.Constant.cv_IMREAD_COLOR())

画像の書込

img_path = "rwakabay.jpg"

Evision.imwrite(img_path, img)

画像の読込

img = Evision.imread(img_path)
size = Evision.Mat.shape(img)
Evision.Mat.to_nx(img)

リサイズ

Evision.resize(img, {256, 128})

グレースケール

Evision.imread(img_path, flags: Evision.Constant.cv_IMREAD_GRAYSCALE())
Evision.cvtColor(img, Evision.Constant.cv_COLOR_BGR2GRAY())

二値化

{threshold, mono_img} =
  img_path
  |> Evision.imread(flags: Evision.Constant.cv_IMREAD_GRAYSCALE())
  |> Evision.threshold(127, 255, Evision.Constant.cv_THRESH_BINARY())

IO.inspect(threshold)

mono_img

並進

affine =
  [
    [1, 0, 100],
    [0, 1, 50]
  ]
  |> Nx.tensor(type: :f32)

Evision.warpAffine(img, affine, {512, 512})

回転

affine = Evision.getRotationMatrix2D({512 / 2, 512 / 2}, 70, 1)

Evision.warpAffine(img, affine, {512, 512})

ぼかし

Evision.blur(img, {9, 9})
Evision.medianBlur(img, 9)
Evision.gaussianBlur(img, {9, 9}, 5)

図形描画

img
# 直線
|> Evision.line(
  # 始点{x, y}
  {200, 400},
  # 終点{x, y}
  {300, 450},
  # 色{R, G, B}
  {0, 255, 255},
  # 線の太さ
  thickness: 5
)
# 矢印
|> Evision.arrowedLine(
  # 始点{x, y}
  {300, 200},
  # 終点{x, y}
  {400, 150},
  # 色{R, G, B}
  {255, 255, 0},
  # 線の太さ
  thickness: 3,
  # 頭の大きさ
  tipLength: 0.3
)
img
# 四角形
|> Evision.rectangle(
  # 左上{x, y}
  {150, 120},
  # 右下{x, y}
  {225, 320},
  # 色{R, G, B}
  {0, 0, 255},
  # 線の太さ
  thickness: 12,
  # 線の引き方(角がギザギザになる)
  lineType: Evision.Constant.cv_LINE_4()
)
|> Evision.rectangle(
  # 左上{x, y}
  {50, 120},
  # 右下{x, y}
  {125, 320},
  # 色{R, G, B}
  {0, 0, 255},
  # 線の太さ
  thickness: 12,
  # 線の引き方(角が滑らかになる)
  lineType: Evision.Constant.cv_LINE_AA()
)
|> Evision.rectangle(
  # 左上{x, y}
  {250, 60},
  # 右下{x, y}
  {325, 110},
  # 色{R, G, B}
  {0, 255, 0},
  # 塗りつぶし
  thickness: -1
)
img
# 円
|> Evision.circle(
  # 中心{x, y}
  {100, 100},
  # 半径
  50,
  # 色{R, G, B}
  {255, 0, 0},
  # 塗りつぶし
  thickness: -1
)
# 楕円
|> Evision.ellipse(
  # 中心{x, y}
  {300, 300},
  # {長径, 短径}
  {100, 200},
  # 回転角度
  30,
  # 弧の開始角度
  0,
  # 弧の終了角度
  360,
  # 色{R, G, B}
  {255, 255, 0},
  # 線の太さ
  thickness: 3
)
# 扇形
|> Evision.ellipse(
  # 中心{x, y}
  {400, 200},
  # {長径, 短径}
  {100, 100},
  # 回転角度
  0,
  # 弧の開始角度
  100,
  # 弧の終了角度
  200,
  # 色{R, G, B}
  {0, 255, 0},
  # 塗りつぶし
  thickness: -1
)

文字描画

img
|> Evision.putText(
  # 文字列
  "Ryo",
  # 左下{x, y}
  {250, 200},
  # フォント種類
  Evision.Constant.cv_FONT_HERSHEY_SIMPLEX(),
  # フォントサイズ
  2.5,
  # 文字色
  {0, 0, 255},
  # 文字太さ
  thickness: 5
)

Nx による画像の縦横変換

img
|> Evision.Mat.to_nx(Nx.BinaryBackend)
|> Nx.transpose(axes: [1, 0, 2])
|> Evision.Mat.from_nx_2d()
|> dbg

Nx による画像のグレースケール化

img
|> Evision.Mat.to_nx(Nx.BinaryBackend)
|> Nx.mean(axes: [2])
|> Nx.broadcast({600, 600, 3}, axes: [0, 1])
|> Evision.Mat.from_nx_2d()
|> dbg