蜗牛网上爬

无论你犯了多少错误,或者进步的有多慢,你都走在了那些不曾尝试的人的前面。...

【图像识别】GrabCut的Android实现

除了用神经网络,做图像识别最重要的是进行图片特征提取。包括:纹理特征、边缘特征、颜色特征、形状特征等等。每一种特征又有不同的实现方式和效果。比如形状特征可以通过提取边缘的斜率,也可以通过其外接矩形的长宽比。

目前前景提取没有十分完美的算法。一种方法不可能适用于所有复杂的环境。所以采用了人机交互的grabcut算法。通过人为制定一些背景信息,大大增加了前景提取的准确性,为之后的特征提取或降维奠定基础。

本算法基于android平台实现,在自己做之前搜索过很多相关信息后,发现目前该算法并没有在android设备上的实现。

GrabCut的算法实现:http://blog.csdn.net/bless2015/article/details/52063432

思路:
自定义view,通过onDraw方法进行画线和矩形。修改其background图片为待提取的图片。把矩形和线的参数传给grabcut算法来完成。

这其中有图片分辨率问题。更改自定义view背景问题。比较坑的是,app启动后,需要加载OpenCV的类库,这需要几十毫秒的时间,所以在使用OpenCV的数据结构时,要先等一会。所以在初始化时:

    private class ProcessImageTask extends AsyncTask<Integer, Integer, Integer> {

        @Override
        protected Integer doInBackground(Integer... arg0) {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("准备初始化...");
            mask = new Mat();
            System.out.println("imagePath:"+imagePath);
            image = Imgcodecs.imread(imagePath);
            mask.create(image.size(), CvType.CV_8UC1);
            mask.setTo(new Scalar(0));
            System.out.println("图像读取成功!");
            return 0;
        }
    }

画矩形:

            double min = CompareUtils.min(clickX, scalX);
            double min2 = CompareUtils.min(clickY, scalY);
            canvas.drawRect(rectX, rectY, (int) min, (int) min2, paint);
            System.out.println("onProcess  and  up");
            onProcess = false;

其中CompareUtils.min是进行边界判断,去参数里面的最小值。
之后把矩形数据存入mask矩阵中:

                // rows是行数 height
                double qidianX = 0;
                double qidianY = 0;
                qidianX = CompareUtils.min(clickX, rectX);
                qidianY = CompareUtils.min(clickY, rectY);
                rectangle = new Rect((int) (qidianX/proW), (int) (qidianY/proH),
                        (int) Math.abs((clickX - rectX)/proW), (int) Math.abs((clickY
                                - rectY)/proH));
                mask.submat(rectangle).setTo(new Scalar(GC_PR_FGD));

然后画轮廓,并把轮廓信息存入mask中:

            System.out.println("画轮廓 ");
            canvas.drawLine(startX, startY, clickX, clickY, paint);

            pX = CompareUtils.max(0, clickX/proW);
            pY = CompareUtils.max(0, clickY/proH);
            p = new Point((int) pX, (int) pY);

            Imgproc.circle(mask, p, radius, new Scalar(GC_BGD), thickness);

最后传给grabcut来实现:

    private class ShowTask extends AsyncTask<Integer, Integer, Integer> {

        @Override
        protected Integer doInBackground(Integer... arg0) {

            Mat bgdModel = new Mat();
            Mat fgdModel = new Mat();
            System.out.println("初始化bgdModel、fgdModel成功!");
            // source为1,1的矩阵,8位无符号数,初始化为3
            Mat source = new Mat(1, 1, CvType.CV_8U, new Scalar(3));
            System.out.println("执行GrabCut");
            Imgproc.grabCut(image, mask, rectangle, bgdModel, fgdModel, 3, 1);
            Core.compare(mask, source, mask, Core.CMP_EQ);
            // 产生输出图像
            System.out.println("准备产生输出图像");
            Mat foreground = new Mat(image.size(), CvType.CV_8UC1, new Scalar(
                    0, 0, 0));
            image.copyTo(foreground, mask);
            System.out.println("准备写入结果");
            System.out.println(mask.size());
            Imgcodecs.imwrite(path2, foreground);
            Log.i("pd", "算法完成");
            result = "success";
            return 0;
        }
    }

效果:
grabcut算法效果

阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/bless2015/article/details/52186428
个人分类: OpenCV
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭