| @@ -23,7 +23,6 @@ import com.aispeech.nativedemo.entity.PersonInfo; | |||||
| import com.aispeech.nativedemo.entity.Stranger; | import com.aispeech.nativedemo.entity.Stranger; | ||||
| import com.aispeech.nativedemo.log.Logger; | import com.aispeech.nativedemo.log.Logger; | ||||
| import com.aispeech.nativedemo.network.ws.MessageUtils; | import com.aispeech.nativedemo.network.ws.MessageUtils; | ||||
| import com.aispeech.nativedemo.tengine.TEngineFaceCheckManager; | |||||
| import com.aispeech.nativedemo.utils.CommandExecution; | import com.aispeech.nativedemo.utils.CommandExecution; | ||||
| import com.aispeech.nativedemo.utils.HttpUtil; | import com.aispeech.nativedemo.utils.HttpUtil; | ||||
| import com.aispeech.nativedemo.widget.CameraTextureView; | import com.aispeech.nativedemo.widget.CameraTextureView; | ||||
| @@ -37,7 +36,6 @@ import com.shareopen.library.helper.StatusUtils; | |||||
| import org.json.JSONObject; | import org.json.JSONObject; | ||||
| import org.json.JSONTokener; | import org.json.JSONTokener; | ||||
| import java.io.IOException; | |||||
| import java.lang.ref.WeakReference; | import java.lang.ref.WeakReference; | ||||
| import java.text.SimpleDateFormat; | import java.text.SimpleDateFormat; | ||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||
| @@ -3,7 +3,7 @@ package com.aispeech.nativedemo.tengine; | |||||
| import static android.media.ExifInterface.ORIENTATION_ROTATE_270; | import static android.media.ExifInterface.ORIENTATION_ROTATE_270; | ||||
| import static android.media.ExifInterface.ORIENTATION_ROTATE_90; | import static android.media.ExifInterface.ORIENTATION_ROTATE_90; | ||||
| import static com.aispeech.nativedemo.tengine.TEngineFaceCheckManager.LOG_TAG; | |||||
| import static com.aispeech.nativedemo.tengine.TEngine2FaceCheckManager.LOG_TAG; | |||||
| import android.content.Context; | import android.content.Context; | ||||
| import android.graphics.Bitmap; | import android.graphics.Bitmap; | ||||
| @@ -2,6 +2,7 @@ package com.aispeech.nativedemo.tengine | |||||
| import android.app.Activity | import android.app.Activity | ||||
| import android.graphics.Bitmap | import android.graphics.Bitmap | ||||
| import android.graphics.Rect | |||||
| import android.util.Log | import android.util.Log | ||||
| import com.aispeech.nativedemo.MainActivity | import com.aispeech.nativedemo.MainActivity | ||||
| import com.aispeech.nativedemo.asr.observer.DuiMessageObserver | import com.aispeech.nativedemo.asr.observer.DuiMessageObserver | ||||
| @@ -13,13 +14,16 @@ import com.aispeech.nativedemo.log.Logger | |||||
| import com.aispeech.nativedemo.utils.Utils | import com.aispeech.nativedemo.utils.Utils | ||||
| import com.lenovo.lefacecamerademo.ConfigClass.PROGRAM_ROOT_PATH | import com.lenovo.lefacecamerademo.ConfigClass.PROGRAM_ROOT_PATH | ||||
| import com.lenovo.lefacesdk.MultiAtt | import com.lenovo.lefacesdk.MultiAtt | ||||
| import com.shareopen.library.MVVM.application.AppContext | |||||
| import com.shareopen.library.helper.LogUtils | import com.shareopen.library.helper.LogUtils | ||||
| import com.tenginekit.engine.core.ImageConfig | |||||
| import com.tenginekit.engine.core.SdkConfig | |||||
| import com.tenginekit.engine.core.TengineKitSdk | |||||
| import com.tenginekit.engine.face.Face | |||||
| import com.tenginekit.engine.face.FaceConfig | |||||
| import com.tenginekit.AndroidConfig | |||||
| import com.tenginekit.KitCore | |||||
| import com.tenginekit.face.Face | |||||
| import com.tenginekit.face.FaceDetectInfo | |||||
| import com.tenginekit.face.FaceLandmarkInfo | |||||
| import com.tenginekit.model.TenginekitPoint | |||||
| import java.io.File | import java.io.File | ||||
| import java.nio.ByteBuffer | |||||
| import java.util.concurrent.ArrayBlockingQueue | import java.util.concurrent.ArrayBlockingQueue | ||||
| import java.util.concurrent.ConcurrentLinkedQueue | import java.util.concurrent.ConcurrentLinkedQueue | ||||
| @@ -28,7 +32,7 @@ class TEngineFaceCheckManager : FaceCheckInterface { | |||||
| companion object { | companion object { | ||||
| val instance by lazy (LazyThreadSafetyMode.SYNCHRONIZED){ | val instance by lazy (LazyThreadSafetyMode.SYNCHRONIZED){ | ||||
| TEngineFaceCheckManager() | |||||
| TEngine2FaceCheckManager() | |||||
| } | } | ||||
| const val LOG_TAG = "TengineKitApp" | const val LOG_TAG = "TengineKitApp" | ||||
| } | } | ||||
| @@ -39,12 +43,12 @@ class TEngineFaceCheckManager : FaceCheckInterface { | |||||
| @Volatile | @Volatile | ||||
| var faceCount = 0 | var faceCount = 0 | ||||
| var faceQueue = ArrayBlockingQueue<PersonInfo>(10) | var faceQueue = ArrayBlockingQueue<PersonInfo>(10) | ||||
| var faceListInVad = ConcurrentLinkedQueue<Face?>() | |||||
| var faceListInVad = ConcurrentLinkedQueue<FaceLandmarkInfo?>() | |||||
| var faceStrListInVad = ConcurrentLinkedQueue<String>() | var faceStrListInVad = ConcurrentLinkedQueue<String>() | ||||
| var faceRectListInVad = ConcurrentLinkedQueue<MultiAtt>() | var faceRectListInVad = ConcurrentLinkedQueue<MultiAtt>() | ||||
| var faceListCloseInVad = ConcurrentLinkedQueue<Face?>() | |||||
| var faceListCloseInVad = ConcurrentLinkedQueue<FaceLandmarkInfo?>() | |||||
| var faceStrListCloseInVad = ConcurrentLinkedQueue<String>() | var faceStrListCloseInVad = ConcurrentLinkedQueue<String>() | ||||
| var faceRectListCloseInVad = ConcurrentLinkedQueue<MultiAtt>() | var faceRectListCloseInVad = ConcurrentLinkedQueue<MultiAtt>() | ||||
| @@ -64,7 +68,18 @@ class TEngineFaceCheckManager : FaceCheckInterface { | |||||
| override fun init() { | override fun init() { | ||||
| Log.i(LOG_TAG, "start init") | Log.i(LOG_TAG, "start init") | ||||
| copyModel(MainActivity.instance) | |||||
| /** | |||||
| * 初始化 | |||||
| * */ | |||||
| KitCore.init( | |||||
| AppContext.getInstance(), | |||||
| AndroidConfig | |||||
| .create() | |||||
| .setNormalMode() | |||||
| .setDefaultFunc() | |||||
| .setInputImageFormat(AndroidConfig.ImageFormat.RGBA)) | |||||
| // .setInputImageSize(Image_w, Image_h) | |||||
| // .setOutputImageSize(Image_w as Int, Image_h as Int) | |||||
| Log.i(LOG_TAG, "init Success") | Log.i(LOG_TAG, "init Success") | ||||
| } | } | ||||
| @@ -77,11 +92,11 @@ class TEngineFaceCheckManager : FaceCheckInterface { | |||||
| override fun copyFinish() { | override fun copyFinish() { | ||||
| Log.i(LOG_TAG, "copyModel Success") | Log.i(LOG_TAG, "copyModel Success") | ||||
| //modelCopyFinished = true | //modelCopyFinished = true | ||||
| val sdkConfig = SdkConfig() | |||||
| sdkConfig.setAllowReport(false) | |||||
| //TengineKitSdk.getInstance().initSdk(PROGRAM_ROOT_PATH, sdkConfig, AppContext.getInstance()) | |||||
| TengineKitSdk.getInstance().initSdk(activity.externalCacheDir!!.absolutePath, sdkConfig, activity) | |||||
| TengineKitSdk.getInstance().initFaceDetect() | |||||
| // val sdkConfig = SdkConfig() | |||||
| // sdkConfig.setAllowReport(false) | |||||
| // //TengineKitSdk.getInstance().initSdk(PROGRAM_ROOT_PATH, sdkConfig, AppContext.getInstance()) | |||||
| // TengineKitSdk.getInstance().initSdk(activity.externalCacheDir!!.absolutePath, sdkConfig, activity) | |||||
| // TengineKitSdk.getInstance().initFaceDetect() | |||||
| } | } | ||||
| override fun copyFail() { | override fun copyFail() { | ||||
| @@ -179,53 +194,55 @@ class TEngineFaceCheckManager : FaceCheckInterface { | |||||
| return null | return null | ||||
| } | } | ||||
| fun doDetect(bitmap: Bitmap, personInfo: PersonInfo) : Face? { | |||||
| fun doDetect(bitmap: Bitmap, personInfo: PersonInfo) : FaceLandmarkInfo? { | |||||
| val start = System.currentTimeMillis() | val start = System.currentTimeMillis() | ||||
| var faceResult : Face? = null; | |||||
| var faceResult : FaceLandmarkInfo? = null; | |||||
| bitmap?.let { | bitmap?.let { | ||||
| val byte = ImageUtils.bitmap2RGB(bitmap) | |||||
| val config = FaceConfig().apply { | |||||
| detect = true | |||||
| landmark2d = true | |||||
| /** | |||||
| * 获取人脸信息 | |||||
| */ | |||||
| /** | |||||
| * 获取人脸信息 | |||||
| */ | |||||
| val data: ByteArray = bitmap2Bytes(bitmap) | |||||
| val faceDetect = Face.detect(data) | |||||
| var faceDetectInfos: List<FaceDetectInfo>? = ArrayList() | |||||
| var landmarkInfos: List<FaceLandmarkInfo> = ArrayList() | |||||
| if (faceDetect.faceCount > 0) { | |||||
| faceDetectInfos = faceDetect.detectInfos | |||||
| landmarkInfos = faceDetect.landmark2d() | |||||
| } | } | ||||
| val imageConfig = ImageConfig().apply { | |||||
| data = byte | |||||
| degree = 0 | |||||
| mirror = false | |||||
| height = it.height | |||||
| width = it.width | |||||
| format = ImageConfig.FaceImageFormat.RGB | |||||
| } | |||||
| val faces = TengineKitSdk.getInstance().detectFace(imageConfig, config) | |||||
| if (faces.isNotEmpty()) { | |||||
| Log.i(LOG_TAG, "faces length:" + faces.size + " duration " + (System.currentTimeMillis() - start)) | |||||
| Log.d("#####", "Face Num: " + faceDetectInfos!!.size) | |||||
| if (faceDetectInfos != null && faceDetectInfos.size > 0) { | |||||
| val face_landmarks: List<List<TenginekitPoint>> = ArrayList() | |||||
| for (i in faceDetectInfos.indices) { | |||||
| var rect: Rect? = Rect() | |||||
| rect = faceDetectInfos[i].asRect() | |||||
| Log.d( | |||||
| "#####", | |||||
| "mouseClose: " + landmarkInfos[i].mouseClose + "pitch: " + landmarkInfos[i].pitch + "yaw: " + landmarkInfos[i].yaw | |||||
| ) | |||||
| } | |||||
| } | } | ||||
| Log.i(LOG_TAG, "end detect") | Log.i(LOG_TAG, "end detect") | ||||
| val sb = StringBuilder() | val sb = StringBuilder() | ||||
| if (faces != null) { | |||||
| LogUtils.e("access123", "faces length " + faces.size) | |||||
| for (face in faces) { | |||||
| sb.append("· ").append("性别:").append(if (face.gender == 1) "女" else "男") | |||||
| .append("\n") | |||||
| sb.append("· ").append("年龄:").append(face.age).append("\n") | |||||
| // sb.append("· ").append("模糊度:").append(df.format(face.blurness.toDouble())) | |||||
| // .append("\n") | |||||
| // sb.append("· ").append("置信度:").append(df.format(face.confidence.toDouble())) | |||||
| // .append("\n") | |||||
| if (landmarkInfos != null) { | |||||
| LogUtils.e("access123", "faces length " + landmarkInfos.size) | |||||
| for (face in landmarkInfos) { | |||||
| var expression = "" | var expression = "" | ||||
| sb.append("· ").append("表情:").append(expression).append("\n") | sb.append("· ").append("表情:").append(expression).append("\n") | ||||
| sb.append("· ").append("眼部状态(左眼):").append(face.leftEyeClose) | sb.append("· ").append("眼部状态(左眼):").append(face.leftEyeClose) | ||||
| .append("\n") | .append("\n") | ||||
| sb.append("· ").append("眼部状态(右眼):").append(face.rightEyeClose) | sb.append("· ").append("眼部状态(右眼):").append(face.rightEyeClose) | ||||
| .append("\n") | .append("\n") | ||||
| sb.append("· ").append("嘴部状态:").append("闭嘴${(face.mouthClose*100).toInt()}%") | |||||
| sb.append("· ").append("嘴部状态:").append("闭嘴${(face.mouseClose*100).toInt()}%") | |||||
| .append("\n") | .append("\n") | ||||
| sb.append("· ").append("嘴部状态bigopen:").append("闭嘴${(face.mouthBigOpen*100).toInt()}%") | |||||
| sb.append("· ").append("嘴部状态bigopen:").append("闭嘴${(face.mouseOpenBig*100).toInt()}%") | |||||
| .append("\n") | .append("\n") | ||||
| sb.append("· ").append("3DPose:{pitch=").append(face.headX).append(",roll=") | |||||
| .append(face.headZ).append(",yaw=").append(face.headY).append("}\n") | |||||
| sb.append("· ").append("关键点个数:").append("" + face.landmark.size).append("\n") | |||||
| sb.append("· ").append("3DPose:{pitch=").append(face.pitch).append(",roll=") | |||||
| .append(face.roll).append(",yaw=").append(face.yaw).append("}\n") | |||||
| sb.append("· ").append("关键点个数:").append("" + face.landmarks.size).append("\n") | |||||
| sb.append("\n") | sb.append("\n") | ||||
| Log.e(LOG_TAG, "bitmapDetected: $sb") | Log.e(LOG_TAG, "bitmapDetected: $sb") | ||||
| faceResult = face | faceResult = face | ||||
| @@ -242,6 +259,14 @@ class TEngineFaceCheckManager : FaceCheckInterface { | |||||
| return faceResult; | return faceResult; | ||||
| } | } | ||||
| private fun bitmap2Bytes(image: Bitmap): ByteArray { | |||||
| // calculate how many bytes our image consists of | |||||
| val bytes = image.byteCount | |||||
| val buffer = ByteBuffer.allocate(bytes) // Create a new buffer | |||||
| image.copyPixelsToBuffer(buffer) // Move the byte data to the buffer | |||||
| return buffer.array() | |||||
| } | |||||
| private fun getEyeStatus(eyeType: Int): String? { | private fun getEyeStatus(eyeType: Int): String? { | ||||
| var reuslt = "" | var reuslt = "" | ||||
| when (eyeType) { | when (eyeType) { | ||||
| @@ -266,14 +291,14 @@ class TEngineFaceCheckManager : FaceCheckInterface { | |||||
| return result | return result | ||||
| } | } | ||||
| fun addFaceInVad(faceResult: Face?, faceStr: String?, faceMultiAtt: MultiAtt?) { | |||||
| fun addFaceInVad(faceResult: FaceLandmarkInfo?, faceStr: String?, faceMultiAtt: MultiAtt?) { | |||||
| faceListInVad.offer(faceResult) | faceListInVad.offer(faceResult) | ||||
| faceStrListInVad.offer(faceStr) | faceStrListInVad.offer(faceStr) | ||||
| faceRectListInVad.offer(faceMultiAtt) | faceRectListInVad.offer(faceMultiAtt) | ||||
| } | } | ||||
| fun addFaceInVadClose( | fun addFaceInVadClose( | ||||
| faceResult: Face?, | |||||
| faceResult: FaceLandmarkInfo?, | |||||
| faceStr: String?, | faceStr: String?, | ||||
| faceMultiAtt: MultiAtt? | faceMultiAtt: MultiAtt? | ||||
| ) { | ) { | ||||
| @@ -306,7 +331,9 @@ class TEngineFaceCheckManager : FaceCheckInterface { | |||||
| return checkSpeak(name, " BeforeASR ", faceListInVad) | return checkSpeak(name, " BeforeASR ", faceListInVad) | ||||
| } | } | ||||
| override fun onDestroy() {} | |||||
| override fun onDestroy() { | |||||
| KitCore.release() | |||||
| } | |||||
| override fun getCurrentSpeak(name: String, isClear: Boolean): Boolean { | override fun getCurrentSpeak(name: String, isClear: Boolean): Boolean { | ||||
| @@ -415,7 +442,7 @@ class TEngineFaceCheckManager : FaceCheckInterface { | |||||
| private fun checkAngle( | private fun checkAngle( | ||||
| faceList: ConcurrentLinkedQueue<Face?>, | |||||
| faceList: ConcurrentLinkedQueue<FaceLandmarkInfo?>, | |||||
| name: String | name: String | ||||
| ): Boolean { | ): Boolean { | ||||
| val count = faceList.size | val count = faceList.size | ||||
| @@ -425,12 +452,12 @@ class TEngineFaceCheckManager : FaceCheckInterface { | |||||
| overAngleCount++ | overAngleCount++ | ||||
| continue | continue | ||||
| } | } | ||||
| if (face.headY > 0.3f || face.headY < -0.3f) { | |||||
| if (face.yaw > 0.3f || face.yaw < -0.3f) { | |||||
| overAngleCount++ | overAngleCount++ | ||||
| } else { | } else { | ||||
| LogUtils.e( | LogUtils.e( | ||||
| "testtwoface", | "testtwoface", | ||||
| "face.yaw " + face.headY + " time " + DuiMessageObserver.mTime + " " + name | |||||
| "face.yaw " + face.yaw + " time " + DuiMessageObserver.mTime + " " + name | |||||
| ) | ) | ||||
| } | } | ||||
| } | } | ||||
| @@ -449,7 +476,7 @@ class TEngineFaceCheckManager : FaceCheckInterface { | |||||
| fun checkSpeak( | fun checkSpeak( | ||||
| name: String, | name: String, | ||||
| logTag: String, | logTag: String, | ||||
| faceList: ConcurrentLinkedQueue<Face?> | |||||
| faceList: ConcurrentLinkedQueue<FaceLandmarkInfo?> | |||||
| ): Boolean { | ): Boolean { | ||||
| val start = System.currentTimeMillis() | val start = System.currentTimeMillis() | ||||
| var isSpeak = false | var isSpeak = false | ||||
| @@ -464,16 +491,16 @@ class TEngineFaceCheckManager : FaceCheckInterface { | |||||
| if (face == null) { | if (face == null) { | ||||
| continue | continue | ||||
| } | } | ||||
| if (faceType >= 0 && (faceType - face.mouthClose) > 0.1f) { | |||||
| if (faceType >= 0 && (faceType - face.mouseClose) > 0.1f) { | |||||
| mouthChangeCount++ | mouthChangeCount++ | ||||
| } | } | ||||
| faceType = face.mouthClose | |||||
| if (face.mouthClose < 0.9f) { | |||||
| faceType = face.mouseClose | |||||
| if (face.mouseClose < 0.9f) { | |||||
| mouthOpen++ | mouthOpen++ | ||||
| } else { | } else { | ||||
| mouthClose++ | mouthClose++ | ||||
| } | } | ||||
| if (face.headX > 0.3f || face.headX < -0.3f) { | |||||
| if (face.pitch > 0.3f || face.pitch < -0.3f) { | |||||
| overAngleCount++ | overAngleCount++ | ||||
| } | } | ||||
| } | } | ||||
| @@ -1,8 +1,6 @@ | |||||
| package com.aispeech.nativedemo.tengine | package com.aispeech.nativedemo.tengine | ||||
| import android.content.res.AssetManager | import android.content.res.AssetManager | ||||
| import com.aispeech.nativedemo.tengine.ImageUtils.isFileExists | |||||
| import com.shareopen.library.helper.util.FileUtils | |||||
| import java.io.File | import java.io.File | ||||
| import java.io.File.separator | import java.io.File.separator | ||||
| import java.io.FileOutputStream | import java.io.FileOutputStream | ||||
| @@ -0,0 +1,511 @@ | |||||
| package com.aispeech.nativedemo.tengine2 | |||||
| import android.app.Activity | |||||
| import android.graphics.Bitmap | |||||
| import android.graphics.Rect | |||||
| import android.util.Log | |||||
| import com.aispeech.nativedemo.MainActivity | |||||
| import com.aispeech.nativedemo.asr.observer.DuiMessageObserver | |||||
| import com.aispeech.nativedemo.entity.PersonInfo | |||||
| import com.aispeech.nativedemo.face.AngleInfo | |||||
| import com.aispeech.nativedemo.face.FaceCheckInterface | |||||
| import com.aispeech.nativedemo.face.FaceManager | |||||
| import com.aispeech.nativedemo.log.Logger | |||||
| import com.aispeech.nativedemo.utils.Utils | |||||
| import com.lenovo.lefacecamerademo.ConfigClass.PROGRAM_ROOT_PATH | |||||
| import com.lenovo.lefacesdk.MultiAtt | |||||
| import com.shareopen.library.MVVM.application.AppContext | |||||
| import com.shareopen.library.helper.LogUtils | |||||
| import com.tenginekit.AndroidConfig | |||||
| import com.tenginekit.KitCore | |||||
| import com.tenginekit.face.Face | |||||
| import com.tenginekit.face.FaceDetectInfo | |||||
| import com.tenginekit.face.FaceLandmarkInfo | |||||
| import com.tenginekit.model.TenginekitPoint | |||||
| import java.io.File | |||||
| import java.nio.ByteBuffer | |||||
| import java.util.concurrent.ArrayBlockingQueue | |||||
| import java.util.concurrent.ConcurrentLinkedQueue | |||||
| class TEngine2FaceCheckManager : FaceCheckInterface { | |||||
| companion object { | |||||
| val instance by lazy (LazyThreadSafetyMode.SYNCHRONIZED){ | |||||
| TEngine2FaceCheckManager() | |||||
| } | |||||
| const val LOG_TAG = "TengineKitApp" | |||||
| } | |||||
| var hasInitKs = false | |||||
| private val TAG = "KSFaceCheckManager" | |||||
| var needKSCheck = false | |||||
| @Volatile | |||||
| var faceCount = 0 | |||||
| var faceQueue = ArrayBlockingQueue<PersonInfo>(10) | |||||
| var faceListInVad = ConcurrentLinkedQueue<FaceLandmarkInfo?>() | |||||
| var faceStrListInVad = ConcurrentLinkedQueue<String>() | |||||
| var faceRectListInVad = ConcurrentLinkedQueue<MultiAtt>() | |||||
| var faceListCloseInVad = ConcurrentLinkedQueue<FaceLandmarkInfo?>() | |||||
| var faceStrListCloseInVad = ConcurrentLinkedQueue<String>() | |||||
| var faceRectListCloseInVad = ConcurrentLinkedQueue<MultiAtt>() | |||||
| var needFaceCheck = true | |||||
| var needFaceAngleCheck = true | |||||
| // fun getInstance(): TEngineFaceCheckManager? { | |||||
| // if (TEngineFaceCheckManager.mInstance == null) { | |||||
| // synchronized(KSFaceCheckManager::class.java) { | |||||
| // if (TEngineFaceCheckManager.mInstance == null) { | |||||
| // TEngineFaceCheckManager.mInstance = TEngineFaceCheckManager() | |||||
| // } | |||||
| // } | |||||
| // } | |||||
| // return TEngineFaceCheckManager.mInstance | |||||
| // } | |||||
| override fun init() { | |||||
| Log.i(LOG_TAG, "start init") | |||||
| /** | |||||
| * 初始化 | |||||
| * */ | |||||
| KitCore.init( | |||||
| AppContext.getInstance(), | |||||
| AndroidConfig | |||||
| .create() | |||||
| .setNormalMode() | |||||
| .setDefaultFunc() | |||||
| .setInputImageFormat(AndroidConfig.ImageFormat.RGBA)) | |||||
| // .setInputImageSize(Image_w, Image_h) | |||||
| // .setOutputImageSize(Image_w as Int, Image_h as Int) | |||||
| Log.i(LOG_TAG, "init Success") | |||||
| } | |||||
| override fun bitmapDetected(bitmap: Bitmap?, personInfo: PersonInfo) { | |||||
| if (!needKSCheck || !hasInitKs) { | |||||
| return | |||||
| } | |||||
| if (personInfo.result == null || DuiMessageObserver.needPause) { | |||||
| return | |||||
| } | |||||
| val start = System.currentTimeMillis() | |||||
| val bitmap1 = Utils.CompressBmpByHD(bitmap, personInfo.result) | |||||
| ?: return | |||||
| personInfo.faceStr = "" | |||||
| val faceResult = doDetect(bitmap1, personInfo) | |||||
| if (faceResult != null) { | |||||
| addFaceInVad(faceResult, personInfo.faceStr, personInfo.result) | |||||
| } else { | |||||
| LogUtils.e( | |||||
| "testface", | |||||
| " faceData.faceResult == null $personInfo" | |||||
| ) | |||||
| } | |||||
| // faceQueue.offer(personInfo); | |||||
| // faceCount++; | |||||
| Log.e( | |||||
| "testtwo", | |||||
| "selectMan CompressBmpByHD duration " + (System.currentTimeMillis() - start) | |||||
| ) | |||||
| if (MainActivity.instance != null) { | |||||
| MainActivity.instance.setSettingLog(personInfo.faceStr) | |||||
| } | |||||
| } | |||||
| override fun bitmapDetectedClose(bitmap: Bitmap?, personInfo: PersonInfo) { | |||||
| if (!needKSCheck || !hasInitKs) { | |||||
| return | |||||
| } | |||||
| if (personInfo.result == null || DuiMessageObserver.needPause) { | |||||
| LogUtils.e("testtwo", " personInfo.result == null$personInfo") | |||||
| return | |||||
| } | |||||
| val start = System.currentTimeMillis() | |||||
| val bitmap1 = Utils.CompressBmpByHD(bitmap, personInfo.result) | |||||
| ?: return | |||||
| personInfo.faceStr = "" | |||||
| val faceResult = doDetect(bitmap1, personInfo) | |||||
| val time = System.currentTimeMillis() | |||||
| if (faceResult != null) { | |||||
| addFaceInVadClose(faceResult, personInfo.faceStr, personInfo.result) | |||||
| } else { | |||||
| LogUtils.e( | |||||
| "testtwo", | |||||
| " faceData.faceResult == null $personInfo" | |||||
| ) | |||||
| val file: File = | |||||
| File(PROGRAM_ROOT_PATH + "/" + DuiMessageObserver.mTime + "_" + personInfo.faceWidth + "_" + time + "_" + "last.jpg") | |||||
| //BitmapUtil.saveBitmap(file.getAbsolutePath(), bitmap1); | |||||
| } | |||||
| // faceQueue.offer(personInfo); | |||||
| // faceCount++; | |||||
| Log.e("testtwo", "close man face width " + personInfo.faceWidth + " time " + time) | |||||
| Log.e( | |||||
| "testtwo", | |||||
| "close CompressBmpByHD duration " + (System.currentTimeMillis() - start) + " facestr " + personInfo.faceStr + " person " + personInfo + " time " + time | |||||
| ) | |||||
| if (MainActivity.instance != null) { | |||||
| MainActivity.instance.setSettingLogClose(personInfo.faceStr) | |||||
| } | |||||
| } | |||||
| override fun onVadBegin() { | |||||
| while (faceListInVad.size > 2) { | |||||
| faceListInVad.poll() | |||||
| } | |||||
| Log.e("testface", "before vad " + faceListInVad.size) | |||||
| } | |||||
| override fun setFaceCheck(faceCheck: Boolean, | |||||
| needMouthCheck: Boolean, | |||||
| needAngleCheck: Boolean) { | |||||
| needKSCheck = faceCheck | |||||
| needFaceCheck = needMouthCheck | |||||
| needFaceAngleCheck = needAngleCheck; | |||||
| Log.i(LOG_TAG, "setFaceCheck ") | |||||
| } | |||||
| override fun getAngle(bitmap: Bitmap?, personInfo: PersonInfo?): AngleInfo? { | |||||
| return null | |||||
| } | |||||
| fun doDetect(bitmap: Bitmap, personInfo: PersonInfo) : FaceLandmarkInfo? { | |||||
| val start = System.currentTimeMillis() | |||||
| var faceResult : FaceLandmarkInfo? = null; | |||||
| bitmap?.let { | |||||
| /** | |||||
| * 获取人脸信息 | |||||
| */ | |||||
| /** | |||||
| * 获取人脸信息 | |||||
| */ | |||||
| val data: ByteArray = bitmap2Bytes(bitmap) | |||||
| val faceDetect = Face.detect(data) | |||||
| var faceDetectInfos: List<FaceDetectInfo>? = ArrayList() | |||||
| var landmarkInfos: List<FaceLandmarkInfo> = ArrayList() | |||||
| if (faceDetect.faceCount > 0) { | |||||
| faceDetectInfos = faceDetect.detectInfos | |||||
| landmarkInfos = faceDetect.landmark2d() | |||||
| } | |||||
| Log.d("#####", "Face Num: " + faceDetectInfos!!.size) | |||||
| if (faceDetectInfos != null && faceDetectInfos.size > 0) { | |||||
| val face_landmarks: List<List<TenginekitPoint>> = ArrayList() | |||||
| for (i in faceDetectInfos.indices) { | |||||
| var rect: Rect? = Rect() | |||||
| rect = faceDetectInfos[i].asRect() | |||||
| Log.d( | |||||
| "#####", | |||||
| "mouseClose: " + landmarkInfos[i].mouseClose + "pitch: " + landmarkInfos[i].pitch + "yaw: " + landmarkInfos[i].yaw | |||||
| ) | |||||
| } | |||||
| } | |||||
| Log.i(LOG_TAG, "end detect") | |||||
| val sb = StringBuilder() | |||||
| if (landmarkInfos != null) { | |||||
| LogUtils.e("access123", "faces length " + landmarkInfos.size) | |||||
| for (face in landmarkInfos) { | |||||
| var expression = "" | |||||
| sb.append("· ").append("表情:").append(expression).append("\n") | |||||
| sb.append("· ").append("眼部状态(左眼):").append(face.leftEyeClose) | |||||
| .append("\n") | |||||
| sb.append("· ").append("眼部状态(右眼):").append(face.rightEyeClose) | |||||
| .append("\n") | |||||
| sb.append("· ").append("嘴部状态:").append("闭嘴${(face.mouseClose*100).toInt()}%") | |||||
| .append("\n") | |||||
| sb.append("· ").append("嘴部状态bigopen:").append("闭嘴${(face.mouseOpenBig*100).toInt()}%") | |||||
| .append("\n") | |||||
| sb.append("· ").append("3DPose:{pitch=").append(face.pitch).append(",roll=") | |||||
| .append(face.roll).append(",yaw=").append(face.yaw).append("}\n") | |||||
| sb.append("· ").append("关键点个数:").append("" + face.landmarks.size).append("\n") | |||||
| sb.append("\n") | |||||
| Log.e(LOG_TAG, "bitmapDetected: $sb") | |||||
| faceResult = face | |||||
| } | |||||
| } | |||||
| val faceStr = sb.toString() | |||||
| personInfo.faceStr = faceStr | |||||
| LogUtils.e("access123", "faceStr $faceStr") | |||||
| LogUtils.e( | |||||
| "testface", | |||||
| "face duration " + (System.currentTimeMillis() - start) + " lx x1 " + personInfo.result.fa_x1 + " lx y1 " + personInfo.result.fa_y1 + " lx w " + personInfo.result.fa_w + " lx h " + personInfo.result.fa_h | |||||
| ) | |||||
| } | |||||
| return faceResult; | |||||
| } | |||||
| private fun bitmap2Bytes(image: Bitmap): ByteArray { | |||||
| // calculate how many bytes our image consists of | |||||
| val bytes = image.byteCount | |||||
| val buffer = ByteBuffer.allocate(bytes) // Create a new buffer | |||||
| image.copyPixelsToBuffer(buffer) // Move the byte data to the buffer | |||||
| return buffer.array() | |||||
| } | |||||
| private fun getEyeStatus(eyeType: Int): String? { | |||||
| var reuslt = "" | |||||
| when (eyeType) { | |||||
| 0 -> reuslt = "不戴眼镜,并且睁着眼" | |||||
| 1 -> reuslt = "不戴眼镜,并且闭着眼" | |||||
| 2 -> reuslt = "戴着普通眼镜,并且睁着眼" | |||||
| 3 -> reuslt = "戴着普通眼镜,并且闭着眼" | |||||
| 4 -> reuslt = "戴着墨镜" | |||||
| 5 -> reuslt = "眼镜被遮挡" | |||||
| } | |||||
| return reuslt | |||||
| } | |||||
| private fun getMouthStatus(mouthStatus: Int): String? { | |||||
| var result = "" | |||||
| when (mouthStatus) { | |||||
| 0 -> result = "带着面具或者带着口罩" | |||||
| 1 -> result = "被其他东西遮挡着嘴巴" | |||||
| 2 -> result = "闭嘴状态" | |||||
| 3 -> result = "张嘴状态" | |||||
| } | |||||
| return result | |||||
| } | |||||
| fun addFaceInVad(faceResult: FaceLandmarkInfo?, faceStr: String?, faceMultiAtt: MultiAtt?) { | |||||
| faceListInVad.offer(faceResult) | |||||
| faceStrListInVad.offer(faceStr) | |||||
| faceRectListInVad.offer(faceMultiAtt) | |||||
| } | |||||
| fun addFaceInVadClose( | |||||
| faceResult: FaceLandmarkInfo?, | |||||
| faceStr: String?, | |||||
| faceMultiAtt: MultiAtt? | |||||
| ) { | |||||
| faceListCloseInVad.offer(faceResult) | |||||
| faceStrListCloseInVad.offer(faceStr) | |||||
| faceRectListCloseInVad.offer(faceMultiAtt) | |||||
| } | |||||
| override fun getCurrentSpeakBeforeASR(name: String): Boolean { | |||||
| if (!needKSCheck || !hasInitKs) { | |||||
| return true | |||||
| } | |||||
| if (!needFaceCheck) { | |||||
| return if (!needFaceAngleCheck) { | |||||
| true | |||||
| } else { | |||||
| checkAngle(faceListInVad, name) | |||||
| } | |||||
| } | |||||
| if (faceListInVad.size == 0) { | |||||
| Log.e("testface", "BeforeASR size 0 is speak false") | |||||
| return false | |||||
| } | |||||
| if (needFaceAngleCheck) { | |||||
| val isAngleOk = checkAngle(faceListInVad, name) | |||||
| if (!isAngleOk) { | |||||
| return false | |||||
| } | |||||
| } | |||||
| return checkSpeak(name, " BeforeASR ", faceListInVad) | |||||
| } | |||||
| override fun onDestroy() { | |||||
| KitCore.release() | |||||
| } | |||||
| override fun getCurrentSpeak(name: String, isClear: Boolean): Boolean { | |||||
| Log.e("testkd2", "FaceManager.needKSCheck " + needKSCheck) | |||||
| if (!needKSCheck || !hasInitKs) { | |||||
| return true | |||||
| } | |||||
| if (!needFaceCheck) { | |||||
| return if (!needFaceAngleCheck) { | |||||
| true | |||||
| } else { | |||||
| val isRightAngle = checkAngle(faceListInVad, name) | |||||
| faceListInVad.clear() | |||||
| faceStrListInVad.clear() | |||||
| faceRectListInVad.clear() | |||||
| isRightAngle | |||||
| } | |||||
| } | |||||
| if (faceListInVad.size == 0) { | |||||
| Log.e("testface2", "close size 0 is speak false") | |||||
| return false | |||||
| } | |||||
| if (needFaceAngleCheck) { | |||||
| val isAngleOk = checkAngle(faceListInVad, name) | |||||
| Log.e("testtwoface", "$name isAngleOk $isAngleOk") | |||||
| if (!isAngleOk) { | |||||
| faceListInVad.clear() | |||||
| faceStrListInVad.clear() | |||||
| faceRectListInVad.clear() | |||||
| return false | |||||
| } | |||||
| } | |||||
| //needPause = true; | |||||
| val start = System.currentTimeMillis() | |||||
| //if (FaceManager.faceCount == 1 && faceListInVad.size() < 20) | |||||
| run {} | |||||
| // while (FaceManager.faceCount != 0) { | |||||
| // try { | |||||
| // Thread.sleep(20); | |||||
| // } catch (InterruptedException e) { | |||||
| // throw new RuntimeException(e); | |||||
| // } | |||||
| // } | |||||
| val isSpeak = checkSpeak(name, "closeMan", faceListInVad) | |||||
| if (!isSpeak) { | |||||
| } | |||||
| faceListInVad.clear() | |||||
| faceStrListInVad.clear() | |||||
| faceRectListInVad.clear() | |||||
| return isSpeak | |||||
| } | |||||
| override fun getCurrentCloseSpeak(closeName: String, isClear: Boolean): Boolean { | |||||
| if (!FaceManager.needKSCheck || !hasInitKs) { | |||||
| return true | |||||
| } | |||||
| if (!needFaceCheck) { | |||||
| return if (!needFaceAngleCheck) { | |||||
| true | |||||
| } else { | |||||
| val isRightAngle = checkAngle( | |||||
| faceListCloseInVad, | |||||
| "closeName-$closeName" | |||||
| ) | |||||
| faceListCloseInVad.clear() | |||||
| faceStrListCloseInVad.clear() | |||||
| faceRectListCloseInVad.clear() | |||||
| isRightAngle | |||||
| } | |||||
| } | |||||
| if (faceListCloseInVad.size == 0) { | |||||
| Log.e("testface", "size 0 is speak false") | |||||
| return false | |||||
| } | |||||
| if (needFaceAngleCheck) { | |||||
| val isAngleOk = checkAngle( | |||||
| faceListCloseInVad, | |||||
| "closeName-$closeName" | |||||
| ) | |||||
| if (!isAngleOk) { | |||||
| faceListCloseInVad.clear() | |||||
| faceStrListCloseInVad.clear() | |||||
| faceRectListCloseInVad.clear() | |||||
| return false | |||||
| } | |||||
| } | |||||
| //needPause = true; | |||||
| val start = System.currentTimeMillis() | |||||
| //if (FaceManager.faceCount == 1 && faceListInVad.size() < 20) | |||||
| run {} | |||||
| // while (FaceManager.faceCount != 0) { | |||||
| // try { | |||||
| // Thread.sleep(20); | |||||
| // } catch (InterruptedException e) { | |||||
| // throw new RuntimeException(e); | |||||
| // } | |||||
| // } | |||||
| val isSpeak = checkSpeak(closeName, "", faceListCloseInVad) | |||||
| if (!isSpeak) { | |||||
| } | |||||
| faceListCloseInVad.clear() | |||||
| faceStrListCloseInVad.clear() | |||||
| faceRectListCloseInVad.clear() | |||||
| return isSpeak | |||||
| } | |||||
| private fun checkAngle( | |||||
| faceList: ConcurrentLinkedQueue<FaceLandmarkInfo?>, | |||||
| name: String | |||||
| ): Boolean { | |||||
| val count = faceList.size | |||||
| var overAngleCount = 0 | |||||
| for (face in faceList) { | |||||
| if (face == null) { | |||||
| overAngleCount++ | |||||
| continue | |||||
| } | |||||
| if (face.yaw > 0.3f || face.yaw < -0.3f) { | |||||
| overAngleCount++ | |||||
| } else { | |||||
| LogUtils.e( | |||||
| "testtwoface", | |||||
| "face.yaw " + face.yaw + " time " + DuiMessageObserver.mTime + " " + name | |||||
| ) | |||||
| } | |||||
| } | |||||
| val rightAngleCount = count - overAngleCount | |||||
| LogUtils.e( | |||||
| "testtwoface", | |||||
| "face.yaw overAngleCount $overAngleCount count $count name $name" | |||||
| ) | |||||
| return if (count <= 12) { | |||||
| rightAngleCount * 10 > count | |||||
| } else { | |||||
| rightAngleCount * 3 > count | |||||
| } | |||||
| } | |||||
| fun checkSpeak( | |||||
| name: String, | |||||
| logTag: String, | |||||
| faceList: ConcurrentLinkedQueue<FaceLandmarkInfo?> | |||||
| ): Boolean { | |||||
| val start = System.currentTimeMillis() | |||||
| var isSpeak = false | |||||
| var mouthOpen = 0 | |||||
| var mouthClose = 0 | |||||
| var mouthOther = 0 | |||||
| var overAngleCount = 0 | |||||
| var faceType = -1f | |||||
| var mouthChangeCount = 0 | |||||
| val count = faceList.size | |||||
| for (face in faceList) { | |||||
| if (face == null) { | |||||
| continue | |||||
| } | |||||
| if (faceType >= 0 && (faceType - face.mouseClose) > 0.1f) { | |||||
| mouthChangeCount++ | |||||
| } | |||||
| faceType = face.mouseClose | |||||
| if (face.mouseClose < 0.9f) { | |||||
| mouthOpen++ | |||||
| } else { | |||||
| mouthClose++ | |||||
| } | |||||
| if (face.pitch > 0.3f || face.pitch < -0.3f) { | |||||
| overAngleCount++ | |||||
| } | |||||
| } | |||||
| if (faceList.size <= 8) { | |||||
| isSpeak = mouthChangeCount > 0 || overAngleCount > 0 | |||||
| } else if (overAngleCount > 0) { | |||||
| isSpeak = mouthChangeCount > 0 || overAngleCount * 16 >= count | |||||
| } else if (mouthOpen > 0 && mouthClose > 0 || mouthOpen > 0 && mouthOther > 0) { | |||||
| // || (mouthClose > 0 && mouthOther > 0) | |||||
| isSpeak = true | |||||
| } | |||||
| if (!isSpeak) { | |||||
| if (mouthChangeCount * 2 >= count) { | |||||
| isSpeak = true | |||||
| } else if (mouthOpen == 0 && count <= 20) { | |||||
| if (Math.abs(mouthClose - mouthOther) < 3 || mouthChangeCount > mouthClose || mouthChangeCount > mouthOther) { | |||||
| isSpeak = true | |||||
| } | |||||
| } | |||||
| } | |||||
| Logger.e("djASR-嘴型检测: " + logTag + name + " is speak " + isSpeak + " mouthOpen " + mouthOpen + " mouthClose " + mouthClose + " mouthOther " + mouthOther + " mouthChangeCount " + mouthChangeCount + " leftFaceSize " + faceCount + " overAngleCount " + overAngleCount + " time " + DuiMessageObserver.mTime) | |||||
| Log.e( | |||||
| "testface", | |||||
| logTag + name + " is speak " + isSpeak + " mouthOpen " + mouthOpen + " mouthClose " + mouthClose + " mouthOther " + mouthOther + " mouthChangeCount " + mouthChangeCount + " leftFaceSize " + faceCount + " overAngleCount " + overAngleCount + " time " + DuiMessageObserver.mTime + " duration " + (System.currentTimeMillis() - start) | |||||
| ) | |||||
| return isSpeak | |||||
| } | |||||
| } | |||||