画像分割
Mix.install([
{:nx, "~> 0.9"},
{:evision, "~> 0.2"},
{:req, "~> 0.5"},
{:kino, "~> 0.14"}
])
画像の取得
# 指定したパスにダウンロードする
img_path = "rwakabay.jpg"
Req.get!(
"https://www.elixirconf.eu/assets/images/ryo-wakabayashi.jpg",
output: File.stream!(img_path)
)
img_mat = Evision.imread(img_path)
# ファイル名、拡張子、画像サイズの取得
file_ext = Path.extname(img_path)
file_basename = Path.basename(img_path, file_ext)
img_shape = img_mat.shape
{file_basename, file_ext, img_shape}
# 画像リスト保存用関数
save_img_tensor_list = fn img_tensor_list, kind ->
img_tensor_list
|> Enum.with_index()
|> Enum.map(fn {img_tensor, index} ->
dst_filename = "#{file_basename}_#{kind}_#{index}#{file_ext}"
img_mat = Evision.Mat.from_nx_2d(img_tensor)
Evision.imwrite(dst_filename, img_mat)
dst_filename
end)
end
水平に分割
# 分割サイズ(分割した画像一つの幅、高さのピクセル数)
chunk_size = 60
# 分割した画像を並べて表示
img_mat
|> Evision.Mat.to_nx(Nx.BinaryBackend)
|> Nx.to_batched(chunk_size)
# BGR to RGB
|> Enum.map(&Nx.reverse(&1, axes: [2]))
|> Enum.map(&Kino.Image.new(&1))
|> Kino.Layout.grid(columns: 1)
|> dbg()
# 分割した画像をファイルに保存
img_mat
|> Evision.Mat.to_nx(Nx.BinaryBackend)
|> Nx.to_batched(chunk_size)
|> save_img_tensor_list.("h")
# 分割したファイルを結合
Stream.unfold(0, fn counter -> {counter, counter + 1} end)
|> Stream.map(&{&1, "#{file_basename}_h_#{&1}#{file_ext}"})
|> Stream.take_while(fn {_, f} -> File.exists?(f) end)
|> Enum.map(fn {index, filename} ->
new_tensor =
filename
|> Evision.imread()
|> Evision.Mat.to_nx(Nx.BinaryBackend)
# 偶数の場合は色を反転
case rem(index, 2) do
0 ->
Nx.reverse(new_tensor, axes: [2])
_ ->
new_tensor
end
end)
# 結合
|> Nx.concatenate()
# トリミング
|> Nx.slice([0, 0, 0], Tuple.to_list(img_shape))
|> Kino.Image.new()
垂直に分割
# 分割した画像を並べて表示
img_mat
|> Evision.Mat.to_nx(Nx.BinaryBackend)
# 縦横入れ替え
|> Nx.transpose(axes: [1, 0, 2])
# 分割
|> Nx.to_batched(chunk_size)
# 縦横入れ替え
|> Enum.map(&Nx.transpose(&1, axes: [1, 0, 2]))
# BGR to RGB
|> Enum.map(&Nx.reverse(&1, axes: [2]))
|> Enum.map(&Kino.Image.new(&1))
|> Kino.Layout.grid(columns: 10)
|> dbg()
# 分割した画像をファイルに保存
img_mat
|> Evision.Mat.to_nx(Nx.BinaryBackend)
# 縦横入れ替え
|> Nx.transpose(axes: [1, 0, 2])
# 分割
|> Nx.to_batched(chunk_size)
|> Enum.map(&Nx.transpose(&1, axes: [1, 0, 2]))
|> save_img_tensor_list.("v")
# 分割したファイルを結合
Stream.unfold(0, fn counter -> {counter, counter + 1} end)
|> Stream.map(&{&1, "#{file_basename}_v_#{&1}#{file_ext}"})
|> Stream.take_while(fn {_, f} -> File.exists?(f) end)
|> Enum.map(fn {index, filename} ->
new_tensor =
filename
|> Evision.imread()
|> Evision.Mat.to_nx(Nx.BinaryBackend)
# 偶数の場合は色を反転
case rem(index, 2) do
0 ->
Nx.reverse(new_tensor, axes: [2])
_ ->
new_tensor
end
end)
# 結合
|> Nx.concatenate(axis: 1)
# トリミング
|> Nx.slice([0, 0, 0], Tuple.to_list(img_shape))
|> Kino.Image.new()
タイル状に分割
# 分割した画像を並べて表示
img_mat
|> Evision.Mat.to_nx(Nx.BinaryBackend)
# 水平に分割
|> Nx.to_batched(chunk_size)
# 垂直に分割
|> Enum.map(&Nx.transpose(&1, axes: [1, 0, 2]))
|> Enum.flat_map(&Nx.to_batched(&1, chunk_size))
|> Enum.map(&Nx.transpose(&1, axes: [1, 0, 2]))
# BGR to RGB
|> Enum.map(&Nx.reverse(&1, axes: [2]))
|> Enum.map(&Kino.Image.new(&1))
|> Kino.Layout.grid(columns: 10)
|> dbg()
# 分割した画像をファイルに保存
img_mat
|> Evision.Mat.to_nx(Nx.BinaryBackend)
# 水平に分割
|> Nx.to_batched(chunk_size)
# 垂直に分割
|> Enum.map(&Nx.transpose(&1, axes: [1, 0, 2]))
|> Enum.flat_map(&Nx.to_batched(&1, chunk_size))
|> Enum.map(&Nx.transpose(&1, axes: [1, 0, 2]))
|> save_img_tensor_list.("t")
{width, _, _} = img_shape
h_size = div(width, chunk_size)
# 分割したファイルを結合
Stream.unfold(0, fn counter -> {counter, counter + 1} end)
|> Stream.map(&{&1, "#{file_basename}_t_#{&1}#{file_ext}"})
|> Stream.take_while(fn {_, f} -> File.exists?(f) end)
|> Enum.map(fn {t_index, filename} ->
new_tensor =
filename
|> Evision.imread()
|> Evision.Mat.to_nx(Nx.BinaryBackend)
{new_tensor, t_index}
end)
|> Enum.chunk_every(h_size)
|> Enum.map(fn new_tensor_list ->
new_tensor_list
|> Enum.with_index()
|> Enum.map(fn {{new_tensor, t_index}, v_index} ->
cond do
rem(v_index, 2) == rem(div(t_index, h_size), 2) ->
Nx.reverse(new_tensor, axes: [2])
true ->
new_tensor
end
end)
# 横方向に結合
|> Nx.concatenate(axis: 1)
end)
# 縦方向に結合
|> Nx.concatenate()
# トリミング
|> Nx.slice([0, 0, 0], Tuple.to_list(img_shape))
|> Kino.Image.new()