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

Nx.Tensorの真ん中を求める

nx_mean.livemd

Nx.Tensorの真ん中を求める

Mix.install(
  [
    {:nx, "~> 0.5.0"},
    {:exla, "~> 0.5.0"},
    {:evision, "0.1.30"},
    {:kino, "~> 0.7.0"}
  ],
  config: [
    nx: [default_backend: EXLA.Backend]
  ]
)

alias Evision, as: Cv

いろんな真ん中

いろんな真ん中が考えられそうです。

平均値(mean, average)

中央値(median)

中点(midpoint)

幾何中心(geometric center)

外心(circumcenter)

Nx.mean/2 で平均値を求める

points_nx = Nx.tensor([1, 1, 1, 2, 2, 2, 3, 3, 123, 456])
points_nx |> Nx.mean() |> Nx.to_number()

Nx.median/2 で中央値を求める

points_nx = Nx.tensor([1, 1, 1, 2, 2, 2, 3, 3, 123, 456])
points_nx |> Nx.median() |> Nx.to_number()

Nx.mean/2 で座標空間上の中点を求める

points_nx =
  Nx.tensor(
    [
      [50, 80],
      [220, 230]
    ],
    names: [:point, :value]
  )

[midpoint_x, midpoint_y] =
  points_nx
  |> Nx.mean(axes: [:point])
  |> Nx.to_list()
{img_height, img_width} = {300, 300}
default_color = {255, 255, 255}
midpoint_color = {0, 255, 0}

background_mat =
  Nx.tensor([0, 0, 0], type: :u8)
  |> Nx.broadcast({img_height, img_width, 3})
  |> Cv.Mat.from_nx_2d()

Enum.reduce(
  Nx.to_list(points_nx),
  background_mat,
  fn [x, y], acc_mat ->
    Cv.drawMarker(acc_mat, {trunc(x), trunc(y)}, default_color)
  end
)
|> Cv.drawMarker({trunc(midpoint_x), trunc(midpoint_y)}, midpoint_color, thickness: 2)

Nx.mean/2 で幾何中心を求める

単純な重心であれば各座標の平均で求められるそうです。

点群データ上のおける重心検出する方法について

points_nx =
  Nx.tensor(
    [
      [50, 100],
      [120, 230],
      [220, 60]
    ],
    names: [:point, :value]
  )

[midpoint_x, midpoint_y] =
  points_nx
  |> Nx.mean(axes: [:point])
  |> Nx.to_list()
{img_height, img_width} = {300, 300}
default_color = {255, 255, 255}
midpoint_color = {0, 255, 0}

background_mat =
  Nx.tensor([0, 0, 0], type: :u8)
  |> Nx.broadcast({img_height, img_width, 3})
  |> Cv.Mat.from_nx_2d()

Enum.reduce(
  Nx.to_list(points_nx),
  background_mat,
  fn [x, y], acc_mat ->
    Cv.drawMarker(acc_mat, {trunc(x), trunc(y)}, default_color)
  end
)
|> Cv.drawMarker({trunc(midpoint_x), trunc(midpoint_y)}, midpoint_color, thickness: 2)

Evision.minEnclosingCircle/1 で外接円の中心を求める

points_nx =
  Nx.tensor(
    [
      [50.0, 100.0],
      [120.0, 230.0],
      [220.0, 60.0]
    ],
    names: [:point, :value]
  )

{{center_x, center_y}, radius} = Cv.minEnclosingCircle(points_nx)
{img_height, img_width} = {300, 300}
default_color = {255, 255, 255}
circle_color = {0, 255, 0}

background_mat =
  Nx.tensor([0, 0, 0], type: :u8)
  |> Nx.broadcast({img_height, img_width, 3})
  |> Cv.Mat.from_nx_2d()

Enum.reduce(
  Nx.to_list(points_nx),
  background_mat,
  fn [x, y], acc_mat ->
    Cv.drawMarker(acc_mat, {trunc(x), trunc(y)}, default_color)
  end
)
|> Cv.circle({trunc(center_x), trunc(center_y)}, ceil(radius), circle_color, thickness: 2)
|> Cv.drawMarker({trunc(center_x), trunc(center_y)}, circle_color, thickness: 2)