반응형
TensorFlow를 이용한 이미지 분석 구현과 해결 방법
안녕하세요! 오늘은 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를 사용하여 이미지를 분석하는 방법과 발생한 오류를 해결하는 방안을 모두 정리했습니다. 도움이 되셨길 바랍니다! 😊
반응형
'모바일 앱(안드로이드)' 카테고리의 다른 글
코디아 AI 디자인: 스크린샷을 편집 가능한 피그마 디자인으로 무분별하게 변형 ... AI 요약글 (2) | 2024.11.10 |
---|---|
Jetpack Compose를 이용한 Kakao Map LOD 라벨 추가 및 클릭 이벤트 처리 예제 (feat Kakao MAP) (1) | 2024.11.08 |
Jetpack Compose에서 Kakao Map API를 사용하여 지도 구현하기 (0) | 2024.11.04 |
Python을 이용한 Firebase Realtime Database 생성 및 Android Studio를 통한 데이터 읽기 (0) | 2024.10.31 |
Android에서 WorkManager를 InitializationProvider로 설정하기 (0) | 2024.10.21 |