View Source Evision Example - QRCode Encoding and Decoding

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

Encode A String to QRCode

# let's encode this example string
string_to_encode = "This is a string!"

# the result image will be in minimal possible size
# which is what it should be to avoid unnecessary memory allocations
# because it would be easier to let the user to resize the result image
# (most of the time we need to resize it to fit our needs anyway, this saves one call to resize)
%Evision.Mat{} =
  minimal_qrcode = Evision.QRCodeEncoder.encode(Evision.QRCodeEncoder.create(), string_to_encode)

# for this example, we can resize it to 300x300
qrcode = Evision.resize(minimal_qrcode, {300, 300}, interpolation: Evision.Constant.cv_INTER_AREA())
%Evision.Mat{
  channels: 1,
  dims: 2,
  type: {:u, 8},
  raw_type: 0,
  shape: {300, 300},
  ref: #Reference<0.2207498009.3335389204.191169>
}

Read the String Back From the Encoded QRCode

{decoded_string, points, straight_qrcode} =
  Evision.QRCodeDetector.detectAndDecode(Evision.QRCodeDetector.qrCodeDetector(), qrcode)

decoded_string
"This is a string!"

The Second Value In the Returned Tuple

# `points` is the keypoints for the QRCode
# the shape would be {1, 4, 2}, in which:
#  - 1: number of QRCode
#  - 4: always 4, 4 keypoints: top_left, bottom_left, bottom_right, top_right
#  - 2: always 2, (x, y)
points = Evision.Mat.to_nx(points, Nx.BinaryBackend)
#Nx.Tensor<
  f32[1][4][2]
  [
    [
      [24.0, 24.0],
      [275.0000305175781, 24.0],
      [275.0000305175781, 275.0000305175781],
      [24.0, 275.0000305175781]
    ]
  ]
>
# here we take the first QRCode's keypoints
keypoints = Nx.as_type(points[0], :s32)

{top_left, bottom_right} = {
  List.to_tuple(Nx.to_flat_list(keypoints[0])),
  List.to_tuple(Nx.to_flat_list(keypoints[2]))
}
{{24, 24}, {275, 275}}
{{row_start, col_start}, {row_end, col_end}} = {top_left, bottom_right}
qrcode[[col_start..col_end, row_start..row_end]]
%Evision.Mat{
  channels: 1,
  dims: 2,
  type: {:u, 8},
  raw_type: 0,
  shape: {252, 252},
  ref: #Reference<0.2207498009.3335389204.191179>
}

The Third Value In the Returned Tuple

# the third value is `straight_qrcode`, which is the minimal possible image
# for the QRCode
Evision.resize(straight_qrcode, {300, 300}, interpolation: Evision.Constant.cv_INTER_AREA())
%Evision.Mat{
  channels: 1,
  dims: 2,
  type: {:u, 8},
  raw_type: 0,
  shape: {300, 300},
  ref: #Reference<0.2207498009.3335389204.191182>
}