Current section

Files

Jump to
evision lib evision_nx.ex
Raw

lib/evision_nx.ex

defmodule Evision.Nx do
@moduledoc """
OpenCV's cv::mat to Nx tensor.
"""
import Evision.Errorize
unless Code.ensure_loaded?(Nx) do
@compile {:no_warn_undefined, Nx}
end
@doc """
Transform an `Evision.Mat` reference to `Nx.tensor`.
The resulting tensor is in the shape `{height, width, channels}`.
### Example
```elixir
iex> {:ok, mat} = Evision.imread("/path/to/exist/img.png")
iex> nx_tensor = Evision.Nx.to_nx(mat)
...> #Nx.Tensor<
...> u8[1080][1920][3]
...> [[ ... pixel data ... ]]
...> >
```
"""
@doc namespace: :external
def to_nx(mat, backend \\ Evision.Backend) do
with {:ok, mat_type} <- Evision.Mat.type(mat),
{:ok, mat_shape} <- Evision.Mat.shape(mat),
{:ok, bin} <- Evision.Mat.to_binary(mat) do
bin
|> Nx.from_binary(mat_type, backend: backend)
|> Nx.reshape(mat_shape)
else
{:error, reason} ->
{:error, reason}
end
end
deferror(to_nx(mat))
deferror(to_nx(mat, backend))
@doc """
Converts a tensor of `Nx` to `Mat` of evision (OpenCV).
If the tensor has three dimensions, it is expected
to have shape`{height, width, channels}`.
"""
@doc namespace: :external
@spec to_mat(Nx.t()) :: {:ok, reference()} | {:error, String.t()}
def to_mat(t) when is_struct(t, Nx.Tensor) do
case Nx.shape(t) do
{} ->
Evision.Mat.from_binary_by_shape(Nx.to_binary(t), Nx.type(t), {1})
shape ->
Evision.Mat.from_binary_by_shape(Nx.to_binary(t), Nx.type(t), shape)
end
end
deferror(to_mat(t))
@doc namespace: :external
def to_mat(t, as_shape) when is_struct(t, Nx.Tensor) do
case Nx.shape(t) do
{} ->
Evision.Mat.from_binary_by_shape(Nx.to_binary(t), Nx.type(t), {1})
shape ->
if Tuple.product(shape) == Tuple.product(as_shape) do
Evision.Mat.from_binary_by_shape(Nx.to_binary(t), Nx.type(t), as_shape)
else
{:error, "cannot convert tensor(#{inspect(shape)}) to mat as shape #{inspect(as_shape)}"}
end
end
end
deferror(to_mat(t, as_shape))
@doc namespace: :external
def to_mat(binary, type, rows, cols, channels) do
Evision.Mat.from_binary(binary, type, rows, cols, channels)
end
deferror(to_mat(binary, type, rows, cols, channels))
@doc namespace: :external
def to_mat_2d(t) do
case Nx.shape(t) do
{height, width} ->
Evision.Mat.from_binary(Nx.to_binary(t), Nx.type(t), height, width, 1)
{height, width, channels} ->
Evision.Mat.from_binary(Nx.to_binary(t), Nx.type(t), height, width, channels)
shape ->
{:error, "Cannot convert tensor(#{inspect(shape)}) to a 2D image"}
end
end
deferror(to_mat_2d(t))
end