View Source
Find and Draw Contours in an Image
Mix.install([
{:evision, "~> 0.2"},
{:kino, "~> 0.7"},
{:req, "~> 0.3"}
], system_env: [
# optional, defaults to `true`
# 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
{"EVISION_PREFER_PRECOMPILED", true},
# optional, defaults to `true`
# set `EVISION_ENABLE_CONTRIB` to `false`
# if you don't need modules from `opencv_contrib`
{"EVISION_ENABLE_CONTRIB", true},
# optional, defaults to `false`
# set `EVISION_ENABLE_CUDA` to `true`
# if you wish to use CUDA related functions
# note that `EVISION_ENABLE_CONTRIB` also has to be `true`
# because cuda related modules come from the `opencv_contrib` repo
{"EVISION_ENABLE_CUDA", false},
# required when
# - `EVISION_ENABLE_CUDA` is `true`
# - and `EVISION_PREFER_PRECOMPILED` is `true`
#
# set `EVISION_CUDA_VERSION` to the version that matches
# your local CUDA runtime version
#
# current available versions are
# - 118
# - 121
{"EVISION_CUDA_VERSION", "118"},
# require for Windows users when
# - `EVISION_ENABLE_CUDA` is `true`
# set `EVISION_CUDA_RUNTIME_DIR` to the directory that contains
# CUDA runtime libraries
{"EVISION_CUDA_RUNTIME_DIR", "C:/PATH/TO/CUDA/RUNTIME"}
])
:ok
Helper Function
defmodule Helper do
def download!(url, save_as, overwrite? \\ false) do
unless File.exists?(save_as) do
Req.get!(url, http_errors: :raise, output: save_as, cache: not overwrite?)
end
:ok
end
end
{:module, Helper, <<70, 79, 82, 49, 0, 0, 10, ...>>, {:download!, 3}}
Helper.download!("https://docs.opencv.org/4.x/pca_test1.jpg", "pca_test.jpg")
:ok
Load Image As Gray Scale
gray = Evision.imread("pca_test.jpg", flags: Evision.Constant.cv_IMREAD_GRAYSCALE())
%Evision.Mat{
channels: 1,
dims: 2,
type: {:u, 8},
raw_type: 0,
shape: {600, 800},
ref: #Reference<0.2172638371.2268463131.71223>
}
Get A Binary Image
# import Bitwise so that we can use `|||` (bitwise or)
import Bitwise
# binarization
{_, bw} =
Evision.threshold(gray, 50, 255, Evision.Constant.cv_THRESH_BINARY() ||| Evision.Constant.cv_THRESH_OTSU())
bw
%Evision.Mat{
channels: 1,
dims: 2,
type: {:u, 8},
raw_type: 0,
shape: {600, 800},
ref: #Reference<0.2172638371.2268463122.70922>
}
Find All Contours in the Binary Image
# Find all the contours in the thresholded image
{contours, _} = Evision.findContours(bw, Evision.Constant.cv_RETR_LIST(), Evision.Constant.cv_CHAIN_APPROX_NONE())
IO.puts("Find #{Enum.count(contours)} contour(s)")
Find 7 contour(s)
:ok
Ignore Contours That Are Too Small or Too Large
minimal_area = 100
maximal_area = 100_000
contours =
Enum.reject(contours, fn c ->
# Calculate the area of each contour
area = Evision.contourArea(c)
# Ignore contours that are too small or too large
# (return true to reject)
area < minimal_area or area > maximal_area
end)
IO.puts("#{Enum.count(contours)} contour(s) remains")
6 contour(s) remains
:ok
Draw All Contours
# color in {Blue, Green, Red}, range from 0-255
edge_color = {0, 0, 255}
# draw all contours by setting `index` to `-1`
index = -1
# Load image in color
src = Evision.imread("pca_test.jpg")
# draw all contours on the color image
Evision.drawContours(src, contours, index, edge_color, thickness: 2)
%Evision.Mat{
channels: 3,
dims: 2,
type: {:u, 8},
raw_type: 16,
shape: {600, 800, 3},
ref: #Reference<0.2172638371.2268463122.70944>
}