View Source Evision.ML.SVM Example - Support Vector Machine

# 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.21"},
  {:kino, "~> 0.7"},
  {:req, "~> 0.3"}
])
:ok

set-up-training-data

Set Up Training Data

This example is based on the Introduction to Support Vector Machines from Cv.

alias Evision, as: Cv

labels = [1, -1, -1, -1]
training_data = [[501, 10], [255, 10], [501, 255], [10, 501]]

labels_mat = Cv.Mat.literal(labels, :s32)
training_data_mat = Cv.Mat.literal(training_data, :f32)
%Evision.Mat{
  channels: 1,
  dims: 2,
  type: {:f, 32},
  raw_type: 5,
  shape: {4, 2},
  ref: #Reference<0.1481828880.2785148948.120970>
}

create-an-svm-and-train-it-with-the-data

Create an SVM and Train It With the Data

svm = Cv.ML.SVM.create()
svm = Cv.ML.SVM.setType(svm, Cv.cv_C_SVC())
svm = Cv.ML.SVM.setKernel(svm, Cv.cv_LINEAR())
svm = Cv.ML.SVM.setTermCriteria(svm, {Cv.cv_MAX_ITER(), 100, 0.000001})
true = Cv.ML.SVM.train(svm, training_data_mat, Cv.cv_ROW_SAMPLE(), labels_mat)
true = Cv.ML.SVM.isTrained(svm)
true

get-support-vectors

Get Support Vectors

%Evision.Mat{shape: {rows, cols}} = sv = Cv.ML.SVM.getUncompressedSupportVectors(svm)
sv_binary = Cv.Mat.to_binary(sv)
float_bytes = 4

support_vector =
  for i <- (rows - 1)..0, reduce: [] do
    support_vector ->
      current_vector =
        for j <- (cols - 1)..0, reduce: [] do
          vec ->
            <<float_data::float-size(32)-little>> =
              :binary.part(sv_binary, (i * cols + j) * float_bytes, 4)

            [trunc(float_data) | vec]
        end

      [current_vector | support_vector]
  end

[[501, 10], [255, 10], [501, 255]] = support_vector
support_vector
[[501, 10], [255, 10], [501, 255]]

visualise-the-training-result-in-a-response-map

Visualise the Training Result in A Response Map

green = [0, 255, 0]
blue = [255, 0, 0]
width = 512
height = 512

response_data =
  for x <- (width - 1)..0, y <- (height - 1)..0, reduce: [] do
    acc ->
      sample =
        Cv.Mat.from_binary(
          <<y::float-size(32)-little, x::float-size(32)-little>>,
          {:f, 32},
          1,
          2,
          1
        )

      {_, %Cv.Mat{shape: {1, 1}} = response_mat} = Cv.ML.SVM.predict(svm, sample)
      <<response::float-size(32)-little>> = Cv.Mat.to_binary(response_mat)
      response = trunc(response)

      case response do
        1 ->
          [green | acc]

        -1 ->
          [blue | acc]
      end
  end

response_data = response_data |> List.flatten() |> IO.iodata_to_binary()
response_map = Cv.Mat.from_binary(response_data, {:u, 8}, height, width, 3)

# show the training data
thickness = 1

response_map =
  Cv.circle(response_map, List.to_tuple(Enum.at(training_data, 0)), 5, {0, 0, 0},
    thickness: thickness
  )

response_map =
  Cv.circle(response_map, List.to_tuple(Enum.at(training_data, 1)), 5, {255, 255, 255},
    thickness: thickness
  )

response_map =
  Cv.circle(response_map, List.to_tuple(Enum.at(training_data, 2)), 5, {255, 255, 255},
    thickness: thickness
  )

response_map =
  Cv.circle(response_map, List.to_tuple(Enum.at(training_data, 3)), 5, {255, 255, 255},
    thickness: thickness
  )

# show support vectors
response_map =
  Cv.circle(response_map, List.to_tuple(Enum.at(support_vector, 0)), 6, {128, 128, 128},
    thickness: thickness
  )

response_map =
  Cv.circle(response_map, List.to_tuple(Enum.at(support_vector, 1)), 6, {128, 128, 128},
    thickness: thickness
  )

response_map =
  Cv.circle(response_map, List.to_tuple(Enum.at(support_vector, 2)), 6, {128, 128, 128},
    thickness: thickness
  )

Cv.imencode(".png", response_map)
|> Kino.Image.new(:png)