본문 바로가기

안드로이드

KotlinDl - Android 물건탐지, 동작탐지 등등

반응형

안드로이드에서 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 에 대한 처리도 해놓았다.
카메라와 연동한 예제는 샘플 앱에 자세하게 나와있으니 그걸 참고하면 된다.

 

2022.12.16 - [코틀린] - KotlinDl - 코틀린 버전의 딥러닝

반응형