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

opencv_dl_ch4

opencv_dnn_ch4.livemd

opencv_dl_ch4

Mix.install([
  {:exla, "~> 0.4.0"},
  {:evision, "~> 0.1.19"},
  {:kino, "~> 0.7.0"}
])

setup

alias Evision, as: Ev
base = "/Users/shou/livebook_samples/images/"
test = base <> "test.jpg"
veggie = base <> "veggie.png"
choco = base <> "chocolates.jpg"

to_img = fn mat ->
  Ev.imencode(".png", mat) |> Kino.Image.new(:png)
end

ch4/4.1/load_image

img = Ev.imread(test)

Ev.HighGui.imshow("img", img)
# 強制終了しないと消えないので注意
# Ev.HighGui.waitKey(0)

ch4/4.1/load_image_colab

# skip

ch4/4.1/load_image_matplot

img = Ev.imread(test)

Ev.imencode(".png", img)
|> Kino.Image.new(:png)

ch4/4.2/grayscale

img_bgr = Ev.imread(veggie)
img_gray = Ev.cvtColor(img_bgr, Ev.cv_COLOR_BGR2GRAY())

ch4/4.2/split_hsv

img_hsv = Ev.cvtColor(img_bgr, Ev.cv_COLOR_BGR2HSV())

ch4/4.2split_hsv

[h, s, v] = Ev.split(img_hsv)
Ev.hconcat([h, s, v])

ch4/4.2/hsv_colorsspace

img_hsv =
  Enum.map(1..180, fn x ->
    Enum.map(0..255, fn y ->
      [x - 1, y, 255]
    end)
  end)
  |> Nx.tensor(type: :u8)
  |> Ev.Mat.from_nx_2d()
  |> Ev.cvtColor(Ev.cv_COLOR_HLS2RGB())

ch4/4.2/extract_blue

img_bgr = Ev.imread(choco)
img_hsv = Ev.cvtColor(img_bgr, Ev.cv_COLOR_BGR2HSV())

[h, s, v] = Ev.split(img_hsv)

h_list = Ev.Mat.to_nx(h) |> Nx.to_flat_list()
s_list = Ev.Mat.to_nx(s) |> Nx.to_flat_list()

mask =
  Enum.zip_with([h_list, s_list], fn [hue, stu] ->
    if 80 < hue and hue < 140 and stu < 70, do: 255, else: 0
  end)
  |> Nx.tensor(type: :u8)
  |> Nx.reshape(Ev.Mat.shape(h))
  |> Ev.Mat.from_nx()
  |> Ev.morphologyEx(Ev.cv_MORPH_CLOSE(), Ev.Mat.ones({64, 64}, :u8))
  |> Ev.cvtColor(Ev.cv_COLOR_GRAY2RGB())

result_img = Ev.Mat.bitwise_and(img_bgr, mask)

images = [
  to_img.(Ev.cvtColor(img_bgr, Ev.cv_COLOR_BGR2RGB())),
  to_img.(h),
  to_img.(s),
  to_img.(v),
  to_img.(mask),
  to_img.(result_img)
]

Kino.Layout.grid(images, columns: 3)

ch4/4.3/thresh

src_img =
  Nx.iota({256}, type: :u8)
  |> Nx.tile([256])
  |> Nx.reshape({256, 256})
  |> Ev.Mat.from_nx()

{_, th1} = Ev.threshold(src_img, 127, 255, Ev.cv_THRESH_BINARY())
{_, th2} = Ev.threshold(src_img, 127, 255, Ev.cv_THRESH_BINARY_INV())
{_, th3} = Ev.threshold(src_img, 127, 255, Ev.cv_THRESH_TRUNC())
{_, th4} = Ev.threshold(src_img, 127, 255, Ev.cv_THRESH_TOZERO())
{_, th5} = Ev.threshold(src_img, 127, 255, Ev.cv_THRESH_TOZERO_INV())

images = [
  to_img.(src_img),
  to_img.(th1),
  to_img.(th2),
  to_img.(th3),
  to_img.(th4),
  to_img.(th5)
]

Kino.Layout.grid(images, columns: 3, gap: 16)

ch4/4.3/otsu

src_img =
  Ev.Mat.full({100, 500, 3}, 255, :u8)
  |> Ev.Mat.to_nx()
  |> Ev.Mat.from_nx_2d()

colors = [
  {50, 50, 50},
  {50, 50, 200},
  {50, 200, 50},
  {50, 200, 200},
  {200, 50, 50},
  {200, 50, 200},
  {200, 200, 50},
  {200, 200, 200}
]

src_img =
  Enum.reduce(0..7, src_img, fn i, img ->
    Ev.circle(img, {i * 60 + 40, 50}, 30, Enum.at(colors, i), thickness: -1)
  end)

gray_img = Ev.cvtColor(src_img, Ev.cv_COLOR_BGR2GRAY())
{ret, img_otsu} = Ev.threshold(gray_img, 127, 255, Ev.cv_THRESH_BINARY() + Ev.cv_THRESH_OTSU())
IO.inspect(ret)

{_ret, img_triangle} =
  Ev.threshold(gray_img, 127, 255, Ev.cv_THRESH_BINARY() + Ev.cv_THRESH_TRIANGLE())

[
  to_img.(src_img),
  to_img.(gray_img),
  to_img.(img_otsu),
  to_img.(img_triangle)
]
|> Kino.Layout.grid()

ch4/4.3/adaptive_thresh

img_bgr = Ev.imread(base <> "drivecam.jpg")
img_gray = Ev.cvtColor(img_bgr, Ev.cv_COLOR_BGR2GRAY())

[30, 60, 90, 120]
|> Enum.map(fn thresh ->
  {_ret, th} = Ev.threshold(img_gray, thresh, 255, Ev.cv_THRESH_BINARY())
  to_img.(th)
end)
|> Kino.Layout.grid(columns: 2)
{_ret, th} = Ev.threshold(img_gray, 0, 255, Ev.cv_THRESH_BINARY() + Ev.cv_THRESH_OTSU())
th
Ev.adaptiveThreshold(
  img_gray,
  255,
  Ev.cv_ADAPTIVE_THRESH_GAUSSIAN_C(),
  Ev.cv_THRESH_BINARY(),
  15,
  25
)

ch4/4.3/adaptive_thresh_imp

img =
  Ev.imread(base <> "drivecam.jpg")
  |> Ev.cvtColor(Ev.cv_COLOR_BGR2GRAY())

block_size = 15
c = 25
blur_img = Ev.gaussianBlur(img, {block_size, c}, 0)

diff_img = Ev.subtract(blur_img, img)

img_nx = Ev.Mat.to_nx(img) |> Nx.to_flat_list()
blur_nx = Ev.Mat.to_nx(blur_img) |> Nx.to_flat_list()

Enum.zip_with([blur_nx, img_nx], fn [b, i] ->
  if b - c > i, do: 0, else: 255
end)
|> Nx.tensor(type: :u8)
|> Nx.reshape(Ev.Mat.shape(img))
|> Ev.Mat.from_nx_2d()

ch4/4.3/contours

img_bgr =
  Ev.imread(base <> "bolts.jpg")
  |> Ev.resize({500, 375})

{_ret, img_bin} =
  Ev.cvtColor(img_bgr, Ev.cv_COLOR_BGR2GRAY())
  |> Ev.threshold(160, 255, Ev.cv_THRESH_BINARY())

{contours, hierarchy} =
  Ev.findContours(
    img_bin,
    Ev.cv_RETR_TREE(),
    Ev.cv_CHAIN_APPROX_SIMPLE()
  )

contours =
  Enum.filter(contours, fn con ->
    Ev.contourArea(con) > 900
  end)

result_img = Ev.drawContours(img_bgr, contours, -1, {0, 255, 0}, thickness: 5)

rect_img =
  Enum.reduce(contours, result_img, fn c, img ->
    {x, y, w, h} = Ev.boundingRect(c)
    Ev.rectangle(img, {x, y}, {x + w, y + h}, {0, 0, 255})
  end)

Kino.Layout.grid([to_img.(img_bgr), to_img.(img_bin), to_img.(result_img), to_img.(rect_img)])

ch4/4.4/affine

{width, height} = {100, 100}

src_img =
  Ev.Mat.full({width, height, 3}, 128, :u8)
  |> Ev.Mat.to_nx()
  |> Ev.Mat.from_nx_2d()
  |> Ev.rectangle({10, 10}, {width - 10, height - 10}, {255, 255, 255}, thickness: -1)
  |> Ev.putText("CV", {30, 60}, Ev.cv_FONT_HERSHEY_SIMPLEX(), 1.0, {0, 0, 255},
    thickness: 5,
    lineType: Ev.cv_LINE_4()
  )

x = 50
y = -10
m_shift = Nx.tensor([[1, 0, x], [0, 1, y]], type: :f32) |> Ev.Mat.from_nx()
sheer_img = Ev.warpAffine(src_img, m_shift, {width, height})

angle = 45
m_rotate = Ev.getRotationMatrix2D({width / 2, height / 2}, angle, 1.0)
rotation_img = Ev.warpAffine(src_img, m_rotate, {width, height})

a = 0.2
b = 0.0
m_shear = Nx.tensor([[1, a, 0], [b, 1, 0]], type: :f32) |> Ev.Mat.from_nx()
shear_img = Ev.warpAffine(src_img, m_shear, {width, height})

Kino.Layout.grid(
  [
    to_img.(src_img),
    to_img.(sheer_img),
    to_img.(rotation_img),
    to_img.(shear_img)
  ],
  columns: 4
)

ch4/4.4/flag

{width, height} = {20, 20}

src_img =
  Ev.Mat.full({width, height, 3}, 125, :u8)
  |> Ev.Mat.to_nx()
  |> Ev.Mat.from_nx_2d()
  |> Ev.rectangle({5, 5}, {14, 14}, {255, 255, 255}, thickness: -1)

angle = 30
m_rotate = Ev.getRotationMatrix2D({width / 2, height / 2}, angle, 0.6)

flags = [
  Ev.cv_INTER_NEAREST(),
  Ev.cv_INTER_LINEAR(),
  Ev.cv_INTER_CUBIC(),
  Ev.cv_INTER_AREA(),
  Ev.cv_INTER_LANCZOS4()
]

Enum.map(flags, fn flag ->
  Ev.warpAffine(src_img, m_rotate, {width, height}, flag: flag)
  |> to_img.()
end)
|> Kino.Layout.grid(columns: 5)

ch4/4.4/moire

# x = Nx.iota({1, 3000},backend: EXLA.Backend) |> Nx.multiply(16 / 3000)
# y = Nx.iota({1, 3000},backend: EXLA.Backend) |> Nx.multiply(16 / 3000)

# xx = Nx.tile(x,[3000,1])
# yy = Nx.tile(y,[3000, 1]) |> Nx.transpose()

# z = Nx.add(Nx.power(xx,2), Nx.power(yy,2)) |> Nx.sin()

# plt.contoursfのvegaliteでの書き方がわからないので skip

ch4/4.4/perspective

img = Ev.imread(base <> "drivecam.jpg")

src_pts =
  Nx.tensor([[670, 680], [1130, 680], [130, 800], [1600, 800]], type: :f32)
  |> Ev.Mat.from_nx()

dst_pts =
  Nx.tensor([[0, 0], [500, 0], [0, 500], [500, 500]], type: :f32)
  |> Ev.Mat.from_nx()

m = Ev.getPerspectiveTransform(src_pts, dst_pts)

dst_img = Ev.warpPerspective(img, m, {500, 500})

mark =
  [{670, 680}, {1130, 680}, {130, 800}, {1600, 800}]
  |> Enum.reduce(img, fn pos, img ->
    Ev.drawMarker(
      img,
      pos,
      {0, 0, 255},
      markerType: Ev.cv_MARKER_CROSS(),
      markerSize: 50,
      thickness: 10
    )
  end)

Kino.Layout.grid([to_img.(mark), to_img.(dst_img)])