|
@@ -1,358 +0,0 @@
|
|
|
-package com.ethan.psbc.ui.widgets
|
|
|
-
|
|
|
-import android.Manifest
|
|
|
-import android.content.Context
|
|
|
-import android.content.pm.PackageManager
|
|
|
-import android.graphics.*
|
|
|
-import android.os.Environment
|
|
|
-import android.util.AttributeSet
|
|
|
-import android.util.Log
|
|
|
-import android.view.SurfaceHolder
|
|
|
-import android.view.SurfaceView
|
|
|
-import android.widget.Toast
|
|
|
-import androidx.appcompat.app.AppCompatActivity
|
|
|
-import androidx.camera.core.*
|
|
|
-import androidx.camera.core.Camera
|
|
|
-import androidx.camera.lifecycle.ProcessCameraProvider
|
|
|
-import androidx.camera.view.PreviewView
|
|
|
-import androidx.core.app.ActivityCompat
|
|
|
-import androidx.core.content.ContextCompat
|
|
|
-import cn.face.sdk.FaceInterface
|
|
|
-import cn.face.sdk.FaceRecog
|
|
|
-import java.io.File
|
|
|
-import java.io.FileOutputStream
|
|
|
-import java.io.InputStream
|
|
|
-import java.io.OutputStream
|
|
|
-import java.nio.ByteBuffer
|
|
|
-import java.util.concurrent.ExecutorService
|
|
|
-import java.util.concurrent.Executors
|
|
|
-import kotlin.math.min
|
|
|
-
|
|
|
-
|
|
|
-class CameraScanView(mContext: Context, attrs:AttributeSet?, defStyleAttr:Int) : SurfaceView(mContext,attrs,defStyleAttr) {
|
|
|
-
|
|
|
- constructor(context: Context) : this(context, null)
|
|
|
- constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
|
|
|
-
|
|
|
- private val mLogger: org.slf4j.Logger = org.slf4j.LoggerFactory.getLogger(this.javaClass)
|
|
|
-
|
|
|
- private var holder:SurfaceHolder
|
|
|
-
|
|
|
- private var mSurfaceCallback= SurfaceCallback(mContext)
|
|
|
-
|
|
|
- private lateinit var faceConfigFile:File
|
|
|
-
|
|
|
- var faceHandleRet:Int=-1
|
|
|
-
|
|
|
- init {
|
|
|
- holder=getHolder()
|
|
|
- holder.addCallback(mSurfaceCallback)
|
|
|
-
|
|
|
- Log.d("demo","访问外部文件权限"+Environment.getExternalStorageState())
|
|
|
-
|
|
|
- try {
|
|
|
- Log.d("demo", "访问外部文件权限" + Environment.getExternalStorageState())
|
|
|
-
|
|
|
-
|
|
|
- val dirPath= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS).absolutePath+File.separator+"dd"
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- copyAssetsToMnt(mContext, "CWModels", dirPath)
|
|
|
-
|
|
|
- faceConfigFile = File(dirPath, "CWR_Config_1_1.xml")
|
|
|
-
|
|
|
- val licence = "MDQwNTE3NWQyNTkzNGM4MmQ3ZDk2MmQyM2UzODBhMmI1YjFjNjdjd2F1dGhvcml6Zd3n5+Xk5+fk/OXm5+fg5ef15efn5+Xk4Mfl4OXm5uvliObm6+Xm5uuR5ebm6+Xm5qLr5ebm6+Xmrubg5ufr5+v95+vn4OTk59Dk5ubr5+vn1uvn5+fm5Of+5g=="
|
|
|
- Log.d("demo", "初始化人脸识别SDK")
|
|
|
- FaceRecog.getInstance();
|
|
|
- faceHandleRet = FaceRecog.cwCreateRecogHandle(faceConfigFile.path, licence, 0)
|
|
|
- if (faceHandleRet >= FaceInterface.cw_errcode_t.CW_UNKNOWN_ERR) {
|
|
|
- faceHandleRet = -1
|
|
|
- } else {
|
|
|
- faceHandleRet = 0
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- }catch (e:Exception){
|
|
|
- Log.d("demo", "人脸SDK加载失败:"+e.message)
|
|
|
- faceHandleRet = -1
|
|
|
- }
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- fun deleteFolder(folder: File) {
|
|
|
- if (folder.isDirectory) {
|
|
|
- folder.listFiles()?.forEach {
|
|
|
- deleteFolder(it)
|
|
|
- }
|
|
|
- }
|
|
|
- folder.delete()
|
|
|
- }
|
|
|
- fun copyAssetsToMnt(context: Context, assetsPath: String, targetPath: String) {
|
|
|
- val assetManager = context.assets
|
|
|
- val files = assetManager.list(assetsPath) ?: emptyArray()
|
|
|
-
|
|
|
- if (files.isNotEmpty()) {
|
|
|
- val dir = File(targetPath, assetsPath)
|
|
|
- if (!dir.exists()) {
|
|
|
- dir.mkdirs()
|
|
|
- }
|
|
|
-
|
|
|
- for (fileName in files) {
|
|
|
- val subAssetPath = if (assetsPath.isEmpty()) fileName else "$assetsPath/$fileName"
|
|
|
- val subTargetPath = File(targetPath, subAssetPath)
|
|
|
-
|
|
|
- if (subTargetPath.isDirectory) {
|
|
|
- copyAssetsToMnt(context, subAssetPath, targetPath)
|
|
|
- } else {
|
|
|
- copyAssetFile(context, subAssetPath, subTargetPath.path)
|
|
|
- }
|
|
|
- }
|
|
|
- } else {
|
|
|
- // 如果是文件,直接复制
|
|
|
- copyAssetFile(context, assetsPath, targetPath)
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private fun copyAssetFile(context: Context, assetPath: String, targetPath: String) {
|
|
|
- val assetManager = context.assets
|
|
|
- val inputStream: InputStream = assetManager.open(assetPath)
|
|
|
- val outputFile = File(targetPath)
|
|
|
- if(outputFile.exists()){
|
|
|
- outputFile.delete()
|
|
|
- }
|
|
|
- val outputStream: OutputStream = FileOutputStream(outputFile,true)
|
|
|
-
|
|
|
- inputStream.use { input ->
|
|
|
- outputStream.use { output ->
|
|
|
- input.copyTo(output)
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- private var mWidth:Float=0.0f
|
|
|
- private var mHeight:Float=0.0f
|
|
|
- private var mCenterY:Float=0.0f
|
|
|
- private var mCenterX:Float=0.0f
|
|
|
- private var mRadius:Float=160f
|
|
|
-
|
|
|
- lateinit var mPreview:PreviewView
|
|
|
- override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
|
|
|
- super.onMeasure(widthMeasureSpec, heightMeasureSpec)
|
|
|
- mWidth = (measuredWidth - paddingLeft - paddingRight).toFloat()
|
|
|
- mHeight = (measuredHeight - paddingTop - paddingBottom).toFloat()
|
|
|
- mCenterX = mWidth / 2
|
|
|
- mCenterY = mHeight / 2
|
|
|
-
|
|
|
- val short = min(mWidth, mHeight)
|
|
|
- if (mRadius == 0.0f || mRadius * 2 > short) {
|
|
|
- mRadius = short / 2
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- mSurfaceCallback.mCenterX=this@CameraScanView.mCenterX
|
|
|
- mSurfaceCallback.mCenterY=this@CameraScanView.mCenterY
|
|
|
- mSurfaceCallback.mRadius=this@CameraScanView.mRadius
|
|
|
- mSurfaceCallback.mPreview=this@CameraScanView.mPreview
|
|
|
- mSurfaceCallback.faceConfigFile=this@CameraScanView.faceConfigFile
|
|
|
- mSurfaceCallback.faceHandleRet = this@CameraScanView.faceHandleRet
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- class SurfaceCallback() :SurfaceHolder.Callback{
|
|
|
-
|
|
|
- constructor(tContext:Context) : this() {
|
|
|
- this.tContext=tContext
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- private lateinit var cameraExecutor: ExecutorService
|
|
|
- private var cameraProvider: ProcessCameraProvider? = null
|
|
|
- private var preview: Preview? = null
|
|
|
- private var imageCamera: ImageCapture? = null
|
|
|
- private lateinit var camera: Camera //相机对象
|
|
|
- private lateinit var imageAnalysis: ImageAnalysis
|
|
|
- private lateinit var tContext: Context
|
|
|
-
|
|
|
- private val licence:String="MDQwNTE3NWQyNTkzNGM4MmQ3ZDk2MmQyM2UzODBhMmI1YjFjNjdjd2F1dGhvcml6Zd3n5+Xk5+fk/OXm5+fg5ef15efn5+Xk4Mfl4OXm5uvliObm6+Xm5uuR5ebm6+Xm5qLr5ebm6+Xmrubg5ufr5+v95+vn4OTk59Dk5ubr5+vn1uvn5+fm5Of+5g=="
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- var mCenterY:Float=0.0f
|
|
|
- var mCenterX:Float=0.0f
|
|
|
- var mRadius:Float=160f
|
|
|
- lateinit var mPreview:PreviewView
|
|
|
- var faceConfigFile:File?=null
|
|
|
- var faceHandleRet:Int=-1
|
|
|
-
|
|
|
-
|
|
|
- override fun surfaceCreated(holder: SurfaceHolder) {
|
|
|
-
|
|
|
-
|
|
|
- val canvas: Canvas =holder.lockCanvas()
|
|
|
- var backLayer=Paint();
|
|
|
- backLayer.run {
|
|
|
-
|
|
|
- style = Paint.Style.FILL
|
|
|
- isAntiAlias = true // 设置抗锯齿
|
|
|
- isDither = true // 设置抖动
|
|
|
-
|
|
|
- }
|
|
|
- backLayer.color=Color.TRANSPARENT
|
|
|
- var layerId=canvas.saveLayer(0.0F,0.0F,0.0F,0.0F,backLayer)
|
|
|
- canvas.drawColor(Color.TRANSPARENT)
|
|
|
- backLayer.xfermode = PorterDuffXfermode(PorterDuff.Mode.DST_ATOP) //这里选择DST_ATOP
|
|
|
- backLayer.color = Color.TRANSPARENT //颜色设置成透明
|
|
|
- canvas.drawCircle(mCenterX, mCenterY, mRadius, backLayer) //透明的圆形
|
|
|
- backLayer.xfermode = null
|
|
|
- canvas.restoreToCount(layerId)
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- val mCirclePaint= Paint()
|
|
|
- mCirclePaint.run {
|
|
|
- style = Paint.Style.STROKE
|
|
|
- isAntiAlias = true
|
|
|
- isDither = true
|
|
|
- strokeWidth =10f
|
|
|
- color = Color.WHITE
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- //绘制白色框,圆弧
|
|
|
- canvas.drawCircle(mCenterX, mCenterY, mRadius, mCirclePaint)
|
|
|
-
|
|
|
- holder.unlockCanvasAndPost(canvas);
|
|
|
-
|
|
|
-
|
|
|
- runCamera(tContext,holder,mPreview, faceHandleRet)
|
|
|
- }
|
|
|
-
|
|
|
- override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- override fun surfaceDestroyed(holder: SurfaceHolder) {
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- fun runCamera(context: Context,holder: SurfaceHolder,previewView: PreviewView?, handle:Int){
|
|
|
-
|
|
|
- if( PackageManager.PERMISSION_GRANTED!= ContextCompat.checkSelfPermission(context , Manifest.permission.CAMERA)){
|
|
|
- ActivityCompat.requestPermissions(context as AppCompatActivity, arrayOf(Manifest.permission.CAMERA),1)
|
|
|
- Toast.makeText(context as AppCompatActivity, "申请相机权限", Toast.LENGTH_SHORT).show()
|
|
|
- }else{
|
|
|
- Toast.makeText(context as AppCompatActivity, "已经拥有相机权限", Toast.LENGTH_SHORT).show()
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- val cameraSelector: CameraSelector = CameraSelector.Builder().requireLensFacing(CameraSelector.LENS_FACING_BACK).build()
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- cameraExecutor = Executors.newSingleThreadExecutor()
|
|
|
- val cameraProviderFuture = ProcessCameraProvider.getInstance(context)
|
|
|
- cameraProviderFuture.addListener({
|
|
|
- cameraProvider = cameraProviderFuture.get()//获取相机信息
|
|
|
-
|
|
|
- //预览配置
|
|
|
- preview = Preview.Builder()
|
|
|
- .build()
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- imageCamera = ImageCapture.Builder()
|
|
|
- .setCaptureMode(ImageCapture.CAPTURE_MODE_MINIMIZE_LATENCY)
|
|
|
- .build()
|
|
|
-
|
|
|
-
|
|
|
- imageAnalysis = ImageAnalysis.Builder()
|
|
|
- .setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
|
|
|
- .build()
|
|
|
-
|
|
|
-
|
|
|
- imageAnalysis.setAnalyzer(cameraExecutor) { imageProxy ->
|
|
|
- val planes: Array<ImageProxy.PlaneProxy> = imageProxy.planes
|
|
|
- val buffer: ByteBuffer = planes[0].buffer;
|
|
|
- val data: ByteArray = ByteArray(buffer.capacity())
|
|
|
- buffer.rewind()
|
|
|
- buffer.get(data)
|
|
|
-
|
|
|
-
|
|
|
- if(handle==-1){
|
|
|
- Log.d("demo", "SDK无法使用")
|
|
|
- }else{
|
|
|
- val iFeaLen:Int = FaceRecog.cwGetFeatureLength(handle)
|
|
|
- Log.d("demo", "获取到人脸特征长度${iFeaLen}")
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- imageProxy.close()
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- try {
|
|
|
- cameraProvider?.unbindAll()//先解绑所有用例
|
|
|
- camera = cameraProvider?.bindToLifecycle(
|
|
|
- context,
|
|
|
- cameraSelector,
|
|
|
- preview,
|
|
|
- imageCamera,
|
|
|
- imageAnalysis
|
|
|
- )!!//绑定用例
|
|
|
- } catch (_: Exception) {
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- preview?.setSurfaceProvider(previewView?.surfaceProvider)
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- }, ContextCompat.getMainExecutor(context))
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|