View Source Evision Example - Warp Perspective
# set `EVISION_PREFER_PRECOMPILED` to `false`
# if you prefer `:evision` to be compiled from source
# note that to compile from source, you may need at least 1GB RAM
# System.put_env("EVISION_PREFER_PRECOMPILED", "false")
Mix.install([
{:evision, "~> 0.1.15"},
{:req, "~> 0.3"},
{:kino, "~> 0.7"}
])
:ok
define-some-helper-functions
Define Some Helper Functions
defmodule Helper do
def download!(url, save_as, overwrite \\ false)
def download!(url, save_as, false) do
unless File.exists?(save_as) do
download!(url, save_as, true)
end
:ok
end
def download!(url, save_as, true) do
body =
case Req.get!(url) do
%Req.Response{status: 200, body: body} ->
body
error ->
raise inspect(error)
end
File.write!(save_as, body)
end
end
{:module, Helper, <<70, 79, 82, 49, 0, 0, 10, ...>>, {:download!, 3}}
read-the-test-image-from-file
Read the Test Image From File
# Download the test image
test_image_path = Path.join(__DIR__, "warp_perspective.png")
Helper.download!(
"https://raw.githubusercontent.com/cocoa-xu/evision/main/test/warp_perspective.png",
test_image_path
)
# Read the test image
%Evision.Mat{shape: {h, w, _}} = img = Evision.imread(test_image_path)
%Evision.Mat{
channels: 3,
dims: 2,
type: {:u, 8},
raw_type: 16,
shape: {288, 277, 3},
ref: #Reference<0.391993608.626655254.103441>
}
function-hypot-returns-the-euclidean-norm
Function hypot: returns the Euclidean norm
# hypot.(list(number())) function returns the Euclidean norm
hypot = fn l -> :math.sqrt(Enum.sum(Enum.map(l, fn i -> i * i end))) end
#Function<42.3316493/1 in :erl_eval.expr/6>
calculate-the-output-coordinates-for-corners
Calculate the Output Coordinates for Corners
# specify input coordinates for corners of red quadrilateral in order TL, TR, BR, BL as x,
input =
Nx.tensor(
[
[136, 113],
[206, 130],
[173, 207],
[132, 196]
],
type: :f32
)
#Nx.Tensor<
f32[4][2]
[
[136.0, 113.0],
[206.0, 130.0],
[173.0, 207.0],
[132.0, 196.0]
]
>
# get top and left dimensions and set to output dimensions of red rectangle
output_width = [
Nx.to_number(Nx.subtract(input[[0, 0]], input[[1, 0]])),
Nx.to_number(Nx.subtract(input[[0, 1]], input[[1, 1]]))
]
output_width = round(hypot.(output_width))
output_height = [
Nx.to_number(Nx.subtract(input[[0, 0]], input[[3, 0]])),
Nx.to_number(Nx.subtract(input[[0, 1]], input[[3, 1]]))
]
output_height = round(hypot.(output_height))
83
# set upper left coordinates for output rectangle
x = Nx.to_number(input[[0, 0]])
y = Nx.to_number(input[[0, 1]])
113.0
# specify output coordinates for corners of red quadrilateral in order TL, TR, BR, BL as x,
output =
Nx.tensor(
[
[x, y],
[x + output_width - 1, y],
[x + output_width - 1, y + output_height - 1],
[x, y + output_height - 1]
],
type: :f32
)
#Nx.Tensor<
f32[4][2]
[
[136.0, 113.0],
[207.0, 113.0],
[207.0, 195.0],
[136.0, 195.0]
]
>
compute-perspective-matrix
Compute Perspective Matrix
# compute perspective matrix
matrix = Evision.getPerspectiveTransform(input, output)
%Evision.Mat{
channels: 1,
dims: 2,
type: {:f, 64},
raw_type: 6,
shape: {3, 3},
ref: #Reference<0.391993608.626655249.103165>
}
perspective-transformation
Perspective Transformation
# do perspective transformation setting area outside input to black
# Note that output size is the same as the input image size
img_output =
Evision.warpPerspective(
img,
matrix,
{w, h},
flags: Evision.cv_INTER_LINEAR(),
borderMode: Evision.cv_BORDER_CONSTANT(),
borderValue: {0, 0, 0}
)
%Evision.Mat{
channels: 3,
dims: 2,
type: {:u, 8},
raw_type: 16,
shape: {288, 277, 3},
ref: #Reference<0.391993608.626655249.103168>
}