AWS Rekognition
Mix.install([
{:ex_aws, "~> 2.5"},
{:ex_aws_rekognition, "~> 0.6"},
{:poison, "~> 5.0"},
{:hackney, "~> 1.20"},
{:sweet_xml, "~> 0.7"},
{:explorer, "~> 0.9"},
{:evision, "~> 0.2"},
{:req, "~> 0.5"},
{:kino, "~> 0.14"}
])
準備
alias ExAws.Rekognition
alias Explorer.DataFrame
alias Explorer.Series
require Explorer.DataFrame
認証
access_key_id_input = Kino.Input.password("ACCESS_KEY_ID")
secret_access_key_input = Kino.Input.password("SECRET_ACCESS_KEY")
region_input = Kino.Input.text("REGION")
[
access_key_id_input,
secret_access_key_input,
region_input
]
|> Kino.Layout.grid(columns: 3)
auth_config = [
access_key_id: Kino.Input.read(access_key_id_input),
secret_access_key: Kino.Input.read(secret_access_key_input),
region: Kino.Input.read(region_input)
]
Kino.nothing()
物体検出
lenna_mat =
"https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png"
|> Req.get!()
|> Map.get(:body)
|> Evision.imdecode(Evision.Constant.cv_IMREAD_COLOR())
rek_res =
Evision.imencode(".png", lenna_mat)
|> Rekognition.detect_labels()
|> ExAws.request!(auth_config)
detections_df =
rek_res["Labels"]
# 位置情報がないものは除外する
|> Enum.filter(&(Enum.count(&1["Instances"]) > 0))
|> Enum.flat_map(fn detection ->
detection["Instances"]
|> Enum.map(fn instance ->
[
label: detection["Name"],
left: instance["BoundingBox"]["Left"],
top: instance["BoundingBox"]["Top"],
width: instance["BoundingBox"]["Width"],
height: instance["BoundingBox"]["Height"],
score: instance["Confidence"]
]
end)
end)
|> DataFrame.new()
Kino.DataTable.new(detections_df)
detections_df =
DataFrame.distinct(detections_df, ["left", "top", "width", "height"], keep_all: true)
Kino.DataTable.new(detections_df)
{img_height, img_width, _} = Evision.Mat.shape(lenna_mat)
detections_df
|> DataFrame.to_rows()
|> Enum.reduce(lenna_mat, fn detection, drawed ->
label = detection["label"]
left = (img_width * detection["left"]) |> trunc()
top = (img_height * detection["top"]) |> trunc()
right = (left + img_width * detection["width"]) |> trunc()
bottom = (top + img_height * detection["height"]) |> trunc()
drawed
|> Evision.rectangle(
{left, top},
{right, bottom},
{255, 0, 0},
thickness: 4
)
|> Evision.putText(
label,
{left + 6, top + 26},
Evision.Constant.cv_FONT_HERSHEY_SIMPLEX(),
0.8,
{0, 0, 255},
thickness: 2
)
end)
show_objects = fn input_mat ->
Evision.imencode(".jpg", input_mat)
|> Rekognition.detect_labels()
|> ExAws.request!(auth_config)
|> Map.get("Labels")
|> Enum.filter(&(Enum.count(&1["Instances"]) > 0))
|> Enum.flat_map(fn detection ->
detection["Instances"]
|> Enum.map(fn instance ->
[
label: detection["Name"],
left: instance["BoundingBox"]["Left"],
top: instance["BoundingBox"]["Top"],
width: instance["BoundingBox"]["Width"],
height: instance["BoundingBox"]["Height"],
score: instance["Confidence"]
]
end)
end)
|> DataFrame.new()
|> DataFrame.distinct(["left", "top", "width", "height"], keep_all: true)
|> DataFrame.to_rows()
|> Enum.reduce(input_mat, fn detection, drawed ->
{img_height, img_width, _} = Evision.Mat.shape(input_mat)
label = detection["label"]
left = (img_width * detection["left"]) |> trunc()
top = (img_height * detection["top"]) |> trunc()
right = (left + img_width * detection["width"]) |> trunc()
bottom = (top + img_height * detection["height"]) |> trunc()
drawed
|> Evision.rectangle(
{left, top},
{right, bottom},
{255, 0, 0},
thickness: 4
)
|> Evision.putText(
label,
{left + 6, top + 26},
Evision.Constant.cv_FONT_HERSHEY_SIMPLEX(),
0.8,
{0, 0, 255},
thickness: 2
)
end)
end
dog_mat =
"https://raw.githubusercontent.com/pjreddie/darknet/master/data/dog.jpg"
|> Req.get!()
|> Map.get(:body)
|> Evision.imdecode(Evision.Constant.cv_IMREAD_COLOR())
show_objects.(dog_mat)
顔検出
rek_res =
Evision.imencode(".png", lenna_mat)
|> Rekognition.detect_faces(attributes: ["ALL"])
|> ExAws.request!(auth_config)
lenna_face =
rek_res["FaceDetails"]
|> Enum.at(0)
顔の位置
{img_height, img_width, _} = Evision.Mat.shape(lenna_mat)
box = lenna_face["BoundingBox"]
left = (img_width * box["Left"]) |> trunc()
top = (img_height * box["Top"]) |> trunc()
right = (left + img_width * box["Width"]) |> trunc()
bottom = (top + img_height * box["Height"]) |> trunc()
lenna_mat
|> Evision.rectangle(
{left, top},
{right, bottom},
{255, 0, 0},
thickness: 4
)
顔のパーツ
{img_height, img_width, _} = Evision.Mat.shape(lenna_mat)
lenna_face["Landmarks"]
|> Enum.reduce(lenna_mat, fn detection, drawed ->
x = (img_width * detection["X"]) |> trunc()
y = (img_height * detection["Y"]) |> trunc()
drawed
|> Evision.circle(
{x, y},
4,
{255, 0, 0},
thickness: -1
)
end)
顔の向き
lenna_face["Pose"]
|> then(
&%{
"どれくらい首を傾げているか" => Float.round(&1["Roll"]),
"どれくらい見上げたり見下ろしたりしているか" => Float.round(&1["Pitch"]),
"どれくらい左右に向いているか" => Float.round(&1["Yaw"])
}
)
写りの良さ
lenna_face["Quality"]["Brightness"]
|> Float.round()
|> then(&"明るさ #{&1}%")
lenna_face["Quality"]["Sharpness"]
|> Float.round()
|> then(&"鮮明さ #{&1}%")
感情
lenna_face["Emotions"]
|> Enum.map(fn emotion ->
%{
"confidence" => Float.round(emotion["Confidence"]),
"emotion" => emotion["Type"]
}
end)
|> DataFrame.new()
|> DataFrame.select(["emotion", "confidence"])
|> Kino.DataTable.new()
年齢
lenna_face["AgeRange"]
|> then(&"#{&1["Low"]}歳 〜 #{&1["High"]}歳")
性別
lenna_face["Gender"]
|> then(fn attr ->
"#{Float.round(attr["Confidence"])}% " <>
case attr["Value"] do
"Female" ->
"女性"
"Male" ->
"男性"
end
end)
その他の情報
to_jp = fn bool ->
case bool do
true ->
"る"
false ->
"ない"
end
end
attributes = [
{"Smile", "微笑んで"},
{"EyesOpen", "目を開けて"},
{"MouthOpen", "口を開けて"},
{"Eyeglasses", "メガネをかけて"},
{"Sunglasses", "サングラスをかけて"},
{"Mustache", "髭が生えて"},
{"Beard", "ハゲて"}
]
attributes
|> Enum.map(fn {en, jp} ->
lenna_face[en]
|> then(fn attr ->
"#{Float.round(attr["Confidence"])}% #{jp}い#{to_jp.(attr["Value"])}"
end)
end)