找到一个免费的开源工具
https://github.com/FaceOnLive/Realtime-Background-Changer-SDK-Android
他是根据相机实时抠人像的,刚好在他的demo里面集成了相机,可以把背景图片改一下,,设置成蓝色红色就是证件照的拍摄了。(fotoapparat是项目中的相机sdk,,我运行不起来,库已经下载不下来了,所以我去GitHub直接拿了他的源码)
当然我看有些收费的证件照软件还支持传入照片变成证件照,,那么demo中的代码就要改一下了。如下:
package com.ttv.segmentdemo
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.os.Bundle
import android.util.Log
import android.widget.Button
import android.widget.ImageView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.ttv.segment.TTVException
import com.ttv.segment.TTVSeg
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.ByteArrayOutputStream
class MainActivity2 : AppCompatActivity() {
private var licenseValid = false
private var humanSegInited = false
private val imageView by lazy {
findViewById<ImageView>(R.id.image_view)
}
private val button by lazy {
findViewById<Button>(R.id.btn_start)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main2)
TTVSeg.createInstance(this)
val ret = TTVSeg.getInstance().setLicenseInfo("")
if(ret == 0) {
licenseValid = true
init()
}
button.setOnClickListener {
// 处理传入的图片
lifecycleScope.launch{
val bitmap = withContext(Dispatchers.IO){
processImage()
}
bitmap?.apply {
// 显示处理结果
imageView.setImageBitmap(this)
}
}
}
}
private fun init() {
if (!licenseValid) {
return
}
try {
if (TTVSeg.getInstance().create(this.applicationContext, 0, 0, 0) == 0) {
humanSegInited = true
return
}
} catch (e: TTVException) {
e.printStackTrace()
}
}
private suspend fun processImage():Bitmap? {
if (!humanSegInited) {
Toast.makeText(this, "人像分割未初始化", Toast.LENGTH_SHORT).show()
return null
}
val bitmap = BitmapFactory.decodeResource(resources, R.drawable.face2) // 替换为你的图片资源
val bitmapData = bitmapToNV21(bitmap)
val bgColor = intArrayOf(255, 255, 255) // 设置背景颜色
val iArr = IntArray(1)
// 执行抠图
try {
val segment: Bitmap = TTVSeg.getInstance().process(
bitmapData,
bitmap.width,
bitmap.height,
0, // 这里的 rotation 可根据需要调整
0,
bgColor,
null,
iArr
)
return segment
}catch(e : Error){
e.printStackTrace()
}
return null
}
fun compressBitmap(originalBitmap: Bitmap, quality: Int, width: Int, height:Int): Bitmap {
// 缩放 Bitmap
// 缩放 Bitmap
val resizedBitmap = Bitmap.createScaledBitmap(originalBitmap, width, height, true)
// 创建一个 ByteArrayOutputStream
// 创建一个 ByteArrayOutputStream
val outputStream = ByteArrayOutputStream()
// 压缩 Bitmap
// 压缩 Bitmap
resizedBitmap.compress(
Bitmap.CompressFormat.JPEG,
quality,
outputStream
) // quality 范围是 0 - 100
// 将压缩后的数据转换为 byte 数组
// 将压缩后的数据转换为 byte 数组
val byteArray = outputStream.toByteArray()
// 通过 byte 数组创建新的 Bitmap
// 通过 byte 数组创建新的 Bitmap
return BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)
}
fun bitmapToNV21(bitmap: Bitmap): ByteArray {
// 1. 将 Bitmap 转换为 YUV NV21 格式
val width = bitmap.width
val height = bitmap.height
val argb = IntArray(width * height)
bitmap.getPixels(argb, 0, width, 0, 0, width, height)
return argbToNv21(argb, width, height)
}
private fun argbToNv21(argb: IntArray, width: Int, height: Int): ByteArray {
val frameSize = width * height
var yIndex = 0
var uvIndex = frameSize
var index = 0
val nv21 = ByteArray(width * height * 3 / 2)
for (j in 0 until height) {
for (i in 0 until width) {
val R = argb[index] and 0xFF0000 shr 16
val G = argb[index] and 0x00FF00 shr 8
val B = argb[index] and 0x0000FF
val Y = (66 * R + 129 * G + 25 * B + 128 shr 8) + 16
val U = (-38 * R - 74 * G + 112 * B + 128 shr 8) + 128
val V = (112 * R - 94 * G - 18 * B + 128 shr 8) + 128
nv21[yIndex++] = (if (Y < 0) 0 else if (Y > 255) 255 else Y).toByte()
if (j % 2 == 0 && index % 2 == 0 && uvIndex < nv21.size - 2) {
nv21[uvIndex++] = (if (V < 0) 0 else if (V > 255) 255 else V).toByte()
nv21[uvIndex++] = (if (U < 0) 0 else if (U > 255) 255 else U).toByte()
}
++index
}
}
return nv21
}
}
可惜的是,yuvnv21这种方式摸透了,直接传普通bitmap的开放接口传数据会报错,,后续再摸摸。不然的话转来转去太耗时了
如果要做开发,传过去的图片最好先经过一次裁剪,,先让用户选择好大小,可以4:3裁剪可以16:9,当然1:1也可以。还有,我这里bgColor传的是白色,证件照嘛,改成蓝色或者红色应该问题不大,就不记录了
aar保存一下:
链接: https://pan.baidu.com/s/1IJ0P35TSnzMzABalC5I2ag 提取码: p5ik 复制这段内容后打开百度网盘手机App,操作更方便哦