英文:
Android transparent background shows as black in Photos
问题
以下是代码的翻译部分:
我正在使用以下代码从图像中删除背景,这确实有效,但当我将图像保存到设备时,您可以看到背景变成了黑色?
object BackgroundRemover {
private val segment: Segmenter
private var buffer = ByteBuffer.allocate(0)
private var width = 0
private var height = 0
init {
val segmentOptions = SelfieSegmenterOptions.Builder()
.setDetectorMode(SelfieSegmenterOptions.SINGLE_IMAGE_MODE)
.build()
segment = Segmentation.getClient(segmentOptions)
}
/**
* 处理图像以获取缓冲区和图像高度和宽度
* @param bitmap 要删除背景的位图。
* @param trimEmptyPart 如果为true,则在删除背景后将删除位图的空白部分。默认为false。
* @param listener 成功和失败回调的监听器。
**/
fun bitmapForProcessing(
bitmap: Bitmap,
trimEmptyPart: Boolean = false,
listener: OnBackgroundChangeListener
) {
// 生成位图的副本以防万一位图是不可变的。
val copyBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true)
val input = InputImage.fromBitmap(copyBitmap, 0)
segment.process(input)
.addOnSuccessListener { segmentationMask ->
buffer = segmentationMask.buffer
width = segmentationMask.width
height = segmentationMask.height
CoroutineScope(Dispatchers.IO).launch {
val time = measureTimeMillis {
val resultBitmap = if (trimEmptyPart) {
val bgRemovedBitmap = removeBackgroundFromImage(copyBitmap)
trim(bgRemovedBitmap)
} else {
removeBackgroundFromImage(copyBitmap)
}
withContext(Dispatchers.Main) {
listener.onSuccess(resultBitmap)
}
}
Log.e("TAG", "bitmapForProcessingTime: $time")
}
}
.addOnFailureListener { e ->
println("Image processing failed: $e")
listener.onFailed(e)
}
}
/**
* 将背景像素颜色更改为透明。
* */
private suspend fun removeBackgroundFromImage(
image: Bitmap
): Bitmap {
val bitmap = CoroutineScope(Dispatchers.IO).async {
for (y in 0 until height) {
for (x in 0 until width) {
val bgConfidence = ((1.0 - buffer.get()) * 255).toInt()
if (bgConfidence >= 100) {
image.setPixel(x, y, Color.TRANSPARENT)
}
}
}
buffer.rewind()
return@async image
}
return bitmap.await()
}
/**
* 裁剪位图的空白部分。
**/
private suspend fun trim(
bitmap: Bitmap
): Bitmap {
val result = CoroutineScope(Dispatchers.Default).async {
var firstX = 0
var firstY = 0
var lastX = bitmap.width
var lastY = bitmap.height
val pixels = IntArray(bitmap.width * bitmap.height)
bitmap.getPixels(pixels, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height)
loop@ for (x in 0 until bitmap.width) {
for (y in 0 until bitmap.height) {
if (pixels[x + y * bitmap.width] != Color.TRANSPARENT) {
firstX = x
break@loop
}
}
}
loop@ for (y in 0 until bitmap.height) {
for (x in firstX until bitmap.width) {
if (pixels[x + y * bitmap.width] != Color.TRANSPARENT) {
firstY = y
break@loop
}
}
}
loop@ for (x in bitmap.width - 1 downTo firstX) {
for (y in bitmap.height - 1 downTo firstY) {
if (pixels[x + y * bitmap.width] != Color.TRANSPARENT) {
lastX = x
break@loop
}
}
}
loop@ for (y in bitmap.height - 1 downTo firstY) {
for (x in bitmap.width - 1 downTo firstX) {
if (pixels[x + y * bitmap.width] != Color.TRANSPARENT) {
lastY = y
break@loop
}
}
}
return@async Bitmap.createBitmap(bitmap, firstX, firstY, lastX - firstX, lastY - firstY)
}
return result.await()
}
}
希望这有助于您理解代码。如果有任何问题,请随时提出。
英文:
I'm using the below code to remove the background from an image, which does work fine, but when i save the image to device, as you can see the background becomes black?
object BackgroundRemover {
private val segment: Segmenter
private var buffer = ByteBuffer.allocate(0)
private var width = 0
private var height = 0
init {
val segmentOptions = SelfieSegmenterOptions.Builder()
.setDetectorMode(SelfieSegmenterOptions.SINGLE_IMAGE_MODE)
.build()
segment = Segmentation.getClient(segmentOptions)
}
/**
* Process the image to get buffer and image height and width
* @param bitmap Bitmap which you want to remove background.
* @param trimEmptyPart After removing the background if its true it will remove the empty part of bitmap. by default its false.
* @param listener listener for success and failure callback.
**/
fun bitmapForProcessing(
bitmap: Bitmap,
trimEmptyPart: Boolean = false,
listener: OnBackgroundChangeListener
) {
//Generate a copy of bitmap just in case the if the bitmap is immutable.
val copyBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true)
val input = InputImage.fromBitmap(copyBitmap, 0)
segment.process(input)
.addOnSuccessListener { segmentationMask ->
buffer = segmentationMask.buffer
width = segmentationMask.width
height = segmentationMask.height
CoroutineScope(Dispatchers.IO).launch {
val time = measureTimeMillis {
val resultBitmap = if (trimEmptyPart) {
val bgRemovedBitmap = removeBackgroundFromImage(copyBitmap)
trim(bgRemovedBitmap)
} else {
removeBackgroundFromImage(copyBitmap)
}
withContext(Dispatchers.Main) {
listener.onSuccess(resultBitmap)
}
}
Log.e("TAG", "bitmapForProcessingTime: $time")
}
}
.addOnFailureListener { e ->
println("Image processing failed: $e")
listener.onFailed(e)
}
}
/**
* Change the background pixels color to transparent.
* */
private suspend fun removeBackgroundFromImage(
image: Bitmap
): Bitmap {
val bitmap = CoroutineScope(Dispatchers.IO).async {
for (y in 0 until height) {
for (x in 0 until width) {
val bgConfidence = ((1.0 - buffer.float) * 255).toInt()
if (bgConfidence >= 100) {
image.setPixel(x, y, Color.TRANSPARENT)
}
}
}
buffer.rewind()
return@async image
}
return bitmap.await()
}
/**
* trim the empty part of a bitmap.
**/
private suspend fun trim(
bitmap: Bitmap
): Bitmap {
val result = CoroutineScope(Dispatchers.Default).async {
var firstX = 0
var firstY = 0
var lastX = bitmap.width
var lastY = bitmap.height
val pixels = IntArray(bitmap.width * bitmap.height)
bitmap.getPixels(pixels, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height)
loop@ for (x in 0 until bitmap.width) {
for (y in 0 until bitmap.height) {
if (pixels[x + y * bitmap.width] != Color.TRANSPARENT) {
firstX = x
break@loop
}
}
}
loop@ for (y in 0 until bitmap.height) {
for (x in firstX until bitmap.width) {
if (pixels[x + y * bitmap.width] != Color.TRANSPARENT) {
firstY = y
break@loop
}
}
}
loop@ for (x in bitmap.width - 1 downTo firstX) {
for (y in bitmap.height - 1 downTo firstY) {
if (pixels[x + y * bitmap.width] != Color.TRANSPARENT) {
lastX = x
break@loop
}
}
}
loop@ for (y in bitmap.height - 1 downTo firstY) {
for (x in bitmap.width - 1 downTo firstX) {
if (pixels[x + y * bitmap.width] != Color.TRANSPARENT) {
lastY = y
break@loop
}
}
}
return@async Bitmap.createBitmap(bitmap, firstX, firstY, lastX - firstX, lastY - firstY)
}
return result.await()
}
答案1
得分: 1
看到图像背景为黑色的原因是因为图像未使用 alpha 通道。
val c : Canvas = Canvas(bm); // 位图
c.drawColor(0, Mode.CLEAR);
以 ARGB_8888 模式创建的位图支持透明度。
将此方法更新为以下内容。
private suspend fun removeBackgroundFromImage(
image: Bitmap
): Bitmap {
val bitmap = CoroutineScope(Dispatchers.IO).async {
for (y in 0 until height) {
for (x in 0 until width) {
val bgConfidence = ((1.0 - buffer.float) * 255).toInt()
if (bgConfidence >= 100) {
image.setHasAlpha(true)
image.setPixel(x, y, Color.TRANSPARENT)
}
}
}
buffer.rewind()
return@async image
}
return bitmap.await()
}
我只是添加了 image.setHasAlpha(true)
。
setHasAlpha
告诉位图所有像素是否已知为不透明(false)或可能包含非不透明 alpha 值(true)。
注意,对于某些配置(如 RGB_565),此调用会被忽略,因为它不支持每像素 alpha 值。这是作为绘图提示,因为在某些情况下,已知为不透明的位图可以采用比可能具有不透明像素 alpha 值更快的绘制方式。
英文:
The reason you see black in the background of your image is because your image is not using the alpha channel.
val c : Canvas = Canvas(bm); // bitmap
c.drawColor(0, Mode.CLEAR);
Bitmap created in mode ARGB_8888 supports transparency
Update this method like this.
private suspend fun removeBackgroundFromImage(
image: Bitmap
): Bitmap {
val bitmap = CoroutineScope(Dispatchers.IO).async {
for (y in 0 until height) {
for (x in 0 until width) {
val bgConfidence = ((1.0 - buffer.float) * 255).toInt()
if (bgConfidence >= 100) {
image.setHasAlpha(true)
image.setPixel(x, y, Color.TRANSPARENT)
}
}
}
buffer.rewind()
return@async image
}
return bitmap.await()
}
I just added image.setHasAlpha(true)
.
setHasAlpha
> Tell the bitmap if all of the pixels are known to be opaque (false) or
> if some of the pixels may contain non-opaque alpha values (true).
> Note, for some configs (e.g. RGB_565) this call is ignored, since it
> does not support per-pixel alpha values. This is meant as a drawing
> hint, as in some cases a bitmap that is known to be opaque can take a
> faster drawing case than one that may have non-opaque per-pixel alpha
> values.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论