[FishingMemory]사이즈 수동 측정에서 자동 측정

hegleB·2024년 6월 20일
0

1. 내장 카메라 사용

 val takePictureLauncher = rememberLauncherForActivityResult(
        contract = ActivityResultContracts.StartActivityForResult()
    ) { result ->
	    val extras = result.data?.extras
    }
private fun startCamera(takePictureLauncher: ManagedActivityResultLauncher<Intent, ActivityResult>) {
    val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
    takePictureLauncher.launch(intent)
}

안드로이드 내장 카메라로 촬영된 이미지를 전송을 하게 된다.

그러나 이미지를 고화질 이미지를 가져오지 못하는 문제가 발생하였다.

왜 고화질 이미지를 가져오지 못할까??

(참고 자료: https://stackoverflow.com/questions/8552514/is-there-any-limit-of-bundle-in-android)

Bundle에 담을 수 있는 데이터의 크기에는 제한이 있다. 이 제한은 약 1MB로 알려져 있다. 일반적으로 비트맵 이미지는 픽셀 당 24비트를 사용한다. 따라서 1920x1080 해상도의 이미지 크기를 계산하면 다음과 같다

  • 이미지 전체 픽셀 수: 1920 * 1080 = 2,073,600 픽셀
  • 비트 수: 2,073,600 픽셀 * 24 비트 = 49,766,400 비트
  • 바이트 수 계산: 49,766,400 비트 / 8 = 6,220,800 바이트

따라서 전체 메가바이트 수는 약 5.93MB가 된다. 이러한 이유로, 이미지를 Bundle에 담아 전송할 때는 압축이 필요하며, 이로 인해 고해상도의 이미지를 전송하는 대신 저해상도의 이미지를 전달하게 된다.

고해상도 이미지 얻기

(참고자료: https://developer.android.com/reference/androidx/core/content/FileProvider)

 fun getImageUri(context: Context): Uri {
            val directory = File(context.cacheDir, "images")
            directory.mkdirs()
            val file = File.createTempFile(
                "selected_image_",
                ".jpg",
                directory,
            )
            val authority = context.packageName + ".provider"
            return getUriForFile(
                context,
                authority,
                file,
            )

이미지를 저장할 디렉토리를 생성한 후, File.createTempFile를 사용하여 임시 파일을 만든다. 그런 다음, FileProvider를 위한 authority를 생성하고, FileProvider.getUriForFile 메서드를 사용하여 해당 파일의 URI를 생성하고 반환한다.

이 과정을 통해 카메라 앱이 고해상도 이미지를 해당 파일에 저장할 수 있으며, 안전하게 저장된 파일에 접근할 수 있다.

CameraX 라이브러리

내장 카메라를 사용할 때 커스터마이징이 어렵고, 물체를 인식하여 크기를 측정하는 데 한계가 있었다.

이 문제를 해결하기 위해 CameraX 라이브러리를 도입하였다. CameraX는 Android Jetpack 라이브러리의 일부로, 안드로이드에서 카메라 애플리케이션을 쉽게 개발할 수 있도록 도와준다. Camera2 API의 강력한 기능을 유지하면서도 사용하기 쉽게 설계되어, 다양한 카메라 기능을 간편하게 구현할 수 있다. 특히, CameraX는 ML Kit과의 통합이 용이하여, 이미지 분석 기능을 쉽게 추가할 수 있다.

핵심 구성 요소

cameraProviderFuture.addListener(Runnable {
		val preview = Preview.Builder()
			.build()
			.also {
				it.setSurfaceProvider(viewFinder.surfaceProvider)
			}
}

Preview: 카메라 미리보기 기능 제공

imageCapture.takePicture(
       outputOptions, ContextCompat.getMainExecutor(this), object : ImageCapture.OnImageSavedCallback {
           override fun onError(exc: ImageCaptureException) {
               L
           }

            override fun onCaptureSuccess(image: ImageProxy) {
              
           }
       })

Image Capture: 사진 촬영 기능 제공

val imageAnalyzer = ImageAnalysis.Builder()
      .setDefaultResolution(screenSize)
      .build()
val imageAnalysis = ImageAnalysis(imageAnalyzer)

imageAnalysis.setAnalyzer(ContextCompat.getMainExecutor(context)) { imageProxy ->
   
})

Image Analysis: 실시간 이미지 분석을 위해 각 프레임 제공

val camera = cameraProvider.bindToLifecycle(
                this as LifecycleOwner, cameraSelector, preview, imageCapture)

Lifecycle Bind: CameraX 라이브러라를 사용하면 Lifecycle 문제를 해결하기 위해 사용

ML Kit 도입하기

ML Kit은 구글이 제공하는 모바일용 머신러닝 SDK로, 머신러닝 기능을 손쉽게 통합할 수 있도록 도와준다. ML Kit은 Google의 머신러닝 모델을 활용하여 이미지 레이블링, 얼굴 인식, 텍스트 인식, 바코드 스캔 등의 기능을 제공한다. 물고기 사이즈를 측정하기 위해서 Object-Detection를 사용하였다.

val options = ObjectDetectorOptions.Builder()
        .setDetectorMode(ObjectDetectorOptions.SINGLE_IMAGE_MODE)
        .enableMultipleObjects()
        .enableClassification()
        .build()
  • 감지 모드는 STREAM_MODE,| SINGLE_IMAGE_MODE 두가지가 있다. STREAM_MODE를 사용하게 되면 경계 상자가 불완전한 결과를 가져올 수 있기 때문에 SINGLE_IMAGE_MODE로 설정하였다. 여러 객체를 감지하기 위해 enableMultipleObjects 설정하고 감지된 객체를 카테고리로 분류할 수 있도록 enableClassification를 사용하였다.
objectDetector.process(image)
    .addOnSuccessListener { detectedObjects ->
    
    }
  
    .addOnFailureListener { e ->
       
    }
  • 객체 감지가 성공하면 반환된 detectedObjects 리스트를 반복하면서 각 객체에 대해 필요한 작업을 수행한다. 여기에는 객체의 경계 상자(boundingBox), 추적 ID(trackingId), 및 라벨 정보(labels)가 포함되어 있다

물고기, 카드 인식 구분의 어려움

enableClassification 옵션을 설정했음에도 불구하고 물고기와 카드를 구분하는 데 한계가 있었다. 이 문제를 해결하기 위해, 인식된 이미지에서 위쪽은 물고기로, 아래쪽은 카드로 처리하는 방법을 선택했다. 이를 위해 y 좌표의 중심값을 기준으로 이미지를 구분하였고, 결과를 리스트 형태로 받아서 처리했다.

profile
성장하는 개발자

0개의 댓글

관련 채용 정보