OpenCV在Android上踩过的坑

最近一个新项目需要用的到人脸检测,想着之前见过opencv,就在网上找了配置教程,结果一直无法成功,鉴于网上的基本都是330版本,想着可能比较老,去官网下载了最新版(那个下载速度啊,真的是…)建议可以去github上面下载,我下的是3.4.0(为什么不是最新版呢?因为我下过了,不行,后面看到有人说不要下载最新版 ^ 笑哭^)
好了, 配置看上面的有人的文章就好了
万一有人的文章不进了呢,那我还是复制一下吧

  1. 导入modul
    就常规的import module啊 选择下载的文件里面sdk 文件夹下面的 java文件夹 导入就好了

  2. 修改配置文件
    修改导入module的build.gradle
    (1)将apply plugin: 'com.android.application’修改为apply plugin: ‘com.android.library’
    (2)将applicationId “org.opencv”"删去
    (3)将compileSdkVersion 、buildToolsVersion、minSdkVersion 、targetSdkVersion 属性值的设置与app对应的build.gradle文件的配置一致

  3. 增加依赖库
    这个都会吧 不用记了

  4. 最重要的来了
    将下载的文件夹里面的sdk → native → libs文件下的文件复制到项目的主module的lib文件夹下面(也不用全部放进去啦 要哪个就加哪个就好了)

然后就是在主module里面配置假如的so文件啦 这个也会吧

现在就可以验证了哦

 private BaseLoaderCallback loaderCallback = new BaseLoaderCallback(this) {
        @Override
        public void onManagerConnected(int status) {
            super.onManagerConnected(status);
            switch (status) {
                case LoaderCallbackInterface.SUCCESS:
                    try {
                        //加载人脸检测XML
                        //OpenCV的人脸模型文件: lbpcascade_frontalface_improved
                        InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface_improved);
                        File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
                        File cascadeFile = new File(cascadeDir, "lbpcascade_frontalface_improved.xml");
                        FileOutputStream fos = new FileOutputStream(cascadeFile);

                        byte[] buffer = new byte[4096];
                        int bytesRead;
                        while ((bytesRead = is.read(buffer)) != -1) {
                            fos.write(buffer, 0, bytesRead);
                        }
                        is.close();
                        fos.close();

                        cascadeClassifier = new CascadeClassifier(cascadeFile.getAbsolutePath());
                    } catch (FileNotFoundException e) {
                        e.printStackTrace();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    mVB.viewCamera.enableView();
                    break;
                default:
                    super.onManagerConnected(status);
                    break;
            }
        }
    };
    @Override
    protected void onResume() {
        super.onResume();
        if (OpenCVLoader.initDebug()) {
            loaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
        } else {
            OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_4_0, XmApplication.getInstance(), loaderCallback);
        }
    }
  1. 人脸检测

implements CameraBridgeViewBase.CvCameraViewListener2

   @Override
    public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
    

        mGrayImage = inputFrame.gray();
        mRgbaImage = inputFrame.rgba();
        int rotation = mVB.viewCamera.getDisplay().getRotation();

        //函数很简单,一个输入Mat,一个输出Mat,flipCode有三种情况,0为绕X轴翻转,大于的0代表绕Y轴翻转,-1代表即桡X轴也绕Y轴翻转。
        if (Constants.isCameraBack) {
            Core.flip(mRgbaImage, mRgbaImage, 1);
            Core.flip(mGrayImage, mGrayImage, 1);
        }

        MatOfRect faces = new MatOfRect();
        if (rotation == Surface.ROTATION_0) {
            Core.rotate(mGrayImage, mGray, Core.ROTATE_90_COUNTERCLOCKWISE);
            Core.rotate(mRgbaImage, mRgba, Core.ROTATE_90_COUNTERCLOCKWISE);
            if (cascadeClassifier != null) {
                cascadeClassifier.detectMultiScale(mGray, faces, 1.1, 2, 2, new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size());
            }
            org.opencv.core.Rect[] faceArray = faces.toArray();
            if (mCameraBitmap == null && faceArray.length >= 1) {
                //WillWolf 获取人脸Bitmap
                Mat tmMat = new Mat(mRgba, faceArray[0]);
                Bitmap bitmap = Bitmap.createBitmap(tmMat.cols(), tmMat.rows(), Bitmap.Config.ARGB_8888);
                Utils.matToBitmap(tmMat, bitmap);
                mCameraBitmap = bitmap;
            }
            Core.rotate(mRgba, mRgbaImage, Core.ROTATE_90_COUNTERCLOCKWISE);
        } else {
            if (cascadeClassifier != null) {
                cascadeClassifier.detectMultiScale(mGrayImage, faces, 1.1, 2, 2, new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size());
            }
            org.opencv.core.Rect[] faceArray = faces.toArray();
            for (int i = 0; i < faceArray.length; i++) {
                Imgproc.rectangle(mRgbaImage, faceArray[i].tl(), faceArray[i].br(), new Scalar(0, 255, 0, 255), 2);
            }
        }
        return mRgbaImage;
    }
    @Override
    public void onCameraViewStarted(int width, int height) {

        mRgbaImage = new Mat(width, height, CvType.CV_8UC4);
        mGrayImage = new Mat(height, width, CvType.CV_8UC4);
        mRgba = new Mat(width, height, CvType.CV_8UC4);
        mGray = new Mat(width, height, CvType.CV_8UC4);

        mAbsoluteFaceSize = (int) (height * 0.2);
    }
    @Override
    public void onCameraViewStopped() {
        /*
        mGray.release();
        mRgba.release();
         */

        mGrayImage.release();
        mRgbaImage.release();
        mRgba.release();
        mGray.release();
    }

补充

补充一下关于预览界面翻转的问题

其实就是修改opencv的一个库文件CameraBridgeViewBase.java 文件里面的deliverAndDrawFrame

protected void deliverAndDrawFrame(CvCameraViewFrame frame) {
        Mat modified;

        if (mListener != null) {
            modified = mListener.onCameraFrame(frame);
        } else {
            modified = frame.rgba();
        }

        boolean bmpValid = true;
        if (modified != null) {
            try {
                Utils.matToBitmap(modified, mCacheBitmap);
            } catch (Exception e) {
                Log.e(TAG, "Mat type: " + modified);
                Log.e(TAG, "Bitmap type: " + mCacheBitmap.getWidth() + "*" + mCacheBitmap.getHeight());
                Log.e(TAG, "Utils.matToBitmap() throws an exception: " + e.getMessage());
                bmpValid = false;
            }
        }

        if (bmpValid && mCacheBitmap != null) {
            Canvas canvas = getHolder().lockCanvas();
            if (canvas != null) {
                canvas.drawColor(0, android.graphics.PorterDuff.Mode.CLEAR);
/*
                //原来的方法
                if (BuildConfig.DEBUG)
                    Log.d(TAG, "mStretch value: " + mScale);

                if (mScale != 0) {
                    canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()),
                         new Rect((int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2),
                         (int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2),
                         (int)((canvas.getWidth() - mScale*mCacheBitmap.getWidth()) / 2 + mScale*mCacheBitmap.getWidth()),
                         (int)((canvas.getHeight() - mScale*mCacheBitmap.getHeight()) / 2 + mScale*mCacheBitmap.getHeight())), null);
                } else {
                     canvas.drawBitmap(mCacheBitmap, new Rect(0,0,mCacheBitmap.getWidth(), mCacheBitmap.getHeight()),
                         new Rect((canvas.getWidth() - mCacheBitmap.getWidth()) / 2,
                         (canvas.getHeight() - mCacheBitmap.getHeight()) / 2,
                         (canvas.getWidth() - mCacheBitmap.getWidth()) / 2 + mCacheBitmap.getWidth(),
                         (canvas.getHeight() - mCacheBitmap.getHeight()) / 2 + mCacheBitmap.getHeight()), null);
                }
*/

                //解决竖屏图像翻转问题
                Matrix matrix = new Matrix();
                if (getDisplay().getRotation() == Surface.ROTATION_0) {
                    matrix.preTranslate((canvas.getWidth() - mCacheBitmap.getWidth()) / 2, (canvas.getHeight() - mCacheBitmap.getHeight()) / 2);
                    matrix.postRotate(90f, (canvas.getWidth()) / 2, (canvas.getHeight()) / 2);
                    float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
                    matrix.postScale(scale, scale, canvas.getWidth() / 2, canvas.getHeight() / 2);
                    canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
                } else if (getDisplay().getRotation() == Surface.ROTATION_90) {
                    float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
                    matrix.postScale(scale, scale, canvas.getWidth() / 2, canvas.getHeight() / 2);
                    canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
                } else if (getDisplay().getRotation() == Surface.ROTATION_180) {
                    matrix.preTranslate((canvas.getWidth() - mCacheBitmap.getWidth()) / 2, (canvas.getHeight() - mCacheBitmap.getHeight()) / 2);
                    matrix.postRotate(270f, (canvas.getWidth()) / 2, (canvas.getHeight()) / 2);
                    float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
                    matrix.postScale(scale, scale, canvas.getWidth() / 2, canvas.getHeight() / 2);
                    canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
                } else if (getDisplay().getRotation() == Surface.ROTATION_270) {
                    matrix.postRotate(180f, (canvas.getWidth()) / 2, (canvas.getHeight()) / 2);
                    float scale = (float) canvas.getWidth() / (float) mCacheBitmap.getHeight();
                    matrix.postScale(scale, scale, canvas.getWidth() / 2, canvas.getHeight() / 2);
                    canvas.drawBitmap(mCacheBitmap, matrix, new Paint());
                }

                if (mFpsMeter != null) {
                    mFpsMeter.measure();
                    mFpsMeter.draw(canvas, 20, 30);
                }
                getHolder().unlockCanvasAndPost(canvas);
            }
        }
    }

但是该方法要是在AndroidManifest.xml里锁定竖屏


        <activity
            android:name=".ui.MainActivity"
            android:screenOrientation="portrait" />

最后补一句 解决竖屏的问题 也是我抄的 大佬在这里

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: OpenCV for Android 是一个开源的计算机视觉库,它提供了一系列用于计算机视觉应用的高效算法。OpenCV 是一个流行的计算机视觉库,它提供了许多用于图像和视频处理的功能。如果你想在 Android 应用程序中使用 OpenCV,你可以使用 OpenCV for Android。 在使用 OpenCV for Android 之前,你需要先安装 Android Studio 和 OpenCV for Android。安装完成后,你可以创建一个新的 Android 应用程序项目,并将 OpenCV for Android 添加到你的项目中。 要使用 OpenCV for Android,你需要在你的代码中添加 OpenCV 库的引用。你可以使用 OpenCV 提供的 Java API,或者使用 JNI 将 C++ 代码嵌入到你的应用程序中。 在使用 OpenCV for Android 时,你需要确保你的应用程序具有足够的权限,以便访问设备上的相机或图库等资源。你还需要测试你的应用程序,以确保它可以正确地使用 OpenCV 库来处理图像和视频数据。 总的来说,OpenCV for Android 是一个强大的工具,可以帮助你快速开发出高质量的 Android 应用程序,从而实现各种计算机视觉任务。 ### 回答2: OpenCV for Android是一个专门设计用于移动平台的图像处理库,它给Android系统提供了处理数字图像和视频的丰富功能和工具。OpenCV for Android可以作为一个Android应用中的库(.so文件),也可以通过Java API直接调用。它可以完成图像预处理、特征提取、物体检测、视频分析等多种图像处理功能。 OpenCV for Android用C++语言开发,但也提供了Java API,这使得开发者可以使用Java语言调用C++函数,而避免了直接使用NDK编写Native代码的复杂性。它的Java API设计良好,比较容易理解和使用。与此同时,OpenCV for Android提供了一个完整的示例应用程序,方便开发者学习和使用。 OpenCV for Android还具有高度的可裁剪性。开发者可以根据自己的需求,选择只使用OpenCV for Android库中的特定模块,而不必将整个库作为一个整体引入项目。这使得OpenCV for Android在应用中的集成更为灵活和轻量。 OpenCV for Android有一些特性,使其在处理大规模的图像和视频上更为高效和可靠。它使用了Java虚拟机 (JVM) 来缓存和管理内存,而OpenCV核心库会自动进行并行优化,以使程序在Android设备上运行得更快。此外,OpenCV for Android支持多种图像和视频格式,如JPG、PNG、BMP、AVI、MP4等。 总之,OpenCV for AndroidAndroid平台上提供了强大的图像和视频处理能力,为开发者带来了巨大的方便,并且可以快速集成到Android应用程序中。作为一个开源库,它的源代码和详细的文档也是公开可用的,这使得学习和使用OpenCV for Android更为容易和方便。 ### 回答3: OpenCV for Android是一款开源的计算机视觉库,它可以轻松地在Android平台上进行图像和视频处理。这个库具有广泛的功能,包括图像处理、目标识别、运动跟踪、面部识别和机器学习等等。 OpenCV for Android的使用非常简单和直接。可供选择的API包括Java API和C++ API。你可以使用Java API来编写易于理解和易于维护的代码,或者使用C++ API来获得更高的性能和更完整的OpenCV函数库。 OpenCV for Android也提供了丰富的开发工具。开发者可以使用Android Studio来编写和调试他们的OpenCV应用程序。同时,该库还提供了大量的示例代码和文档,以帮助开发者更快地开始开发他们的应用程序。 除此之外,OpenCV for Android还可以与其他库和工具进行集成,例如TensorFlow,Caffe和Git等。这些工具加强了OpenCV的功能,为开发者提供了更多的选择和灵活性。 总体而言,OpenCV for Android是一种强大而且易于使用的计算机视觉库,它适用于广泛的应用程序和项目。它的不断发展和完善也使其成为了学习计算机视觉技术的理想选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嘟嘟嘟~~~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值