I am using Selfie Segmentation to remove the background and using overlay effect to display it but the probelm is i need to somehow hide the preview and just display the OverlayEffect
[*]Clone this repo
[*]Open in Android Studio
[*]The preview is visible along with the Overlay Effect
< /ol>
Вот код < /p>
class MainActivity : AppCompatActivity() {
private var imageCapture: ImageCapture? = null
private lateinit var cameraExecutor: ExecutorService
private lateinit var viewFinder: PreviewView
private lateinit var button: Button
private lateinit var greenScreenEffect: OverlayEffect
private val activityResultLauncher =
registerForActivityResult(
ActivityResultContracts.RequestMultiplePermissions()
)
{ permissions ->
// Handle Permission granted/rejected
var permissionGranted = true
permissions.entries.forEach {
if (it.key in REQUIRED_PERMISSIONS && !it.value)
permissionGranted = false
}
if (!permissionGranted) {
Toast.makeText(
baseContext,
"Permission request denied",
Toast.LENGTH_SHORT
).show()
} else {
startCamera()
}
}
lateinit var mask: Bitmap
lateinit var bitmap: Bitmap
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContentView(R.layout.activity_main)
ViewCompat.setOnApplyWindowInsetsListener(findViewById(R.id.main)) { v, insets ->
val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
insets
}
viewFinder = findViewById(R.id.viewFinder)
button = findViewById(R.id.image_capture_button)
greenScreenEffect = OverlayEffect(
PREVIEW or IMAGE_CAPTURE or VIDEO_CAPTURE,
5,
Handler(Looper.getMainLooper()),
) {}
button.setOnClickListener {
takePhoto()
}
if (allPermissionsGranted()) {
startCamera()
} else {
requestPermissions()
}
cameraExecutor = Executors.newSingleThreadExecutor()
}
private fun takePhoto() {
// Get a stable reference of the modifiable image capture use case
val imageCapture = imageCapture ?: return
// Create time stamped name and MediaStore entry.
val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US)
.format(System.currentTimeMillis())
val contentValues = ContentValues().apply {
put(MediaStore.MediaColumns.DISPLAY_NAME, name)
put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg")
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) {
put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX-Image")
}
}
// Create output options object which contains file + metadata
val outputOptions = ImageCapture.OutputFileOptions
.Builder(
contentResolver,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
contentValues
)
.build()
// Set up image capture listener, which is triggered after photo has
// been taken
imageCapture.takePicture(
outputOptions,
ContextCompat.getMainExecutor(this),
object : ImageCapture.OnImageSavedCallback {
override fun onError(exc: ImageCaptureException) {
Log.e(TAG, "Photo capture failed: ${exc.message}", exc)
}
override fun
onImageSaved(output: ImageCapture.OutputFileResults) {
val msg = "Photo capture succeeded: ${output.savedUri}"
cameraExecutor.shutdown()
Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
}
}
)
}
private fun startCamera() {
val aspectRatioStrategy = AspectRatioStrategy(
AspectRatio.RATIO_16_9, AspectRatioStrategy.FALLBACK_RULE_NONE
)
val resolutionSelector = ResolutionSelector.Builder()
.setAspectRatioStrategy(aspectRatioStrategy)
.build()
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
// Used to bind the lifecycle of cameras to the lifecycle owner
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
// Preview
val preview = Preview.Builder()
.setResolutionSelector(resolutionSelector)
.setTargetRotation(viewFinder.display.rotation)
.build()
.also {
it.surfaceProvider = viewFinder.surfaceProvider
}
// Make the preview view transparent
imageCapture = ImageCapture.Builder()
.setResolutionSelector(resolutionSelector)
.setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
.setTargetRotation(viewFinder.display.rotation)
.build()
val imageAnalysisUseCase = ImageAnalysis.Builder()
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build()
imageAnalysisUseCase.setAnalyzer(
ContextCompat.getMainExecutor(this),
SelfieSegmentationAnalyzer(),
)
val paint = Paint()
paint.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_IN)
paint.colorFilter = ColorMatrixColorFilter(
floatArrayOf(
0f, 0f, 0f, 1f, 0f,
0f, 0f, 0f, 1f, 0f,
0f, 0f, 0f, 1f, 0f,
0f, 0f, 0f, 1f, 0f,
),
)
greenScreenEffect.setOnDrawListener { frame ->
if (!::mask.isInitialized || !::bitmap.isInitialized) {
// Do not change the drawing if the frame doesn’t match the analysis
// result.
return@setOnDrawListener true
}
// Clear the previously drawn frame.
frame.overlayCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
// Draw the bitmap and mask, positioning the overlay in the bottom right corner.
// val rect = Rect(2 * bitmap.width, 0, 3 * bitmap.width, bitmap.height)
val rect = Rect(0, 0, frame.overlayCanvas.width, frame.overlayCanvas.height)
frame.overlayCanvas.drawBitmap(bitmap, null, rect, null)
frame.overlayCanvas.drawBitmap(mask, null, rect, paint)
true
}
// Select back camera as a default
val cameraSelector = CameraSelector.DEFAULT_FRONT_CAMERA
val useCaseGroupBuilder = UseCaseGroup.Builder()
.addUseCase(preview)
.addUseCase(imageCapture!!)
.addUseCase(imageAnalysisUseCase)
.addEffect(greenScreenEffect)
try {
// Unbind use cases before rebinding
cameraProvider.unbindAll()
// Bind use cases to camera
cameraProvider.bindToLifecycle(
this, cameraSelector, useCaseGroupBuilder.build()
)
} catch (exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}
}, ContextCompat.getMainExecutor(this))
}
private fun requestPermissions() {
activityResultLauncher.launch(REQUIRED_PERMISSIONS)
}
private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
ContextCompat.checkSelfPermission(
baseContext, it
) == PackageManager.PERMISSION_GRANTED
}
override fun onDestroy() {
super.onDestroy()
cameraExecutor.shutdown()
}
companion object {
private const val TAG = "CameraXApp"
private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS"
private val REQUIRED_PERMISSIONS =
mutableListOf(
Manifest.permission.CAMERA
).apply {
if (Build.VERSION.SDK_INT
// Get foreground probabilities for each pixel. Since ML Kit returns this
// in a byte buffer with each 4 bytes representing a float, convert it to
// a FloatBuffer for easier use.
val maskProbabilities = results.buffer.asFloatBuffer()
// Initialize our mask buffer and intermediate mask bitmap
if (!::maskBuffer.isInitialized) {
maskBitmap = createBitmap(
results.width,
results.height,
Bitmap.Config.ALPHA_8,
)
maskBuffer = ByteBuffer.allocateDirect(
maskBitmap.allocationByteCount,
)
}
maskBuffer.rewind()
// Convert the mask to an A8 image from the mask probabilities.
// We use a line buffer hear to optimize reads from the FloatBuffer.
val lineBuffer = FloatArray(results.width)
for (y in 0.. backgroundRemovalThreshold) {
255.toByte()
} else {
0
},
)
}
}
maskBuffer.rewind()
// Convert the mask buffer to a Bitmap so we can easily rotate and
// mirror.
maskBitmap.copyPixelsFromBuffer(maskBuffer)
val rotation = imageProxy.imageInfo.rotationDegrees
// Transformation matrix to mirror and rotate our bitmaps
val matrix = Matrix().apply {
// setScale(-1f, 1f)
// preRotate(-rotation.toFloat()) //here
}
// Mirror the ImageProxy
bitmap = Bitmap.createBitmap(
imageProxy.toBitmap(),
0,
0,
imageProxy.width,
imageProxy.height,
matrix,
false,
)
// Rotate and mirror the mask. When the rotation is 90 or 270, we need
// to swap the width and height.
val (rotWidth, rotHeight) = when (rotation) {
90, 270 ->
Pair(maskBitmap.height, maskBitmap.width)
else ->
Pair(maskBitmap.width, maskBitmap.height)
}
mask = Bitmap.createBitmap(
maskBitmap,
0,
0,
rotWidth,
rotHeight,
matrix
.apply { preRotate(-rotation.toFloat()) },
false,
)
}
.addOnCompleteListener {
// Final cleanup. Close imageProxy for next analysis frame.
imageProxy.close()
}
} else {
imageProxy.close()
}
}
}
}
Я попытался скрыть видимость предварительного просмотра, изменив альфа, изменяя цвет фона на прозрачный, устанавливая поставщика поверхности на нулевый или не устанавливая поставщика поверхности, но все это скрывает эффект наложения
I am using Selfie Segmentation to remove the background and using overlay effect to display it but the probelm is i need to somehow hide the preview and just display the OverlayEffect
[*]Clone this repo [*]Open in Android Studio [*]The preview is visible along with the Overlay Effect < /ol> Вот код < /p> [code]class MainActivity : AppCompatActivity() {
private var imageCapture: ImageCapture? = null private lateinit var cameraExecutor: ExecutorService
private lateinit var viewFinder: PreviewView private lateinit var button: Button
private lateinit var greenScreenEffect: OverlayEffect
private val activityResultLauncher = registerForActivityResult( ActivityResultContracts.RequestMultiplePermissions() ) { permissions -> // Handle Permission granted/rejected var permissionGranted = true permissions.entries.forEach { if (it.key in REQUIRED_PERMISSIONS && !it.value) permissionGranted = false } if (!permissionGranted) { Toast.makeText( baseContext, "Permission request denied", Toast.LENGTH_SHORT ).show() } else { startCamera() } }
lateinit var mask: Bitmap lateinit var bitmap: Bitmap
private fun takePhoto() { // Get a stable reference of the modifiable image capture use case val imageCapture = imageCapture ?: return
// Create time stamped name and MediaStore entry. val name = SimpleDateFormat(FILENAME_FORMAT, Locale.US) .format(System.currentTimeMillis()) val contentValues = ContentValues().apply { put(MediaStore.MediaColumns.DISPLAY_NAME, name) put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg") if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P) { put(MediaStore.Images.Media.RELATIVE_PATH, "Pictures/CameraX-Image") } }
// Create output options object which contains file + metadata val outputOptions = ImageCapture.OutputFileOptions .Builder( contentResolver, MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues ) .build()
// Set up image capture listener, which is triggered after photo has // been taken imageCapture.takePicture( outputOptions, ContextCompat.getMainExecutor(this), object : ImageCapture.OnImageSavedCallback { override fun onError(exc: ImageCaptureException) { Log.e(TAG, "Photo capture failed: ${exc.message}", exc) }
override fun onImageSaved(output: ImageCapture.OutputFileResults) { val msg = "Photo capture succeeded: ${output.savedUri}" cameraExecutor.shutdown() Toast.makeText(baseContext, msg, Toast.LENGTH_SHORT).show()
} } ) }
private fun startCamera() {
val aspectRatioStrategy = AspectRatioStrategy( AspectRatio.RATIO_16_9, AspectRatioStrategy.FALLBACK_RULE_NONE ) val resolutionSelector = ResolutionSelector.Builder() .setAspectRatioStrategy(aspectRatioStrategy) .build()
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({ // Used to bind the lifecycle of cameras to the lifecycle owner val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
greenScreenEffect.setOnDrawListener { frame -> if (!::mask.isInitialized || !::bitmap.isInitialized) { // Do not change the drawing if the frame doesn’t match the analysis // result. return@setOnDrawListener true }
// Clear the previously drawn frame. frame.overlayCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR)
// Draw the bitmap and mask, positioning the overlay in the bottom right corner. // val rect = Rect(2 * bitmap.width, 0, 3 * bitmap.width, bitmap.height) val rect = Rect(0, 0, frame.overlayCanvas.width, frame.overlayCanvas.height) frame.overlayCanvas.drawBitmap(bitmap, null, rect, null) frame.overlayCanvas.drawBitmap(mask, null, rect, paint)
true }
// Select back camera as a default val cameraSelector = CameraSelector.DEFAULT_FRONT_CAMERA
val useCaseGroupBuilder = UseCaseGroup.Builder() .addUseCase(preview) .addUseCase(imageCapture!!) .addUseCase(imageAnalysisUseCase) .addEffect(greenScreenEffect)
try { // Unbind use cases before rebinding cameraProvider.unbindAll()
// Bind use cases to camera cameraProvider.bindToLifecycle( this, cameraSelector, useCaseGroupBuilder.build() )
private fun requestPermissions() { activityResultLauncher.launch(REQUIRED_PERMISSIONS) }
private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all { ContextCompat.checkSelfPermission( baseContext, it ) == PackageManager.PERMISSION_GRANTED }
override fun onDestroy() { super.onDestroy() cameraExecutor.shutdown() }
companion object { private const val TAG = "CameraXApp" private const val FILENAME_FORMAT = "yyyy-MM-dd-HH-mm-ss-SSS" private val REQUIRED_PERMISSIONS = mutableListOf( Manifest.permission.CAMERA ).apply { if (Build.VERSION.SDK_INT // Get foreground probabilities for each pixel. Since ML Kit returns this // in a byte buffer with each 4 bytes representing a float, convert it to // a FloatBuffer for easier use. val maskProbabilities = results.buffer.asFloatBuffer()
// Convert the mask to an A8 image from the mask probabilities. // We use a line buffer hear to optimize reads from the FloatBuffer. val lineBuffer = FloatArray(results.width) for (y in 0.. backgroundRemovalThreshold) { 255.toByte() } else { 0 }, ) } } maskBuffer.rewind() // Convert the mask buffer to a Bitmap so we can easily rotate and // mirror. maskBitmap.copyPixelsFromBuffer(maskBuffer) val rotation = imageProxy.imageInfo.rotationDegrees // Transformation matrix to mirror and rotate our bitmaps val matrix = Matrix().apply { // setScale(-1f, 1f) // preRotate(-rotation.toFloat()) //here }
} [/code] Я попытался скрыть видимость предварительного просмотра, изменив альфа, изменяя цвет фона на прозрачный, устанавливая поставщика поверхности на нулевый или не устанавливая поставщика поверхности, но все это скрывает эффект наложения