この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは、CX事業本部 IoT事業部の若槻です。
Amazon Rekognitionは、機械学習を利用した画像や動画の分析を簡単に実施できるAWSのサービスです。
今回は、Amazon Rekognitionでイメージの顔検出による感情分析を行ってみました。
顔検出による感情分析
Amazon Rekognitionで感情分析を行う場合は顔検出APIのDetectFacesを使用します。
DetectFacesのリクエストの構文は下記のようになります。
Image
パラメータには、Bytes
で分析対象の画像データのバイトデータを直接指定、またはS3Object
で画像データのS3オブジェクトを指定します。Attributes
パラメータには、レスポンスデータに含みたい属性を指定します。既定では感情の属性はレスポンスに含まれませんが、ALL
を指定することにより含めることが出来ます。
{
"Image": {
"Bytes": blob,
"S3Object": {
"Bucket": "string",
"Name": "string",
"Version": "string"
}
},
"Attributes": [ "string" ]
}
DetectFacesのレスポンスのサンプルは下記のようになります(感情分析属性部分のみ抜き出しています)。Emotions
属性に各タイプの感情データがリストで格納されています。
detectFacesResult.json
{
"FaceDetails": [
{
"Emotions": [
{
"Type": "HAPPY",
"Confidence": 97.60749053955078
},
{
"Type": "SURPRISED",
"Confidence": 0.7658454179763794
},
{
"Type": "CONFUSED",
"Confidence": 0.5557805299758911
},
{
"Type": "ANGRY",
"Confidence": 0.3515094518661499
},
{
"Type": "DISGUSTED",
"Confidence": 0.34102049469947815
},
{
"Type": "CALM",
"Confidence": 0.19356855750083923
},
{
"Type": "FEAR",
"Confidence": 0.13799776136875153
},
{
"Type": "SAD",
"Confidence": 0.046782251447439194
}
]
}
]
}
検出できる感情タイプ
DetectFacesで検出できる感情は下記の8タイプとなります。
HAPPY
:幸せSURPRISED
:驚きCONFUSED
:困惑ANGRY
:怒りDISGUSTED
:うんざりCALM
:穏やかFEAR
:恐れSAD
:悲しみ-
aws-sdk-js-v3/models_0.ts at 44635811e48c77dbdad388eb75ca92cdc0882c98 · aws/aws-sdk-js-v3
感情分析結果から感情を推定
レスポンスのサンプルにあったように、感情分析の結果はどれか一つの感情タイプが検出されるのでなく、8種類の感情タイプそれぞれに対する信頼度(Confidential)が検出されたデータとなります。よって一つの感情タイプを推定したい場合は、感情検出結果のリストから信頼度の一番高い感情を1つ取得する必要があります。
下記は感情を推定するサンプルコード(TypeScript)です。感情分析結果のリストからConfidence
が最大のデータの感情を取得し、推定結果としています。
import Rekognition, {
FaceDetailList,
Emotions,
Emotion,
DetectFacesRequest,
} from 'aws-sdk/clients/rekognition';
/**
* 顔検出での感情推定結果を取得する
* @param imageData 画像データ(Base64)
*/
export const getEmotion = async (imageData: string): Promise<void> => {
const rekognitionClient = new Rekognition({
apiVersion: '2016-06-27',
});
const params: DetectFacesRequest = {
Image: {
Bytes: Buffer.from(
imageData.replace('data:image/jpeg;base64,', ''),
'base64',
),
},
Attributes: ['ALL'],
};
const rawResult = await rekognitionClient.detectFaces(params).promise();
if (rawResult.FaceDetails?.length === 0) {
console.log('顔は検出されませんでした。');
} else {
//感情検出結果のリストから信頼度の一番高い感情データを1つ取得
const emotions = (rawResult.FaceDetails as FaceDetailList)[0]
.Emotions as Emotions;
const largestEmotionConfidence = Math.max(
...(emotions.map((d) => d.Confidence) as number[]),
);
const emotion = emotions.find(
(d) => d.Confidence === largestEmotionConfidence,
) as Emotion;
console.log(emotion);
}
};
React(react-webcam)で感情推定してみる
先日投稿したエントリのReactアプリに感情推定機能を実装してみました。ハイライト部分が追記箇所です。
src/App.tsx
import { useRef, useState, useCallback } from "react";
import Webcam from "react-webcam";
import { makeStyles } from "@material-ui/core/styles";
import {
DetectFacesRequest,
DetectFacesResponse,
FaceDetailList,
Emotions,
Emotion,
} from "aws-sdk/clients/rekognition";
import AWS from "aws-sdk";
const useStyles = makeStyles(() => ({
webcam: {
position: "absolute",
top: "0px",
left: "0px",
visibility: "hidden",
},
rekognizeResult: {
flex: 1,
width: "100%",
flexDirection: "row",
justifyContent: "flex-start",
},
}));
const videoConstraints = {
width: 720,
height: 360,
facingMode: "user",
};
AWS.config.update({
accessKeyId: process.env.REACT_APP_AWS_ACCESS_KEY_ID,
secretAccessKey: process.env.REACT_APP_AWS_SECRET_ACCESS_KEY,
region: process.env.REACT_APP_AWS_REGION,
});
const rekognitionClient = new AWS.Rekognition({
apiVersion: "2016-06-27",
});
//Amazon Rekognitionによる顔分析
const detectFaces = async (imageData: string): Promise<DetectFacesResponse> => {
const params: DetectFacesRequest = {
Image: {
Bytes: Buffer.from(
imageData.replace("data:image/jpeg;base64,", ""),
"base64"
),
},
Attributes: ["ALL"],
};
return await rekognitionClient.detectFaces(params).promise();
};
//分析結果からConfidence(分析結果の信頼度)取得
const getConfidence = (rekognizeResult: DetectFacesResponse): number => {
return (rekognizeResult.FaceDetails as FaceDetailList)[0].Confidence!;
};
//分析結果からLowAge(推測される年齢範囲の加減)取得
const getLowAge = (rekognizeResult: DetectFacesResponse): number => {
return (rekognizeResult.FaceDetails as FaceDetailList)[0].AgeRange?.Low!;
};
//分析結果からHighAge(推測される年齢範囲の上限)取得
const getHighAge = (rekognizeResult: DetectFacesResponse): number => {
return (rekognizeResult.FaceDetails as FaceDetailList)[0].AgeRange?.High!;
};
//分析結果からEyeglasses(眼鏡を掛けているか)取得
const getIsWearingEyeGlasses = (
rekognizeResult: DetectFacesResponse
): boolean => {
return (rekognizeResult.FaceDetails as FaceDetailList)[0].Eyeglasses?.Value!;
};
//分析結果からEyeglasses(サングラスを掛けているか)取得
const getIsWearingSunGlasses = (
rekognizeResult: DetectFacesResponse
): boolean => {
return (rekognizeResult.FaceDetails as FaceDetailList)[0].Sunglasses?.Value!;
};
//分析結果から感情を推定
const getEmotion = (rekognizeResult: DetectFacesResponse): string => {
const emotions = (rekognizeResult.FaceDetails as FaceDetailList)[0]
.Emotions as Emotions;
const largestEmotionConfidence = Math.max(
...(emotions.map((d) => d.Confidence) as number[])
);
const emotion = emotions.find(
(d) => d.Confidence === largestEmotionConfidence
) as Emotion;
return emotion.Type as string;
};
const App = () => {
const classes = useStyles();
const [isCaptureEnable, setCaptureEnable] = useState<boolean>(false);
const webcamRef = useRef<Webcam>(null);
const [url, setUrl] = useState<string | null>(null);
const capture = useCallback(() => {
const imageSrc = webcamRef.current?.getScreenshot();
if (imageSrc) {
setUrl(imageSrc);
setRekognizeResult(undefined);
}
}, [webcamRef]);
const [rekognizeResult, setRekognizeResult] = useState<DetectFacesResponse>();
const rekognizeHandler = async () => {
const result: DetectFacesResponse = await detectFaces(url as string);
setRekognizeResult(result);
console.log(result);
};
return (
<>
<header>
<h1>カメラアプリ(顔分析付き)</h1>
</header>
{isCaptureEnable || (
<button onClick={() => setCaptureEnable(true)}>開始</button>
)}
{isCaptureEnable && (
<>
<div>
<button onClick={() => setCaptureEnable(false)}>終了</button>
</div>
<div>
<Webcam
audio={false}
width={540}
height={360}
ref={webcamRef}
screenshotFormat="image/jpeg"
videoConstraints={videoConstraints}
className={classes.webcam}
/>
</div>
<button onClick={capture}>キャプチャ</button>
</>
)}
{url && (
<>
<div>
<button
onClick={() => {
setUrl(null);
setRekognizeResult(undefined);
}}
>
削除
</button>
<button onClick={() => rekognizeHandler()}>分析</button>
</div>
<div>
<img src={url} alt="Screenshot" />
</div>
{typeof rekognizeResult !== "undefined" && (
<div className={classes.rekognizeResult}>
<div>{"Confidence: " + getConfidence(rekognizeResult)}</div>
<div>
{"AgeRange: " +
getLowAge(rekognizeResult) +
" ~ " +
getHighAge(rekognizeResult)}
</div>
<div>
{"Eyeglasses: " + getIsWearingEyeGlasses(rekognizeResult)}
</div>
<div>
{"Sunglasses: " + getIsWearingSunGlasses(rekognizeResult)}
</div>
<div>{"Emotion: " + getEmotion(rekognizeResult)}</div>
</div>
)}
</>
)}
</>
);
};
export default App;
- CALM(穏やか)
-
SURPRISED(驚き)
-
HAPPY(幸せ)
-
SAD(悲しみ)
-
CONFUSED(混乱)
狙った感情を分析結果で出すのがなかなか難しくてゲームみたいになりました。
参考
以上