ML Kit를 사용하면 주제 세분화 기능을 앱에 쉽게 추가할 수 있습니다.
<ph type="x-smartling-placeholder">기능 | 세부정보 |
---|---|
SDK 이름 | play-services-mlkit-subject-segmentation |
구현 | 번들로 묶이지 않음: 모델이 Google Play 서비스를 사용하여 동적으로 다운로드됩니다. |
앱 크기 영향 | 크기가 최대 200KB 늘어났습니다. |
초기화 시간 | 사용자는 처음 사용하기 전에 모델이 다운로드될 때까지 기다려야 할 수도 있습니다. |
사용해 보기
- 샘플 앱을 사용하여 이 API의 사용 예를 참조하세요.
시작하기 전에
<ph type="x-smartling-placeholder">- 프로젝트 수준
build.gradle
파일의buildscript
및allprojects
섹션에 Google의 Maven 저장소가 포함되어야 합니다. - 모듈의 앱 수준 Gradle 파일(일반적으로
app/build.gradle
)에 ML Kit 주제 세분화 라이브러리의 종속 항목을 추가합니다.
dependencies {
implementation 'com.google.android.gms:play-services-mlkit-subject-segmentation:16.0.0-beta1'
}
위에서 언급했듯이 모델은 Google Play 서비스에서 제공합니다.
모델을 기기에 자동으로 다운로드하도록 앱을 구성할 수 있습니다.
Play 스토어에서 앱을 설치한 후 이렇게 하려면 다음을 추가합니다.
선언을 앱의 AndroidManifest.xml
파일에 추가합니다.
<application ...>
...
<meta-data
android:name="com.google.mlkit.vision.DEPENDENCIES"
android:value="subject_segment" >
<!-- To use multiple models: android:value="subject_segment,model2,model3" -->
</application>
또한 모델 가용성을 명시적으로 확인하고 ModuleInstallClient API를 사용하여 Google Play 서비스를 통해 다운로드를 요청할 수 있습니다.
설치 시간 모델 다운로드를 사용 설정하지 않거나 명시적 다운로드를 요청하지 않는 경우 세그먼트 도구를 처음 실행할 때 모델이 다운로드됩니다. 내가 한 요청 결과가 나오지 않습니다.
1. 입력 이미지 준비
이미지 세분화를 수행하려면 InputImage
객체를 만듭니다.
Bitmap
, media.Image
, ByteBuffer
, 바이트 배열 또는
있습니다.
InputImage
를 만들 수 있습니다.
아래에 각각 설명되어 있습니다.
media.Image
사용
InputImage
를 만들려면 다음 안내를 따르세요.
(예: media.Image
객체에서 이미지를 캡처할 때)
기기의 카메라에서 이미지를 캡처하려면 media.Image
객체와 이미지의
InputImage.fromMediaImage()
로 회전
<ph type="x-smartling-placeholder"></ph>
CameraX 라이브러리, OnImageCapturedListener
및
회전 값을 계산하는 ImageAnalysis.Analyzer
클래스
있습니다.
Kotlin
private class YourImageAnalyzer : ImageAnalysis.Analyzer { override fun analyze(imageProxy: ImageProxy) { val mediaImage = imageProxy.image if (mediaImage != null) { val image = InputImage.fromMediaImage(mediaImage, imageProxy.imageInfo.rotationDegrees) // Pass image to an ML Kit Vision API // ... } } }
자바
private class YourAnalyzer implements ImageAnalysis.Analyzer { @Override public void analyze(ImageProxy imageProxy) { Image mediaImage = imageProxy.getImage(); if (mediaImage != null) { InputImage image = InputImage.fromMediaImage(mediaImage, imageProxy.getImageInfo().getRotationDegrees()); // Pass image to an ML Kit Vision API // ... } } }
이미지의 회전 각도를 제공하는 카메라 라이브러리를 사용하지 않는 경우 기기의 회전 각도와 카메라의 방향에서 센서에 있어야 합니다.
Kotlin
private val ORIENTATIONS = SparseIntArray() init { ORIENTATIONS.append(Surface.ROTATION_0, 0) ORIENTATIONS.append(Surface.ROTATION_90, 90) ORIENTATIONS.append(Surface.ROTATION_180, 180) ORIENTATIONS.append(Surface.ROTATION_270, 270) } /** * Get the angle by which an image must be rotated given the device's current * orientation. */ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Throws(CameraAccessException::class) private fun getRotationCompensation(cameraId: String, activity: Activity, isFrontFacing: Boolean): Int { // Get the device's current rotation relative to its "native" orientation. // Then, from the ORIENTATIONS table, look up the angle the image must be // rotated to compensate for the device's rotation. val deviceRotation = activity.windowManager.defaultDisplay.rotation var rotationCompensation = ORIENTATIONS.get(deviceRotation) // Get the device's sensor orientation. val cameraManager = activity.getSystemService(CAMERA_SERVICE) as CameraManager val sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION)!! if (isFrontFacing) { rotationCompensation = (sensorOrientation + rotationCompensation) % 360 } else { // back-facing rotationCompensation = (sensorOrientation - rotationCompensation + 360) % 360 } return rotationCompensation }
자바
private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); static { ORIENTATIONS.append(Surface.ROTATION_0, 0); ORIENTATIONS.append(Surface.ROTATION_90, 90); ORIENTATIONS.append(Surface.ROTATION_180, 180); ORIENTATIONS.append(Surface.ROTATION_270, 270); } /** * Get the angle by which an image must be rotated given the device's current * orientation. */ @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private int getRotationCompensation(String cameraId, Activity activity, boolean isFrontFacing) throws CameraAccessException { // Get the device's current rotation relative to its "native" orientation. // Then, from the ORIENTATIONS table, look up the angle the image must be // rotated to compensate for the device's rotation. int deviceRotation = activity.getWindowManager().getDefaultDisplay().getRotation(); int rotationCompensation = ORIENTATIONS.get(deviceRotation); // Get the device's sensor orientation. CameraManager cameraManager = (CameraManager) activity.getSystemService(CAMERA_SERVICE); int sensorOrientation = cameraManager .getCameraCharacteristics(cameraId) .get(CameraCharacteristics.SENSOR_ORIENTATION); if (isFrontFacing) { rotationCompensation = (sensorOrientation + rotationCompensation) % 360; } else { // back-facing rotationCompensation = (sensorOrientation - rotationCompensation + 360) % 360; } return rotationCompensation; }
그런 다음 media.Image
객체와
회전 각도 값을 InputImage.fromMediaImage()
로:
Kotlin
val image = InputImage.fromMediaImage(mediaImage, rotation)
Java
InputImage image = InputImage.fromMediaImage(mediaImage, rotation);
파일 URI 사용
InputImage
를 만들려면 다음 안내를 따르세요.
객체를 만들고, 앱 컨텍스트와 파일 URI를
InputImage.fromFilePath()
입니다. 이 기능은
ACTION_GET_CONTENT
인텐트를 사용하여 사용자에게 선택하라는 메시지를 표시합니다.
만들 수 있습니다
Kotlin
val image: InputImage try { image = InputImage.fromFilePath(context, uri) } catch (e: IOException) { e.printStackTrace() }
Java
InputImage image; try { image = InputImage.fromFilePath(context, uri); } catch (IOException e) { e.printStackTrace(); }
ByteBuffer
또는 ByteArray
사용
InputImage
를 만들려면 다음 안내를 따르세요.
ByteBuffer
또는 ByteArray
이전에 media.Image
입력에 대해 설명한 회전 각도입니다.
그런 다음 버퍼 또는 배열과 이미지의 InputImage
객체를
높이, 너비, 색상 인코딩 형식 및 회전 각도:
Kotlin
val image = InputImage.fromByteBuffer( byteBuffer, /* image width */ 480, /* image height */ 360, rotationDegrees, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 ) // Or: val image = InputImage.fromByteArray( byteArray, /* image width */ 480, /* image height */ 360, rotationDegrees, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 )
자바
InputImage image = InputImage.fromByteBuffer(byteBuffer, /* image width */ 480, /* image height */ 360, rotationDegrees, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 ); // Or: InputImage image = InputImage.fromByteArray( byteArray, /* image width */480, /* image height */360, rotation, InputImage.IMAGE_FORMAT_NV21 // or IMAGE_FORMAT_YV12 );
Bitmap
사용
InputImage
를 만들려면 다음 안내를 따르세요.
객체를 Bitmap
객체에서 삭제하려면 다음과 같이 선언합니다.
Kotlin
val image = InputImage.fromBitmap(bitmap, 0)
Java
InputImage image = InputImage.fromBitmap(bitmap, rotationDegree);
이미지는 회전 각도와 함께 Bitmap
객체로 표현됩니다.
2. SubjectSegmenter 인스턴스 만들기
분류 기준 옵션 정의
이미지를 분류하려면 먼저 다음과 같이 SubjectSegmenterOptions
의 인스턴스를 만드세요.
팔로우:
Kotlin
val options = SubjectSegmenterOptions.Builder() // enable options .build()
자바
SubjectSegmenterOptions options = new SubjectSegmenterOptions.Builder() // enable options .build();
각 옵션의 세부정보는 다음과 같습니다.
포그라운드 신뢰도 마스크
포그라운드 신뢰도 마스크를 사용하면 포그라운드 피사체와 만들 수 있습니다.
나중에 가져올 수 있는 옵션에서 enableForegroundConfidenceMask()
호출
getForegroundMask()
을 호출하여 포그라운드 마스크를
이미지를 처리한 후 반환된 SubjectSegmentationResult
객체
Kotlin
val options = SubjectSegmenterOptions.Builder() .enableForegroundConfidenceMask() .build()
자바
SubjectSegmenterOptions options = new SubjectSegmenterOptions.Builder() .enableForegroundConfidenceMask() .build();
포그라운드 비트맵
마찬가지로 포그라운드 피사체의 비트맵을 가져올 수도 있습니다.
나중에 가져올 수 있는 옵션에서 enableForegroundBitmap()
를 호출합니다.
getForegroundBitmap()
을 호출하여 전경 비트맵을
이미지를 처리한 후 반환된 SubjectSegmentationResult
객체
Kotlin
val options = SubjectSegmenterOptions.Builder() .enableForegroundBitmap() .build()
자바
SubjectSegmenterOptions options = new SubjectSegmenterOptions.Builder() .enableForegroundBitmap() .build();
다중 주제 신뢰도 마스크
포그라운드 옵션과 마찬가지로 SubjectResultOptions
를 사용하여
각 포그라운드 대상의 신뢰도 마스크는 다음과 같습니다.
Kotlin
val subjectResultOptions = SubjectSegmenterOptions.SubjectResultOptions.Builder() .enableConfidenceMask() .build() val options = SubjectSegmenterOptions.Builder() .enableMultipleSubjects(subjectResultOptions) .build()
자바
SubjectResultOptions subjectResultOptions = new SubjectSegmenterOptions.SubjectResultOptions.Builder() .enableConfidenceMask() .build() SubjectSegmenterOptions options = new SubjectSegmenterOptions.Builder() .enableMultipleSubjects(subjectResultOptions) .build()
다중 대상 비트맵
마찬가지로 각 주제에 비트맵을 사용 설정할 수 있습니다.
Kotlin
val subjectResultOptions = SubjectSegmenterOptions.SubjectResultOptions.Builder() .enableSubjectBitmap() .build() val options = SubjectSegmenterOptions.Builder() .enableMultipleSubjects(subjectResultOptions) .build()
자바
SubjectResultOptions subjectResultOptions = new SubjectSegmenterOptions.SubjectResultOptions.Builder() .enableSubjectBitmap() .build() SubjectSegmenterOptions options = new SubjectSegmenterOptions.Builder() .enableMultipleSubjects(subjectResultOptions) .build()
주제 분류 기준 만들기
SubjectSegmenterOptions
옵션을 지정한 후에는
SubjectSegmenter
인스턴스를 호출하고 getClient()
옵션을
매개변수:
Kotlin
val segmenter = SubjectSegmentation.getClient(options)
Java
SubjectSegmenter segmenter = SubjectSegmentation.getClient(options);
3. 이미지 처리
준비된 InputImage
을 전달합니다.
객체를 SubjectSegmenter
의 process
메서드에 추가합니다.
Kotlin
segmenter.process(inputImage) .addOnSuccessListener { result -> // Task completed successfully // ... } .addOnFailureListener { e -> // Task failed with an exception // ... }
Java
segmenter.process(inputImage) .addOnSuccessListener(new OnSuccessListener() { @Override public void onSuccess(SubjectSegmentationResult result) { // Task completed successfully // ... } }) .addOnFailureListener(new OnFailureListener() { @Override public void onFailure(@NonNull Exception e) { // Task failed with an exception // ... } });
4. 주제 세분화 결과 가져오기
포그라운드 마스크 및 비트맵 검색
처리가 완료되면 이미지 호출을 위한 포그라운드 마스크를 가져올 수 있습니다.
getForegroundConfidenceMask()
는 다음과 같습니다.
Kotlin
val colors = IntArray(image.width * image.height) val foregroundMask = result.foregroundConfidenceMask for (i in 0 until image.width * image.height) { if (foregroundMask[i] > 0.5f) { colors[i] = Color.argb(128, 255, 0, 255) } } val bitmapMask = Bitmap.createBitmap( colors, image.width, image.height, Bitmap.Config.ARGB_8888 )
자바
int[] colors = new int[image.getWidth() * image.getHeight()]; FloatBuffer foregroundMask = result.getForegroundConfidenceMask(); for (int i = 0; i < image.getWidth() * image.getHeight(); i++) { if (foregroundMask.get() > 0.5f) { colors[i] = Color.argb(128, 255, 0, 255); } } Bitmap bitmapMask = Bitmap.createBitmap( colors, image.getWidth(), image.getHeight(), Bitmap.Config.ARGB_8888 );
getForegroundBitmap()
를 호출하는 이미지의 포그라운드 비트맵을 가져올 수도 있습니다.
Kotlin
val foregroundBitmap = result.foregroundBitmap
자바
Bitmap foregroundBitmap = result.getForegroundBitmap();
각 대상의 마스크 및 비트맵 검색
마찬가지로
각 주제에 관한 getConfidenceMask()
은(는) 다음과 같습니다.
Kotlin
val subjects = result.subjects val colors = IntArray(image.width * image.height) for (subject in subjects) { val mask = subject.confidenceMask for (i in 0 until subject.width * subject.height) { val confidence = mask[i] if (confidence > 0.5f) { colors[image.width * (subject.startY - 1) + subject.startX] = Color.argb(128, 255, 0, 255) } } } val bitmapMask = Bitmap.createBitmap( colors, image.width, image.height, Bitmap.Config.ARGB_8888 )
자바
Listsubjects = result.getSubjects(); int[] colors = new int[image.getWidth() * image.getHeight()]; for (Subject subject : subjects) { FloatBuffer mask = subject.getConfidenceMask(); for (int i = 0; i < subject.getWidth() * subject.getHeight(); i++) { float confidence = mask.get(); if (confidence > 0.5f) { colors[width * (subject.getStartY() - 1) + subject.getStartX()] = Color.argb(128, 255, 0, 255); } } } Bitmap bitmapMask = Bitmap.createBitmap( colors, image.width, image.height, Bitmap.Config.ARGB_8888 );
다음과 같이 세그먼트화된 각 주제의 비트맵에 액세스할 수도 있습니다.
Kotlin
val bitmaps = mutableListOf() for (subject in subjects) { bitmaps.add(subject.bitmap) }
자바
Listbitmaps = new ArrayList<>(); for (Subject subject : subjects) { bitmaps.add(subject.getBitmap()); }
실적 개선을 위한 팁
앱 세션마다 첫 번째 추론이 후속 추론보다 느린 경우가 많습니다. 추론할 수 있습니다. 짧은 지연 시간이 중요한 경우 '더미'라는 제공합니다
결과의 품질은 입력 이미지의 품질에 따라 달라집니다.
- ML Kit에서 정확한 세분화 결과를 얻으려면 이미지가 512x512픽셀 이상이어야 합니다.
- 이미지 초점이 잘 맞지 않으면 정확도에 영향을 줄 수도 있습니다. 허용 가능한 수준의 결과를 얻지 못하면 사용자에게 이미지를 다시 캡처하도록 요청합니다.