OpenCV basics
Mix.install([
{:evision, "0.1.30"},
{:kino, "~> 0.7.0"},
{:exla, "~> 0.4.0"},
{:req, "~> 0.3.0"}
])
Resources
Evision
- OpenCVのElixirラッパー
- Nxのバックエンドとして使用でき、行列演算の高速化(CPU,GPU)ができる
- 画像処理の関数を使用できる
alias Evision, as: Cv
Download data files
downloads_dir = System.tmp_dir!()
download = fn url ->
save_as = Path.join(downloads_dir, URI.encode_www_form(url))
unless File.exists?(save_as), do: Req.get!(url, output: save_as)
save_as
end
data_files =
[
# an image that is to be used as input
input_image: "https://github.com/livebook-dev/livebook/raw/main/static/images/logo.png"
]
|> Enum.map(fn {key, url} -> {key, download.(url)} end)
|> Map.new()
Nx.tensor([255, 0, 0], type: :u8)
|> Nx.broadcast({800, 400, 3})
|> Cv.Mat.from_nx_2d()
Mat.zerosで黒色画像の作成
- 第1引数:行列サイズ
- 第2引数:型
color = {255, 255, 255}
font = Cv.Constant.cv_FONT_HERSHEY_SIMPLEX()
# 第一引数で指定したサイズで0で埋めた行列を作成
Cv.Mat.zeros({200, 200}, :u8)
|> Cv.putText("hello", {16, 48}, font, 1, color, thickness: 2)
|> Cv.circle({50, 40}, 30, color)
# RGBの値で作ってMatで表示
Cv.Mat.zeros({100, 100, 3}, :u8)
|> Cv.Mat.to_nx()
|> Cv.Mat.from_nx_2d()
|> dbg()
:ok
Mat.fullでグレー画像の作成
- 第1引数:行列サイズ
- 第2引数:値
- 第3引数:型
Cv.Mat.full({100, 100}, 200, :u8)
Mat.from_nx_2dでNxから色画像の作成
shape = {250, 250, 3}
red =
Nx.tensor([0, 0, 255], type: :u8)
|> Nx.broadcast(shape)
|> Cv.Mat.from_nx_2d()
green =
Nx.tensor([0, 255, 0], type: :u8)
|> Nx.broadcast(shape)
|> Cv.Mat.from_nx_2d()
blue =
Nx.tensor([255, 0, 0], type: :u8)
|> Nx.broadcast(shape)
|> Cv.Mat.from_nx_2d()
mat_to_img = &Kino.Image.new(Cv.imencode(".png", &1), :png)
[red, green, blue]
|> Enum.map(mat_to_img)
|> Kino.Layout.grid(columns: 3)
imreadで画像の読み込み
img = Cv.imread(data_files.input_image)
imwriteでファイル書き込み
# write the image as PNG
png_path = Path.join(System.tmp_dir!(), "opencv_basics_img" <> ".png")
Cv.imwrite(png_path, img)
png_path
# write the image as JPG
jpg_path = Path.join(System.tmp_dir!(), "opencv_basics_img" <> ".jpg")
Cv.imwrite(jpg_path, img)
jpg_path
# error without on ext
{:error, _} = Cv.imwrite("images/logo", img)
resize
{w, h} = {300, 300}
img = Cv.resize(img, {w, h})
Crop and resize
img[[{10, 90}, {40, 120}]]
|> Cv.resize({200, 200})
rotate
Cv.rotate(img, Cv.Constant.cv_ROTATE_90_CLOCKWISE())
Cv.rotate(img, Cv.Constant.cv_ROTATE_90_COUNTERCLOCKWISE())
Cv.rotate(img, Cv.Constant.cv_ROTATE_180())
flip
# 縦方向に反転
Cv.flip(img, 0)
# 横方向に反転
Cv.flip(img, 1)
hconcatで横連結
Cv.hconcat([img, img])
vconcatで縦連結
Cv.vconcat([img, img])
rectangle
{x, y, w, h} = {40, 5, 80, 80}
start_point = {x, y}
end_point = {x + w, y + h}
color = {255, 255, 255}
options = [thickness: 5]
Cv.rectangle(img, start_point, end_point, color, options)
{x, y, w, h} = {40, 5, 80, 80}
start_point = {x, y}
end_point = {x + w, y + h}
color = {255, 255, 255}
options = [thickness: -1]
Cv.rectangle(img, start_point, end_point, color, options)
circle
center = {100, 100}
diameter = 40
color = {255, 255, 255}
options = [thickness: 3]
Cv.circle(img, center, diameter, color, options)
{ox, oy} = {100, 100}
{h, w} = {50, 100}
rotation = -30
start_point = 0
end_point = 360
color = {255, 255, 255}
options = [thickness: 1]
Cv.ellipse(img, {ox, oy}, {w, h}, rotation, start_point, end_point, color, options)
{ox, oy} = {100, 100}
{h, w} = {50, 50}
rotation = 90
start_point = 0
end_point = 180
color = {255, 255, 255}
options = [thickness: -1]
Cv.ellipse(img, {ox, oy}, {w, h}, rotation, start_point, end_point, color, options)[
[0..40, 0..20]
]
putText
text = "LiveViewJP"
position = {20, 120}
options = [thickness: 2]
Cv.putText(img, text, position, Cv.Constant.cv_FONT_ITALIC(), 1.0, color, options)
Mat.roiで切り取り
{x, y, w, h} = {40, 10, 50, 80}
Cv.Mat.roi(img, {x, y, x + w, y + h})
warpAffineでアフィン変換
並行移動
{w, h} = {200, 200}
{x, y} = {50, -10}
m_shift = Nx.tensor([[1, 0, x], [0, 1, y]], type: :f32) |> Cv.Mat.from_nx()
sheer_img = Cv.warpAffine(img, m_shift, {w, h})
回転
{w, h} = {200, 200}
center = {w / 2, h / 2}
angle = 45
scale = 1.0
m_rotate = Cv.getRotationMatrix2D(center, angle, scale)
rotation_img = Cv.warpAffine(img, m_rotate, {w, h})
スキュー(平行四辺形に変形する処理)
###
{w, h} = {200, 200}
{a, b} = {0.2, 0.0}
m_shear = Nx.tensor([[1, a, 0], [b, 1, 0]], type: :f32) |> Cv.Mat.from_nx()
shear_img = Cv.warpAffine(img, m_shear, {w, h})