안드로이드에서 ObjectDetection, PoseDetection 같은 기능을 쉽게 적용할 수 있도록 해주는 라이브러리가 나왔다.
0. 라이브러리 추가
implementation 'org.jetbrains.kotlinx:kotlin-deeplearning-onnx:0.5.0'
1. 모델 다운로드하기
학습된 모델을 사용하기 위해선 해당 모델을 다운로드하는 과정이 필요하다.
// settings.gradle
pluginManagement {
repositories {
...
gradlePluginPortal()
}
}
// module build.gralde
plugins {
...
id 'org.jetbrains.kotlinx.kotlin-deeplearning-gradle-plugin' version "0.5.0"
}
downloadKotlinDLModels {
models = ["SSDMobileNetV1"]
overwrite = true
}
이를 위해서 downloadKotlinDLModels
라는 플러그인 함수를 제공한다.
models
에는 다운로드할 ( 사용할 ) 예정인 모델의 이름을 넣으면 된다.
여기서는 ObjectDetection.SSDMobileNetV1 모델을 기준으로 하였다.
overwrite
값에 true를 해놓으면 빌드할 때마다 해당 모델을 새롭게 받기 때문에 false로 하는 것이 빌드 시간을 줄 일 수 있다. ( 기본 값은 true이다.)
현재는 버그 때문인지 kotlin 1.7.10 버전까지만 동작한다.
1.7.20 버전부터는 다운로드하는 과정에서 아래 SSL 에러와 함께 빌드에 실패하게 된다.
> A failure occurred while executing de.undercouch.gradle.tasks.download.internal.DefaultWorkerExecutorHelper$DefaultWorkAction
> javax.net.ssl.SSLPeerUnverifiedException: Certificate for <kotlindl.s3.amazonaws.com> doesn't match any of the subject alternative names: [*.s3.amazonaws.com, s3.amazonaws.com]
2. 모델 사용하기
val modelHub = ONNXModelHub(this@MainActivity)
val model = ONNXModels.ObjectDetection.SSDMobileNetV1.pretrainedModel(modelHub)
val bitmap = getDrawable(R.drawable.test)!!.toBitmap()
val detectedObject = model.inferAndCloseUsing(ExecutionProvider.CPU()) {
it.detectObjects(image = bitmap, topK = 20)
}
모든 모델은 ONNXModels
를 통해서 접근할 수 있고,
학습된 모델을 가져오기 위해서 pretrainedModel
함수를 이용하면 된다.
모델 별로 detect 함수는
PoseDetection 인 경우 detectPose
ObjectDetection 인 경우 detectObjects
와 같은 식으로 조금씩 다르다.
모델을 사용할 때는 두 가지 옵션이 있다.inferAndCloseUsing
는 Model을 사용 후 바로 close 시키기 때문에 한 번밖에 사용할 수 없다.
재사용이 필요하다면 inferUsing
를 사용하고 직접 close 함수를 호출해주어야 한다.
3. 동작 옵션
동작 옵션도 선택할 수 있다.
model.inferAndCloseUsing(ExecutionProvider.NNAPI()) {
it.detectObjects(image = bitmap, topK = 20)
}
CPU
는 특별한 제약이 없는 디폴트 옵션이다.CUDA
는 Nvidia 그래픽카드가 있거나 Cuda 가 설치되어 있는 경우에 사용할 수 있다. ( 안드로이드에서는 못 쓴다. )NNAPI
는 NNAPI를 지원하는 안드로이드 기기 ( API 27 이상 )에서 사용할 수 있다.
4. 모델 종류
ObjectDetection : COCO 2017 DataSet으로 학습된 모델을 제공한다.
( 사람, 자전거, 차, 칫솔 등등 90가지 레이블이 있다. )
- EfficientDetLite0, SSDMobileNetV1
PoseDetection : 포즈 찾아주는 모델을 제공한다.
- MoveNetSinglePoseLightin , MoveNetSinglePoseThunder
CV : ImageNet DataSet으로 학습된 모델을 제공한다. ( 거위, 복서 등 1000가지 레이블이 있다. )
- EfficientNet4Lite, MobilenetV1
FaceAlignment : 얼굴의 106 가지 지점? 을 탐색하는 모델이다.
- Fan2d106
대충 이런 걸 찾아준다.
FaceDetection : 얼굴 찾아주는 모델을 제공한다.
- UltraFace320, UltraFace640
5. 예제
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.TopStart
) {
Image(
modifier = Modifier.fillMaxHeight(),
contentScale = ContentScale.FillHeight,
painter = painterResource(id = R.drawable.test), contentDescription = null
)
val modelHub = ONNXModelHub(this@MainActivity)
val model = ONNXModels.ObjectDetection.SSDMobileNetV1.pretrainedModel(modelHub)
val bitmap = getDrawable(R.drawable.test)!!.toBitmap()
val detectedObject = model.inferAndCloseUsing(ExecutionProvider.CPU()) {
model.detectObjects(image = bitmap, topK = 20)
}
BoxWithConstraints() {
detectedObject.forEach {
val rect = with(LocalDensity.current) {
val realWidth =
bitmap.width.toDp().times((maxHeight.toPx() / bitmap.height))
val realHeight = maxHeight
DpRect(
left = realWidth * it.xMin,
top = realHeight * it.yMin,
right = realWidth * it.xMax,
bottom = realHeight * it.yMax
)
}
Box(Modifier.offset(rect.left, rect.top)) {
Box(
modifier = Modifier
.size(rect.size)
.border(1.dp, Color.White)
)
Text(text = it.label.toString(), fontSize = 20.sp, color = Color.Black)
}
}
}
}
동작을 확인하기 위한 간단한 예제로
이미지를 넣었을 때 ObjectDetection.SSDMobileNetV1을 통해서 이미지에 있는 물건들을 찾는 코드이다.
그럴듯하게 잘 찾아주는 거 같다.
이것 말고도Bitmap
or BufferedImage
를 학습용 데이터로 쉽게 변환하기 위한 pipeline
이 있고,ImageAnalysis.Analyzer
와 호환되도록 ImageProxy
에 대한 처리도 해놓았다.
카메라와 연동한 예제는 샘플 앱에 자세하게 나와있으니 그걸 참고하면 된다.
'안드로이드' 카테고리의 다른 글
context receivers - 확장함수의 확장함수? (0) | 2023.01.10 |
---|---|
안드로이드 라이브러리 관리 자동화 (1) | 2022.11.15 |
Android - BuildSrc + Version Catalog ( 안드로이드 버전 관리하기 ) (0) | 2022.11.15 |
Android - Module Graph 그리기 (0) | 2022.11.13 |
Compose - Modifier.Node ( composed 상위호환 ) (0) | 2022.11.08 |