오늘은 PorterDuff.Mode 와 ML kit 라이브러리를 활용하여 이미지 배경을 가리는 기능을 구현해보겠습니다.
자바 버전 >> https://stickode.tistory.com/949
해당 글을 보시기 전에 코틀린 버전으로 PorterDuff.Mode 를 활용하여 이미지 합치는 기능을 먼저 보고 와주세요
https://stickode.tistory.com/1057
ML Kit 이란?
ML Kit은 구글이 제공하는 모바일 애플리케이션을 위한 머신 러닝 라이브러리입니다. 이 라이브러리는 안드로이드와 iOS 플랫폼에서 사용할 수 있으며, 개발자들이 머신 러닝을 활용하여 자신들의 앱을 보다 지능적으로 만들 수 있게 도와줍니다.
ML Kit은 여러가지 머신 러닝 기능을 제공합니다. 주요 기능으로는 이미지와 텍스트 관련 작업을 수행하는 기능들이 포함되어 있습니다.
- 이미지 관련 작업:
- 이미지 라벨링(Labeling): 사진에서 물체나 장면 등을 식별하여 라벨을 부여합니다.
- 얼굴 감지(Face Detection): 사진이나 카메라 스트림에서 얼굴을 감지하고 특징을 분석합니다.
- 텍스트 감지(Text Detection): 이미지에서 텍스트를 감지하고 읽어내는 기능입니다.
- 이미지 세그멘테이션(Image Segmentation): 이미지를 객체와 배경으로 분할하여 객체를 식별합니다.
- 바코드 스캐닝(Barcode Scanning): 바코드를 스캔하고 정보를 추출합니다.
- 라벨 기반 물체 검출(Object Detection): 이미지에서 특정 물체들을 감지합니다.
- 텍스트 관련 작업:
- 텍스트 번역(Text Translation): 다양한 언어로 텍스트를 번역합니다.
- 언어 감지(Language Identification): 주어진 텍스트의 언어를 식별합니다.
ML Kit은 머신 러닝을 사용하더라도, 모델을 직접 훈련시킬 필요가 없이 간단한 API 호출을 통해 사용할 수 있습니다. 이는 개발자들에게 머신 러닝을 쉽게 적용할 수 있는 기회를 제공합니다.
또한 ML Kit은 오프라인에서도 동작하는 기능을 제공하며, 이는 사용자 경험을 향상시키는 데에 도움을 줍니다. ML Kit은 Firebase와도 통합되어 있어서 Firebase를 사용하는 애플리케이션에 머신 러닝을 쉽게 추가할 수 있습니다.
자세한 내용은 ML kit 홈페이지에서 확인해보세요
https://developers.google.com/ml-kit?hl=ko
MainActivity.kt
class MainActivity : AppCompatActivity() {
// 필요한 뷰 및 비트맵 변수 선언
private lateinit var imageView: ImageView
private lateinit var imageView3: ImageView
private lateinit var bitmap1: Bitmap
private lateinit var button: Button
private lateinit var segmenter: Segmenter
// 액티비티 생성 시 호출되는 메서드
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 레이아웃 설정
setContentView(R.layout.activity_main)
// 뷰와 버튼 초기화
imageView = findViewById(R.id.imageView)
imageView3 = findViewById(R.id.imageView3)
button = findViewById(R.id.button)
segmenterCreate()
// 첫 번째 이미지뷰에 비트맵 설정
bitmap1 = BitmapFactory.decodeResource(applicationContext.resources, R.drawable.img_3)
imageView.setImageBitmap(bitmap1)
// 버튼에 클릭 리스너 등록
button.setOnClickListener {
val drawable1 = imageView.drawable as BitmapDrawable
val dst = drawable1.bitmap
val mlImage = InputImage.fromBitmap(dst, 0)
segmenter.process(mlImage)
.addOnSuccessListener { segmentationMask ->
// Segmentation 성공 시 호출되는 메서드
// SegmentationMask에서 ByteBuffer, 가로 및 세로 크기를 가져옵니다.
val mask = segmentationMask.buffer
val maskWidth = segmentationMask.width
val maskHeight = segmentationMask.height
// ByteBuffer에서 색상 배열을 가져옵니다.
val arr = maskColorsFromByteBuffer(mask, maskWidth, maskHeight)
// 새로운 비트맵 객체를 생성합니다.
val segmentedBitmap = Bitmap.createBitmap(dst.width, dst.height, Bitmap.Config.ARGB_8888)
val maskBitmap = Bitmap.createBitmap(arr, maskWidth, maskHeight, Bitmap.Config.ARGB_8888)
// Canvas를 사용하여 이미지를 그립니다.
val canvas = Canvas(segmentedBitmap)
val paint = Paint()
canvas.drawBitmap(dst, 0f, 0f, paint)
// Xfermode를 설정하여 마스크를 적용합니다.
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP)
// 비트맵 크기를 조정하고 이동시켜서 블렌딩합니다.
val matrixz = Matrix()
matrixz.setScale(dst.width.toFloat() / maskBitmap.width, dst.height.toFloat() / maskBitmap.height)
matrixz.postTranslate(0f, 0f)
canvas.drawBitmap(maskBitmap, matrixz, paint)
// 결과 이미지를 imageView3에 설정합니다.
imageView3.setImageBitmap(segmentedBitmap)
}
}
}
// ByteBuffer에서 mask 색상 배열 추출
@ColorInt
private fun maskColorsFromByteBuffer(byteBuffer: ByteBuffer, maskWidth: Int, maskHeight: Int): IntArray {
val colors = IntArray(maskWidth * maskHeight)
for (i in 0 until maskWidth * maskHeight) {
val backgroundLikelihood = 1 - byteBuffer.getFloat()
if (backgroundLikelihood > 0.9) {
colors[i] = Color.rgb(51, 112, 69) // 높은 확률의 배경일 경우 녹색으로 설정
} else if (backgroundLikelihood > 0.2) {
colors[i] = Color.rgb(51, 112, 69) // 일반적인 배경일 경우 녹색으로 설정
}
}
return colors
}
// Segmentation 모델 초기화
private fun segmenterCreate() {
try {
val options = SelfieSegmenterOptions.Builder()
.setDetectorMode(SelfieSegmenterOptions.STREAM_MODE)
.enableRawSizeMask()
.build()
segmenter = Segmentation.getClient(options)
} catch (e: MlKitException) {
// Handle the exception appropriately
e.printStackTrace()
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ImageView
android:id="@+id/imageView"
android:layout_width="200dp"
android:layout_height="200dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:srcCompat="@tools:sample/avatars" />
<ImageView
android:id="@+id/imageView3"
android:layout_width="300dp"
android:layout_height="300dp"
app:layout_constraintBottom_toTopOf="@+id/button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/imageView"
tools:srcCompat="@tools:sample/avatars" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
'안드로이드 코틀린' 카테고리의 다른 글
[Kotlin][Android] Jetpack Compose 로 텍스트 목록 만들기 (2) | 2024.09.16 |
---|---|
[Android][코틀린] 이미지 필터 만들기 (2) | 2024.01.02 |
[Android][코틀린] 비트맵 합치기 PorterDuff.Mode (0) | 2023.12.15 |
[Android][Kotlin] ConnectivityManager를 활용하여 현재 인터넷 상태 가져오기 (2) | 2023.12.05 |
[Kotlin][Android] 카메라 기능 이용해서 이미지 받아오기 (0) | 2023.12.02 |