Face Recognition
Mix.install(
[
{:kino, "~> 0.15"},
{:evision, github: "cocoa-xu/evision", branch: "main"}
],
system_env: [
{"EVISION_PREFER_PRECOMPILED", "false"}
]
)
Smart Cell
recognizer =
Evision.Zoo.FaceRecognition.SFace.init(:default_model,
backend: Evision.Constant.cv_DNN_BACKEND_OPENCV(),
target: Evision.Constant.cv_DNN_TARGET_CPU(),
distance_type: :cosine_similarity,
cosine_threshold: 0.5,
l2_norm_threshold: 1.128
)
detector =
Evision.Zoo.FaceDetection.YuNet.init(:default_model,
backend: Evision.Constant.cv_DNN_BACKEND_OPENCV(),
target: Evision.Constant.cv_DNN_TARGET_CPU(),
nms_threshold: 0.3,
conf_threshold: 0.5,
top_k: 5
)
original_input = Kino.Input.image("Original")
comparison_input = Kino.Input.image("Comparison")
form =
Kino.Control.form([original: original_input, comparison: comparison_input],
submit: "Run"
)
frame = Kino.Frame.new()
form
|> Kino.Control.stream()
|> Stream.filter(&(&1.data.original != nil or &1.data.comparison != nil))
|> Kino.listen(fn %{data: %{original: original_image, comparison: comparison_image}} ->
Kino.Frame.render(frame, Kino.Markdown.new("Running..."))
original_image =
Evision.Mat.from_binary(
original_image.data,
{:u, 8},
original_image.height,
original_image.width,
3
)
comparison_image =
Evision.Mat.from_binary(
comparison_image.data,
{:u, 8},
comparison_image.height,
comparison_image.width,
3
)
original_results = Evision.Zoo.FaceDetection.YuNet.infer(detector, original_image)
comparison_results = Evision.Zoo.FaceDetection.YuNet.infer(detector, comparison_image)
case {original_results, comparison_results} do
{%Evision.Mat{}, %Evision.Mat{}} ->
original_bbox = Evision.Mat.to_nx(original_results, Nx.BinaryBackend)[0][0..-2//1]
comparison_bbox =
Evision.Mat.to_nx(comparison_results, Nx.BinaryBackend)[0][0..-2//1]
original_blob =
Evision.FaceRecognizerSF.alignCrop(recognizer, original_image, original_bbox)
original_feature =
Evision.FaceRecognizerSF.feature(recognizer, original_blob)
|> Evision.Mat.to_nx()
|> Evision.Mat.from_nx()
comparison_blob =
Evision.FaceRecognizerSF.alignCrop(recognizer, comparison_image, comparison_bbox)
comparison_feature =
Evision.FaceRecognizerSF.feature(recognizer, comparison_blob)
|> Evision.Mat.to_nx()
|> Evision.Mat.from_nx()
%{matched: matched, retval: val, measure: measure} =
Evision.Zoo.FaceRecognition.SFace.match_feature(
recognizer,
original_feature,
comparison_feature
)
original_image =
Evision.cvtColor(original_image, Evision.Constant.cv_COLOR_RGB2BGR())
comparison_image =
Evision.cvtColor(comparison_image, Evision.Constant.cv_COLOR_RGB2BGR())
vis_original =
Evision.Zoo.FaceDetection.YuNet.visualize(original_image, original_results[0])
vis_comparison =
Evision.Zoo.FaceDetection.YuNet.visualize(comparison_image, comparison_results[0])
vis = [
Kino.Image.new(Evision.imencode(".png", vis_original), :png),
Kino.Image.new(Evision.imencode(".png", vis_comparison), :png)
]
Kino.Frame.render(frame, Kino.Layout.grid(vis, columns: 2))
Kino.Frame.append(
frame,
Kino.Markdown.new("Result: #{matched}, #{measure}: #{val}")
)
{{:error, _}, %Evision.Mat{}} ->
Kino.Frame.render(
frame,
Kino.Markdown.new("Cannot detect any face in the original image")
)
{%Evision.Mat{}, _} ->
Kino.Frame.render(
frame,
Kino.Markdown.new("Cannot detect any face in the comparison image")
)
{_, _} ->
Kino.Frame.render(
frame,
Kino.Markdown.new("Cannot detect any face in both original and comparison images")
)
end
end)
Kino.Layout.grid([form, frame], boxed: true, gap: 16)