效果:
package com.piya; import static com.taobao.weex.WXEnvironment.getApplication; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.AsyncTask; import android.util.Log; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import org.OpenCV.android.OpenCVLoader; import org.opencv.core.Mat; import org.opencv.core.MatOfRect; import org.opencv.core.Rect; import org.opencv.objdetect.CascadeClassifier; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; import io.dcloud.feature.uniapp.annotation.UniJSMethod; import io.dcloud.feature.uniapp.bridge.UniJSCallback; import io.dcloud.feature.uniapp.common.UniModule; public class FaceDetectionHelper extends UniModule { private static final string TAG = "FaceDetectionHelper"; // 异步检测 @UniJSMethod(uiThread = true) public void testAsyncFunc(JSONObject options, final UniJSCallback callback) { // 加载OpenCV库 if (!OpenCVLoader.initDebug()) { Log.e(TAG, "OpenCV initialization failed"); if (callback != null) { JSONObject errorData = new JSONObject(); errorData.put("error", "OpenCV initialization failed"); callback.invoke(errorData); } return; } // 加载人脸检测器模型 CascadeClassifier cascadeClassifier = loadCascadeClassifier(); if (cascadeClassifier == null) { Log.e(TAG, "Cascade classifier loading failed"); if (callback != null) { JSONObject errorData = new JSONObject(); errorData.put("error", "Cascade classifier loading failed"); callback.invoke(errorData); } return; } // 获取图片URL String imageUrl = options.getString("imgUrl"); // 下载并处理图片 new AsyncTask() { @Override protected Bitmap doInBackground(String... params) { try { URL url = new URL(params[0]); HttpURLConnection connection = (HttpURLConnection) url.openConnection(); connection.setDoInput(true); connection.connect(); InputStream input = connection.getInputStream(); return BitmapFactory.decodeStream(input); } catch (Exception e) { Log.e(TAG, "Error downloading image: " + e.getMessage()); return null; } } @Override protected void onPostExecute(Bitmap bitmap) { if (bitmap != null) { // 在图像上执行人脸检测 JSONObject resultData = detectFaces(bitmap, cascadeClassifier); // 调用回调函数返回检测结果 if (callback != null) { callback.invoke(resultData); } } else { Log.e(TAG, "Failed to download image"); if (callback != null) { JSONObject errorData = new JSONObject(); errorData.put("error", "Failed to download image"); callback.invoke(errorData); } } } }.execute(imageUrl); } // 加载人脸检测器模型 private CascadeClassifier loadCascadeClassifier() { try { InputStream is = getApplication().getApplicationContext().getAssets().open("haarcascade_frontalface_alt.xml"); File cascadeFile = new File(getApplication().getApplicationContext().getCacheDir(), "haarcascade_frontalface_alt.xml"); FileOutputStream os = new FileOutputStream(cascadeFile); byte[] buffer = new byte[4096]; int bytesRead; while ((bytesRead = is.read(buffer)) != -1) { os.write(buffer, 0, bytesRead); } is.close(); os.close(); CascadeClassifier cascadeClassifier = new CascadeClassifier(cascadeFile.getAbsolutePath()); if (cascadeClassifier.empty()) { return null; } return cascadeClassifier; } catch (Exception e) { Log.e(TAG, "Error loading cascade classifier: " + e.getMessage()); return null; } } // 在图像上执行人脸检测 private JSONObject detectFaces(Bitmap bitmap, CascadeClassifier cascadeClassifier) { Mat mat = new Mat(); MatOfRect faces = new MatOfRect(); // 将Bitmap转换为OpenCV的Mat对象 org.opencv.android.Utils.bitmapToMat(bitmap, mat); // 执行人脸检测 cascadeClassifier.detectMultiScale(mat, faces); // 构建JSON对象来保存检测结果 JSONObject resultData = new JSONObject(); JSONArray facesArray = new JSONArray(); resultData.put("数量", faces.toArray().length); Rect[] rectsArray = faces.toArray(); for (Rect rect : rectsArray) { JSONObject faceData = new JSONObject(); faceData.put("height", rect.height); faceData.put("x", rect.x); faceData.put("width", rect.width); faceData.put("y", rect.y); facesArray.add(faceData); } resultData.put("位置",facesArray); JSONObject res = new JSONObject(); res.put("code","success"); res.put("data",resultData); return res; } }
uniapp代码
人脸检测异步 {{i.data}}// 获取 module var testModule = uni.requireNativePlugin("FaceDetectionHelper") const modal = uni.requireNativePlugin('modal'); export default { data(){ return{ imgUrls: [ { url: "https://img0.baidu.com/it/u=3389607,2584865022&fm=253&fmt=auto&app=138&f=PNG?w=449&h=645", data: null, }, { url: "https://img1.baidu.com/it/u=1751886178,1535140781&fm=253&fmt=auto&app=138&f=JPEG?w=297&h=384", data: null, }, { url: "https://img0.baidu.com/it/u=1112951416,2217244278&fm=253&fmt=auto&app=138&f=JPEG?w=600&h=304", data: null, }, { url: "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2Ffe639b21-0cde-4fdf-9818-b2442c3e023b%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1710902258&t=4028f29e7697388d94c3f72470cd5ef7", data: null, }, { url: "https://img0.baidu.com/it/u=2353660487,2578268887&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=666", data: null, }, { url: "https://img1.baidu.com/it/u=1241956916,3681734452&fm=253&fmt=auto&app=120&f=JPEG?w=400&h=560", data: null, }, { url: "https://n.sinaimg.cn/sinacn/w640h727/20180131/4c66-fyrcsrv9928989.jpg", data: null, }, { url: "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2Fc28a348f-6030-489e-bf16-3ba2995c80c0%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1710902571&t=95286d160dd05f21702a5f85c800edee", data: null, }, { url: "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F74d7df5d-8dfb-4a89-a12e-d433c4cc2473%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1710902571&t=7bf3f3944d14cc613582d80fa637698c", data: null, }, { url: "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fci.xiaohongshu.com%2Fc27943ba-fa83-42c9-b9e3-c901c532a750%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fci.xiaohongshu.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1710902570&t=36ffeb79e4f5ce047356519495025ea8", data: null, }, { url: "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F177c50eb-ff1e-41ba-a4b5-cdbd06dd5bfd%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1710902595&t=d0ed2efcaef4ff1a56c68c35d196588f", data: null, }, { url: "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F4d8d1eb8-f89a-42b8-b6ae-6375678e5b63%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1710902595&t=7bdd025d948698ef65117355e137d038", data: null, }, { url: "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F6baf9aef-1a72-46f1-b976-cebb6861b43c%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1710902595&t=b8867d83df6208f34784d330b333d814", data: null, }, { url: "https://img-user-qn.hudongba.com/upload/_oss/uePasteUpload/201809/1116/1536656165657.jpg", data: null, }, { url: "https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2Fc27fa638-a145-418e-95a8-61c397c104fe%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1710902632&t=f481b4f348fab8e15465efe30911b058", data: null, }, { url: "https://img1.baidu.com/it/u=2631529228,2871676583&fm=253&fmt=auto&app=138&f=PNG?w=400&h=558", data: null, }, { url: "https://img1.baidu.com/it/u=1740647370,3843349101&fm=253&fmt=auto&app=138&f=JPEG?w=499&h=333", data: null, }, ] } }, methods: { testAsyncFunc(imgUrl, index) { // 调用异步方法 testModule.testAsyncFunc({ 'imgUrl': imgUrl }, (ret) => { this.imgUrls[index].data = JSON.stringify(ret) modal.toast({ message: ret, duration: 1.5 }); }) }, // testSyncFunc() { // // 调用同步方法 // var ret = testModule.testSyncFunc({ // 'imgUrl': this.imgUrl // }) // modal.toast({ // message: ret, // duration: 1.5 // }); // } } }