美文网首页
opencv cascade.xml在安卓APP中的使用

opencv cascade.xml在安卓APP中的使用

作者: Mr_Bluyee | 来源:发表于2018-07-05 20:31 被阅读23次

充电站项目mavic pro自动控制app源码
在上一篇文章中写了怎样训练出cascade.xml文件,这一篇讲解怎样在android app里使用级联分类器进行多目标检测——。

首先要做的是在app中导入opencv4android的SDK。opencv4android SDK

配置环境:OpenCV On Android环境配置指南

本项目采用动态链接库,免去安装额外的OpenCV Manager App。

图像处理与识别部分在src的application下的PictureHandle里。

使用步骤:

1.把cascade.xml文件放入res下的raw文件夹里。

2.在activity里加载opencv库:


@Override

    protected void onResume() {

        super.onResume();

        //load OpenCV engine and init OpenCV library

        if(!OpenCVLoader.initDebug()) {

            OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION, getApplicationContext(), mLoaderCallback);

            Log.d(TAG, "Internal OpenCV library not found. Using Opencv Manager for initialization");

        }else {

            Log.d(TAG, "OpenCV library found inside package. Using it!");

            mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);

        }

    }

3.设置链接到opencv库的回调函数mLoaderCallback。在该回调函数里,我们加载cascade.xml文件,并对CascadeClassifier做初始化:

    @Override
    public void onManagerConnected(int status) {
        switch (status) {
            case LoaderCallbackInterface.SUCCESS:
                isInit = true;
                try {
                    // load cascade file from application resources
                    InputStream is = context.getResources().openRawResource(R.raw.cascade1);
                    File cascade1Dir = context.getDir("cascade1", Context.MODE_PRIVATE);
                    mCascade1File = new File(cascade1Dir, "cascade1.xml");
                    FileOutputStream os = new FileOutputStream(mCascade1File);

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

                    // load cascade file from application resources
                    InputStream ise = context.getResources().openRawResource(R.raw.cascade2);
                    File cascade2Dir = context.getDir("cascade2", Context.MODE_PRIVATE);
                    mCascade2File = new File(cascade2Dir, "cascade2.xml");
                    FileOutputStream ose = new FileOutputStream(mCascade2File);

                    while ((bytesRead = ise.read(buffer)) != -1) {
                        ose.write(buffer, 0, bytesRead);
                    }

                    ise.close();
                    ose.close();

                    mJavaDetector1 = new CascadeClassifier(mCascade1File.getAbsolutePath());
                    if (mJavaDetector1.empty()) {
                        Log.e(TAG, "Failed to load cascade classifier");
                        mJavaDetector1 = null;
                    } else
                        Log.i(TAG, "Loaded cascade classifier from " + mCascade1File.getAbsolutePath());

                    mJavaDetector2 = new CascadeClassifier(mCascade2File.getAbsolutePath());
                    if (mJavaDetector2.empty()) {
                        Log.e(TAG, "Failed to load cascade classifier");
                        mJavaDetector2 = null;
                    } else {
                        Log.i(TAG, "Loaded cascade classifier from " + mCascade2File.getAbsolutePath());
                    }

                    cascade1Dir.delete();
                    cascade2Dir.delete();
                } catch (IOException e) {
                    e.printStackTrace();
                    Log.e(TAG, "Failed to load cascade. Exception thrown: " + e);
                }
                break;
            default:
                isInit = false;
                super.onManagerConnected(status);
                break;
        }
    }

4.新建的Picture_Detector1类。mavic pro的摄像头传回到app上的预览画面使用安卓texture,我们先从texture里取出一帧图片,保存到bitmap类的变量里。然后将bitmap转为opencv的mat类型数据,接着将图片转为灰度图像,传入detectMultiScale方法里检测目标。
下面是新建的Picture_Detector1类,开一个线程处理图像:

    public class Picture_Detector1 implements Runnable{
        private Bitmap bitmap;
        private Handler UIHandler;
        private Rect[] result;

        public void begin() {
            new Thread(this).start();
        }
        public Picture_Detector1(Bitmap bitmap,Handler UIHandler){
            this.bitmap = bitmap;
            this.UIHandler = UIHandler;
        }

        @Override
        public void run() {
            Mat srcimg = new Mat();
            Utils.bitmapToMat(bitmap, srcimg);
            Imgproc.cvtColor(srcimg, srcimg,Imgproc.COLOR_RGBA2GRAY);
            result = detector1(srcimg);
            Message msg = new Message();
            Bundle b = new Bundle();// 存放数据
            b.putSerializable("picturedetector1", result);
            msg.setData(b);
            UIHandler.sendMessage(msg);
        }
    }

图像处理函数为 result = detector1(srcimg);
函数代码如下:

    public Rect[] detector1(Mat srcimg) {
        if (mAbsoluteTargetSize == 0) {
            int height = srcimg.rows();
            if (Math.round(height * mRelativeTargetSize) > 0) {
                mAbsoluteTargetSize = Math.round(height * mRelativeTargetSize);
            }
        }
        MatOfRect targets = new MatOfRect();
        if (mDetectorType == JAVA_DETECTOR) {
            if (mJavaDetector1 != null)
                mJavaDetector1.detectMultiScale(srcimg, targets, 1.1, 6, 2, // TODO: objdetect.CV_HAAR_SCALE_IMAGE
                        new Size(mAbsoluteTargetSize, mAbsoluteTargetSize), new Size());
        }
        else {
            Log.e(TAG, "Detection method is not selected!");
        }
        return targets.toArray();
    }

CascadeClassifier为级联分类器检测类,使用Adaboost的方法,提取LBP\HOG\HAAR特征进行目标检测,加载traincascade进行训练的分类器。
detectMultiscale函数为多尺度多目标检测:
detectMultiScale能够实现多尺度检测,但多尺度检测是通过缩放图像来完成的。多尺度:通常搜索目标的模板尺寸大小是固定的,但是不同图片大小不同,所以目标对象的大小也是不定的,所以多尺度即不断缩放图片大小(缩放到与模板匹配),通过模板滑动窗函数搜索匹配;同一副图片可能在不同尺度下都得到匹配值,所以多尺度检测函数detectMultiscale是多尺度合并的结果。
多目标:通过检测符合模板匹配对象,可得到多个目标,均输出到objects向量里面。
detectMultiScale函数参数解释:
const Mat, —Mat类型的图像,待检测图片,一般为灰度图像加快检测速度。
Rect[],—检测得到的被检测物体的矩形框向量组;为输出量
doublescaleFactor, —图像缩放因子,必须大于1,表示在前后两次相继的扫描中,搜索窗口的比例系数。默认为1.1即每次搜索窗口依次扩大10%;一般设置为1.1 。
intminNeighbors,—构成检测目标的相邻矩形的最小个数(默认为3个)。如果组成检测目标的小矩形的个数和小于 min_neighbors - 1 都会被排除。
如果min_neighbors 为 0, 则函数不做任何操作就返回所有的被检候选矩形框,
这种设定值一般用在用户自定义对检测结果的组合程序上。
int flags, —要么使用默认值,要么使用CV_HAAR_DO_CANNY_PRUNING,如果设置为CV_HAAR_DO_CANNY_PRUNING,那么函数将会使用Canny边缘检测来排除边缘过多或过少的区域。
Size minObjectSize, —最小检测窗口大小
Size maxObjectSize)—最大检测窗口大小(默认是图像大小)
5.在activity里调用Picture_Detector:
新建myhandler,用于处理从线程中接收的数据:

   private Rect[] targets1Array = null;
    private Rect[] targets2Array = null;
    private MyHandler1 myHandler1;
    private MyHandler2 myHandler2;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        setContentView(R.layout.activity_camera);
        super.onCreate(savedInstanceState);
        initUI();
        myHandler1 = new MyHandler1();
        myHandler2 = new MyHandler2();
    }


    class MyHandler1 extends Handler {
        public MyHandler1() {
        }

        public MyHandler1(Looper L) {
            super(L);
        }
        // 子类必须重写此方法,接受数据
        @Override
        public void handleMessage(Message msg) {
            // TODO Auto-generated method stub
            super.handleMessage(msg);
            // 此处可以更新UI
            Bundle b = msg.getData();
            targets1Array = (Rect[]) b.getSerializable("picturedetector1");
            if(targets1Array.length > 0){
                CameraActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mTrackingImage1.setX(targets1Array[0].x);
                        mTrackingImage1.setY(targets1Array[0].y);
                        mTrackingImage1.getLayoutParams().width = targets1Array[0].width;
                        mTrackingImage1.getLayoutParams().height = targets1Array[0].height;
                        mTrackingImage1.requestLayout();
                        mTrackingImage1.setVisibility(View.VISIBLE);
                    }
                });
            }else {
                CameraActivity.this.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mTrackingImage1.setVisibility(View.INVISIBLE);
                    }
                });
            }
        }
    }

重写onSurfaceTextureUpdated回调函数,用于实时图像处理

    @Override
    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
        super.onSurfaceTextureUpdated(surface);
        Bitmap bitmap = mVideoSurface.getBitmap();
        picturehandle.new Picture_Detector1(bitmap,myHandler1).begin();
        picturehandle.new Picture_Detector2(bitmap,myHandler2).begin();
    }

相关文章

网友评论

      本文标题:opencv cascade.xml在安卓APP中的使用

      本文链接:https://www.haomeiwen.com/subject/gjkmuftx.html