728x90
오늘은 PorterDuff.Mode 와 ML kit 라이브러리를 활용하여 이미지 배경을 가리는 기능을 구현해보겠습니다.
PorterDuff.Mode 를 활용하여 이미지 합치는 기능을 먼저 보고 와주세요 https://stickode.tistory.com/948
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
package com.example.stickcodeex;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.BitmapDrawable;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import com.google.android.gms.tasks.OnSuccessListener;
import com.google.mlkit.vision.common.InputImage;
import com.google.mlkit.vision.segmentation.Segmentation;
import com.google.mlkit.vision.segmentation.SegmentationMask;
import com.google.mlkit.vision.segmentation.Segmenter;
import com.google.mlkit.vision.segmentation.selfie.SelfieSegmenterOptions;
import java.nio.ByteBuffer;
public class MainActivity extends AppCompatActivity {
// 필요한 뷰 및 비트맵 변수 선언
ImageView imageView, imageView3;
Bitmap bitmap1;
Button button;
Segmenter segmenter;
// 액티비티 생성 시 호출되는 메서드
@Override
protected void onCreate(Bundle savedInstanceState) {
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(getApplicationContext().getResources(), R.drawable.img_3);
imageView.setImageBitmap(bitmap1);
// 버튼에 클릭 리스너 등록
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
BitmapDrawable drawable1 = (BitmapDrawable) imageView.getDrawable();
Bitmap dst = drawable1.getBitmap();
InputImage mlImage = InputImage.fromBitmap(dst, 0);
segmenter.process(mlImage)
.addOnSuccessListener(new OnSuccessListener<SegmentationMask>() {
@Override
public void onSuccess(@NonNull SegmentationMask segmentationMask) {
// Segmentation 성공 시 호출되는 메서드
// SegmentationMask에서 ByteBuffer, 가로 및 세로 크기를 가져옵니다.
ByteBuffer mask = segmentationMask.getBuffer();
int maskWidth = segmentationMask.getWidth();
int maskHeight = segmentationMask.getHeight();
// ByteBuffer에서 색상 배열을 가져옵니다.
int[] arr = maskColorsFromByteBuffer(mask, maskWidth, maskHeight);
// 새로운 비트맵 객체를 생성합니다.
Bitmap segmentedBitmap = Bitmap.createBitmap(dst.getWidth(), dst.getHeight(), Bitmap.Config.ARGB_8888);
Bitmap maskBitmap = Bitmap.createBitmap(arr, maskWidth, maskHeight, Bitmap.Config.ARGB_8888);
// Canvas를 사용하여 이미지를 그립니다.
Canvas canvas = new Canvas(segmentedBitmap);
Paint paint = new Paint();
canvas.drawBitmap(dst, 0, 0, paint);
// Xfermode를 설정하여 마스크를 적용합니다.
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
// 비트맵 크기를 조정하고 이동시켜서 블렌딩합니다.
Matrix matrixz = new Matrix();
matrixz.setScale((float) dst.getWidth() / maskBitmap.getWidth(), (float) dst.getHeight() / maskBitmap.getHeight());
matrixz.postTranslate(0, 0);
canvas.drawBitmap(maskBitmap, matrixz, paint);
// 결과 이미지를 imageView3에 설정합니다.
imageView3.setImageBitmap(segmentedBitmap);
}
});
}
});
}
// ByteBuffer에서 mask 색상 배열 추출
@ColorInt
private int[] maskColorsFromByteBuffer(ByteBuffer byteBuffer, int maskWidth, int maskHeight) {
@ColorInt int[] colors = new int[maskWidth * maskHeight];
for (int i = 0; i < maskWidth * maskHeight; i++) {
float 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 모델 초기화
public void segmenterCreate() {
SelfieSegmenterOptions options =
new SelfieSegmenterOptions.Builder()
.setDetectorMode(SelfieSegmenterOptions.STREAM_MODE)
.enableRawSizeMask()
.build();
segmenter = Segmentation.getClient(options);
}
}
xml 코드입니다.
activity_main
<?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>
결과입니다.
'안드로이드 자바' 카테고리의 다른 글
[Android][Java] 새 액티비티에서 응답받기 Intent, startActivityForResult (2) | 2023.12.25 |
---|---|
[Android][Java] SQLite Database 데이터베이스 툴 사용하기 (0) | 2023.12.16 |
[Android][Java] 버튼 클릭으로 소리 출력하기 (0) | 2023.12.10 |
[JAVA][Android] SQLite & Dao 사용하기 (2) | 2023.12.06 |
[JAVA][Android] 지문인식 기능 만들기 (0) | 2023.11.30 |