모바일 앱(안드로이드)

TensorFlow를 이용한 이미지 분석 구현과 해결 방법

Billcorea 2024. 11. 6. 15:33
반응형

TensorFlow를 이용한 이미지 분석 구현과 해결 방법

TenserFlow by AI

 

안녕하세요! 오늘은 TensorFlow Lite를 이용해 안드로이드 앱에서 이미지 분석을 수행하는 방법을 소개해드리려고 합니다. 과정에서 발생했던 오류들과 해결 방법도 함께 다루겠습니다. 😊

1. 환경 설정 라이브러리 추가

먼저, TensorFlow Lite와 관련된 종속성을 build.gradle 파일에 추가합니다.

groovy
dependencies {
    implementation 'org.tensorflow:tensorflow-lite:2.11.0'
    implementation 'org.tensorflow:tensorflow-lite-support:0.3.1'
    implementation 'org.tensorflow:tensorflow-lite-gpu:2.11.0'
}

2. 모델 레이블 파일 준비

사전 훈련된 모델(mobilenet_v1_1.0_224.tflite)과 레이블 파일(labels.txt)을 다운로드하여 assets 폴더에 추가합니다.

3. 이미지 로딩 전처리

이미지를 로드하고 모델의 입력 크기에 맞게 전처리합니다.

kotlin
import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import org.tensorflow.lite.Interpreter
import org.tensorflow.lite.support.common.FileUtil
import org.tensorflow.lite.support.image.TensorImage
import org.tensorflow.lite.support.tensorbuffer.TensorBuffer
import java.io.FileInputStream
import java.nio.ByteBuffer
import java.nio.ByteOrder

fun loadImage(context: Context, bitmap: Bitmap, inputShape: IntArray): ByteBuffer {
    val width = inputShape[1]
    val height = inputShape[2]
    val channels = inputShape[3]
    val inputSize = width * height * channels

    val resizedBitmap = Bitmap.createScaledBitmap(bitmap, width, height, true)
    val byteBuffer = ByteBuffer.allocateDirect(4 * inputSize).order(ByteOrder.nativeOrder())

    val pixels = IntArray(width * height)
    resizedBitmap.getPixels(pixels, 0, width, 0, 0, width, height)

    for (pixel in pixels) {
        val r = (pixel shr 16 and 0xFF) / 255.0f
        val g = (pixel shr 8 and 0xFF) / 255.0f
        val b = (pixel and 0xFF) / 255.0f

        byteBuffer.putFloat(r)
        byteBuffer.putFloat(g)
        byteBuffer.putFloat(b)
    }

    return byteBuffer
}

4. 모델 로드 이미지 분석

TensorFlow Lite 모델을 로드하고, 이미지를 분석하여 결과를 출력합니다.

kotlin
fun loadModel(context: Context, modelPath: String): Interpreter {
    val model = FileUtil.loadMappedFile(context, modelPath)
    return Interpreter(model)
}

fun classifyImage(context: Context, bitmap: Bitmap): String {
    val modelPath = "mobilenet_v1_1.0_224.tflite"
    val labelsPath = "labels.txt"
    val labels = FileUtil.loadLabels(context, labelsPath)
    val interpreter = loadModel(context, modelPath)

    val inputTensorShape = interpreter.getInputTensor(0).shape()
    val byteBuffer = loadImage(context, bitmap, inputTensorShape)
    val probabilityBuffer = TensorBuffer.createFixedSize(intArrayOf(1, labels.size), DataType.FLOAT32)
    interpreter.run(byteBuffer, probabilityBuffer.buffer.rewind())
    
    val labeledProbability = TensorLabel(labels, probabilityBuffer).mapWithFloatValue
    return labeledProbability.maxByOrNull { it.value }?.key ?: "Unknown"
}

5. 이미지 로딩 분석 결과 출력

이미지를 로드하고 분석하여 결과를 출력합니다.

kotlin
fun analyzeImage(context: Context, imagePath: String) {
    val bitmap = BitmapFactory.decodeStream(FileInputStream(imagePath))
    val result = classifyImage(context, bitmap)
    println("이미지 분석 결과: $result")
}

발생했던 오류와 해결 방안

오류 1: java.lang.IllegalArgumentException: Cannot copy to a TensorFlowLite tensor...

오류는 입력 데이터의 크기와 모델의 입력 텐서 크기 불일치로 인해 발생합니다. 이를 해결하기 위해 이미지를 모델의 입력 크기에 맞게 리사이즈하고 정규화합니다.

해결 방안:

kotlin
val inputTensorShape = interpreter.getInputTensor(0).shape()
val byteBuffer = loadImage(context, bitmap, inputTensorShape)

오류 2: java.lang.NullPointerException

오류는 null 값에 접근하려고 발생합니다. 이를 해결하기 위해 null 체크를 추가하여 안전한 코드를 작성합니다.

해결 방안:

kotlin
imageUrl?.let { uri ->
    val inputStream = context.contentResolver.openInputStream(uri)
    val btm = BitmapFactory.decodeStream(inputStream)
    val rotatedBtm = rotateImageIfRequired(btm, uri)
    bitmap.value = rotatedBtm
    bitmap.value?.let { btm ->
        // 코드 계속...
    } ?: run {
        Log.e("ImageDetectView", "Bitmap is null after rotation")
    }
} ?: run {
    Log.e("ImageDetectView", "image

 

이제 TensorFlow를 사용하여 이미지를 분석하는 방법과 발생한 오류를 해결하는 방안을 모두 정리했습니다. 도움이 되셨길 바랍니다! 😊

반응형