본문 바로가기

Development/Android

Firebase ML Kit 검토

Firebase에서 출시한 머신러닝 킷으로 MLKit을 통해 사용자의 이미지정보에 대해서 추론한 정보를 획득할 수 있게 되었음. 이를 활용할 수 있는 범위에 대해서 살펴보기 위해 기술검토를 수행하였다.


개요

기존 Cloud Platform에서 제공되고 있던 Vision Api 를 기반으로 하여 On-Device에서도 이미지를 통한 검출결과를 제공하도록 만든 것이 MLKit이다. On-Device에서는 제한적으로 기능이 제공되고 있으며(인식결과의 가지수,랜드마크 등) Cloud에서는 좀더 풍부한 결과를 제공하나, 인식시간(네트워크)비용 1k당 1.5$ 등이 발생하여 우선은 On-Device위주로 검토 하였다.

아래의 이미지는 현재 지원하는 범위이며, 이후 Smart Reply 를 지원할 계획이라고 들었다(Google I/O recap)




실 서비스 에서의 활용 방안

현재로서는 특별한 기능을 제공해 주기에는 한계가 있을 것으로 보여진다. (Cropper에서 이미지 자르기 영역을 정해준다거나?) 다만 사용자가 어떤 이미지를 배경화면으로 사용하고 있는지에 대한 정보를 얻을 수 있을 것이라고 기대하여 Face Detecting과 Image Label Detecting 에 대해서 검토하였다.

바코드 등은 오프라인 사물을 디텍딩 하거나 하기에 유용할 것으로 기대하나 당장은 활용범위가 뚜렷하지 않은 상황
텍스트 인식은 품질이 어떨지에 따라 메모앱 등에서 활용이 가능할 것으로 예상된다.(다만 인식의 정확도를 위해 Cloud를 활용해야 할것으로 보인다.)


Api 호출 예제(Vision Label, Face)


FirebaseVisionLabelDetectorOptions options =
new FirebaseVisionLabelDetectorOptions.Builder()
.setConfidenceThreshold(0.7f)
.build();

FirebaseVisionImage image = null;
try {
image = FirebaseVisionImage.fromFilePath(this, file);
} catch (IOException e) {
e.printStackTrace();
}


if (image != null){
FirebaseVisionLabelDetector labelDetector = FirebaseVision.getInstance()
.getVisionLabelDetector(options);

Task<List<FirebaseVisionLabel>> result =
labelDetector.detectInImage(image)
.addOnSuccessListener(
new OnSuccessListener<List<FirebaseVisionLabel>>() {
@Override
public void onSuccess(List<FirebaseVisionLabel> labels) {
// Task completed successfully
// ...

for (FirebaseVisionLabel label: labels) {
String text = label.getLabel();
String entityId = label.getEntityId();
float confidence = label.getConfidence();

LogUtil.e("TAG", ":::FirebaseVisionLabelDetector:label="+text+"::"+confidence);
}
}
})
.addOnFailureListener(
new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
// Task failed with an exception
// ...
}
});


FirebaseVisionFaceDetectorOptions faceDetectorOptions =
new FirebaseVisionFaceDetectorOptions.Builder()
.setModeType(FirebaseVisionFaceDetectorOptions.ACCURATE_MODE)
.setLandmarkType(FirebaseVisionFaceDetectorOptions.ALL_LANDMARKS)
.setClassificationType(FirebaseVisionFaceDetectorOptions.ALL_CLASSIFICATIONS)
.setMinFaceSize(0.15f)
.setTrackingEnabled(true)
.build();

FirebaseVisionFaceDetector faceDetector = FirebaseVision.getInstance()
.getVisionFaceDetector(faceDetectorOptions);

Task<List<FirebaseVisionFace>> faceResult =
faceDetector.detectInImage(image)
.addOnSuccessListener(
new OnSuccessListener<List<FirebaseVisionFace>>() {
@Override
public void onSuccess(List<FirebaseVisionFace> faces) {
// Task completed successfully
// ...

for (FirebaseVisionFace face : faces) {
Rect bounds = face.getBoundingBox();
float rotY = face.getHeadEulerAngleY(); // Head is rotated to the right rotY degrees
float rotZ = face.getHeadEulerAngleZ(); // Head is tilted sideways rotZ degrees

// If landmark detection was enabled (mouth, ears, eyes, cheeks, and
// nose available):
FirebaseVisionPoint leftEyePos = null;
FirebaseVisionFaceLandmark leftEye = face.getLandmark(FirebaseVisionFaceLandmark.LEFT_EYE);
if (leftEye != null) {
leftEyePos = leftEye.getPosition();
}
float smileProb = 0;
// If classification was enabled:
if (face.getSmilingProbability() != FirebaseVisionFace.UNCOMPUTED_PROBABILITY) {
smileProb = face.getSmilingProbability();
}
if (face.getRightEyeOpenProbability() != FirebaseVisionFace.UNCOMPUTED_PROBABILITY) {
float rightEyeOpenProb = face.getRightEyeOpenProbability();
}


// If face tracking was enabled:
if (face.getTrackingId() != FirebaseVisionFace.INVALID_ID) {
int id = face.getTrackingId();
}




LogUtil.e("TAG", ":::FirebaseVisionFace smile"+smileProb);
if (leftEyePos != null){
LogUtil.e("TAG", ":::FirebaseVisionFace leftEyePos"+leftEyePos);
}
}
}
})
.addOnFailureListener(
new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
// Task failed with an exception
// ...
}

                                            });