我有以下Android代码:
class MainActivity : AppCompatActivity(), TtsSpeaker.Listener, PocketSphinx.Listener {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val ocvLoaded = OpenCVLoader.initDebug()
if (ocvLoaded) {
loadModel(this) // to be sure model in sot alled before initiation openCV
} else {
Log.d("openCV", "loader: ${OpenCVLoader.initDebug()}")
}
}
}
并使用以下人脸检测类:
package hasan.tts_mobile
import android.app.Activity
import android.graphics.Bitmap
import org.opencv.core.Mat
import org.opencv.core.MatOfRect
import org.opencv.core.Size
import org.opencv.imgproc.Imgproc
import org.opencv.objdetect.CascadeClassifier
import java.io.File
import org.opencv.core.CvType
import android.opengl.ETC1.getWidth
import android.opengl.ETC1.getHeight
object FaceDetection {
private val faceModel = "haarcascade_frontalface_default.xml" //lateinit var faceModel: String // = "haarcascade_frontalface_default.xml"
private lateinit var faceCascade: CascadeClassifier
fun loadModel(activity: Activity) {
println("started loading the model")
faceCascade = CascadeClassifier(File(activity.filesDir, "das").apply {
writeBytes(activity.assets.open(faceModel).readBytes())
}.path)
println("completed loading the model")
tts!!.say("I'm 100% ready!")
}
fun detectFaces(activity: Activity, image: Bitmap?): Long {
// bitmap
val matImage = Mat(image!!.height, image.width, CvType.CV_8UC1)
val bmpImage = image.copy(Bitmap.Config.ARGB_8888, true)
Utils.bitmapToMat(bmpImage, matImage)
val rectangles = MatOfRect() //RectVector() //MatOfRect()
val grayScaled = matImage .prepare()
// loadModel(activity)
faceCascade.detectMultiScale(
grayScaled, rectangles, 1.2, 10, 0,
Size(40.0, 40.0),
null)
return rectangles.size() as Long
}
private fun Mat.toGrayScale(): Mat =
if (channels() >= 3) Mat().apply {
Imgproc.cvtColor(
this@toGrayScale,
this,
Imgproc.COLOR_BGR2GRAY
)
}
else this
private fun Mat.prepare(): Mat {
val mat = toGrayScale()
Imgproc.equalizeHist(mat, mat)
return mat
}
}
使用以下代码从相机成功拍摄照片后调用人脸检测功能:
private fun startCamera() {
val fileName = System.currentTimeMillis().toString() + ".jpeg"
output = File(
this.getExternalFilesDir(Environment.DIRECTORY_PICTURES),
fileName
)
val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
outPutFileUri = this?.let { it1 ->
FileProvider.getUriForFile(
it1,
BuildConfig.APPLICATION_ID,
output!!
)
}
intent.putExtra(MediaStore.EXTRA_OUTPUT, outPutFileUri)
startActivityForResult(intent, REQUEST_IMAGE_CAPTURE)
}
@SuppressLint("MissingSuperCall")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == Activity.RESULT_OK) {
val bitmap = outPutFileUri?.let { getCapturedImage(it) }
imageView.setImageBitmap(bitmap)
FaceDetection.detectFaces(this, bitmap) // Calling facedetection
}
}
private fun getCapturedImage(selectedPhotoUri: Uri): Bitmap {
val bitmap = when {
Build.VERSION.SDK_INT < 28 -> MediaStore.Images.Media.getBitmap(
this.contentResolver,
selectedPhotoUri
)
else -> {
val source = ImageDecoder.createSource(this.contentResolver, selectedPhotoUri)
ImageDecoder.decodeBitmap(source)
}
}
return when (ExifInterface(contentResolver.run { openInputStream(selectedPhotoUri) }).getAttributeInt(
ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_UNDEFINED)) {
ExifInterface.ORIENTATION_ROTATE_90 -> Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, Matrix().apply { postRotate(90F) }, true)
ExifInterface.ORIENTATION_ROTATE_180 -> Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, Matrix().apply { postRotate(180F) }, true)
ExifInterface.ORIENTATION_ROTATE_270 -> Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, Matrix().apply { postRotate(270F) }, true)
else -> bitmap
}
}
我得到的完整错误是:
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: hasan.tts_mobile, PID: 14110
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=1, result=-1, data=Intent { }} to activity {hasan.tts_mobile/hasan.tts_mobile.MainActivity}: java.lang.NullPointerException: Attempt to read from field 'double org.opencv.core.Size.width' on a null object reference
at android.app.ActivityThread.deliverResults(ActivityThread.java:4845)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4886)
at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:51)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: java.lang.NullPointerException: Attempt to read from field 'double org.opencv.core.Size.width' on a null object reference
at org.opencv.objdetect.CascadeClassifier.detectMultiScale(CascadeClassifier.java:156)
at hasan.tts_mobile.FaceDetection.detectFaces(FaceDetection.kt:38)
at hasan.tts_mobile.MainActivity.onActivityResult(MainActivity.kt:173)
at android.app.Activity.dispatchActivityResult(Activity.java:8110)
at android.app.ActivityThread.deliverResults(ActivityThread.java:4838)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4886)
at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:51)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
I/Process: Sending signal. PID: 14110 SIG: 9
Process 14110 terminated.
我加
println("pic size: ${grayScaled.size()}")
println("faceCascade: ${faceCascade.originalWindowSize}")
前
faceCascade.detectMultiScale(
grayScaled, rectangles, 1.2, 10, 0,
Size(40.0, 40.0),
null)
并得到以下信息:
I/System.out: pic size: 960x1280
faceCascade: 24x24
D/AndroidRuntime: Shutting down VM
E/AndroidRuntime: FATAL EXCEPTION: main
Process: hasan.tts_mobile, PID: 15177
更新
看起来问题是我将 as 定义maxSize
为null
,它应该是Size()
或全尺寸为:Size(40.0, 40.0)
现在我将其更改为:
faceCascade.detectMultiScale(
grayScaled, rectangles, 1.1, 3, 0,
Size(30.0, 30.0), Size()
)
println("rectangles ${rectangles.size()}")
我没有挂起或崩溃,而是返回rectangles.size()
as :
I/System.out: pic size: 3264x2448
faceCascade: 24x24
I/System.out: rectangles 1x0
这是否意味着它没有检测到任何人脸,如果是,如何解决?