OpenCV4Android学习之图像基本特征检测

原创 2016年12月05日 14:02:29

图像中的信息包括边缘、直线、椭圆、色块或轮廓、角点等形式,这些信息在计算机视觉和图像处理语境中通常被称为特征。下面就来了解一些结合OpenCV在Android平台上的常规的特征检测算法,这里使用AndroidStudio开发平台,当然Eclipse也一样。如果对在这两个IDE上部署OpenCV不熟悉的话,可以参考我之前写的这篇文章:Eclipse与AndroidStudio关于OpenCV4Android库的部署


1.边缘和焦点检测
边缘检测和角点检测时两种最基本也是非常有用的特征检测算法,这些算法包括高斯差分、Canny边缘检测器、Sobel算子和Harris角点。比如我们想在一幅图中找到不同目标的边界或者角点,用于分析目标在图像中的旋转或移动等情况,这时候就需要知道边缘和角点的信息了。

  • 高斯差分
    这里我们先了解下什么是边缘和高斯模糊方法,因为下面要用到边缘这个性质和对图像进行高斯模糊来计算边缘点,即边缘点。

    • 简单的说,边缘就是图像中像素亮度变化明显的点。
    • 高斯(Gaussian)模糊是最常用的模糊方法,是将指定像素变换为其与周边像素加权平均后的值,权重就是高斯分布函数计算出来的值。OpenCV提供了GaussianBlur()的内置函数,我们可以在应用中使用它执行高斯模糊。这里是一篇关于高斯模糊算法的介绍:高斯模糊算法

    形如:

    Mat src;
    Imgproc.GaussianBlur(src,src,new Size(6,6),0);

    让我们回到高斯差分技术,其算法分成三步:

    • 将图像转换为弧度图像
    • 用两个不同的模糊半径对灰色图像执行高斯模糊
    • 对上面两幅图像相减,得到一副只包含边缘点的结果图像

    在应用中,创建一个用于给定图像计算边缘的函数:

    /**
     * 高斯差分
     */
    private void DifferenceOfGaussian() {
        Mat grayMat = new Mat();
        Mat blur1 = new Mat();
        Mat blur2 = new Mat();
        //将图像转换为灰度
        Imgproc.cvtColor(originalMat, grayMat, Imgproc.COLOR_BGR2GRAY);
        //以两个不同的模糊半径对图像做模糊处理,前两个参数分别是输入和输出图像,第三个参数指定应用滤波器时所用核的尺寸,最后一个参数指定高斯函数中的标准差数值
        Imgproc.GaussianBlur(grayMat, blur1, new Size(15, 15), 5);
        Imgproc.GaussianBlur(grayMat, blur2, new Size(21, 21), 5);
        //将两幅模糊后的图像相减
        Mat DoG = new Mat();
        Core.absdiff(blur1, blur2, DoG);
        //反转二值阈值化
        Core.multiply(DoG, new Scalar(100), DoG);
        Imgproc.threshold(DoG, DoG, 50, 255, Imgproc.THRESH_BINARY_INV);
        //将Mat转换为位图
        Utils.matToBitmap(DoG, currentBitmap);
        loadImageToImageView();
    }
    /**
     * 设置图像
     */
    private void loadImageToImageView() {
        ImageView imgView = (ImageView) findViewById(R.id.image_view);
        imgView.setImageBitmap(currentBitmap);
    }

处理结果图:

高斯差分

  • Canny边缘检测器
    Canny边缘检测器算法使用了多向灰度梯度和滞后阈值化等复杂技巧,它是边缘检测的最优方法。
    算法分为四个步骤:
    • 平滑图:使用合适的模糊半径执行高斯模糊来减少图像内的噪声
    • 计算图像梯度:计算图像梯度,并将其分为垂直、水平和斜对角
    • 非最大值:由图像梯度计算得到梯度方向,检查某一像素在梯度正方向和负方向的局部最大值,然后抑制该像素
    • 用滞后阈值化选择边缘:检查某一条边缘是否明显到足以作为最终输出,最后取出所有不够明显的边缘

下面是OpenCV对该算法在Android上的实现代码:

    /**
     * Canny边缘检测器
     */
    private void Canny() {
        Mat grayMat = new Mat();
        Mat cannyEdges = new Mat();
        //将图像转换为灰度
        Imgproc.cvtColor(originalMat, grayMat, Imgproc.COLOR_RGB2GRAY);
        Imgproc.Canny(grayMat, cannyEdges, 10, 100);
        //将Mat转换回位图
        Utils.matToBitmap(cannyEdges, currentBitmap);
        loadImageToImageView();
    }
    /**
     * 设置图像
     */
    private void loadImageToImageView() {
        ImageView imgView = (ImageView) findViewById(R.id.image_view);
        imgView.setImageBitmap(currentBitmap);
    }

处理结果图:

Canny边缘检测器

  • Sobel算子
    Sobel算子和Canny边缘检测一样,计算像素灰度梯度。
    算法分为四个步骤:
    • 将图像转换为灰度图像
    • 计算水平方向灰度梯度绝对值
    • 计算垂直方向灰度梯度绝对值
    • 计算最终梯度

下面是OpenCV对该算法在Android上的实现代码:

    /**
     * Sobel算子
     */
    private void Sobel() {
        Mat grayMat = new Mat();
        //用来保存结果的Mat
        Mat sobel = new Mat(); 
        //分别用于保存梯度和绝对梯度的Mat
        Mat grad_x = new Mat();
        Mat abs_grad_x = new Mat();
        Mat grad_y = new Mat();
        Mat abs_grad_y = new Mat();
        //将图像转换为灰度
        Imgproc.cvtColor(originalMat, grayMat, Imgproc.COLOR_BGR2GRAY);
        //计算水平方向梯度
        Imgproc.Sobel(grayMat, grad_x, CvType.CV_16S, 1, 0, 3, 1, 0);
        //计算垂直方向梯度
        Imgproc.Sobel(grayMat, grad_y, CvType.CV_16S, 0, 1, 3, 1, 0);
        //计算两个方向上梯度绝对值
        Core.convertScaleAbs(grad_x, abs_grad_x);
        Core.convertScaleAbs(grad_y, abs_grad_y);
        //计算结果梯度
        Core.addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 1, sobel);
        //将Mat转换为位图
        Utils.matToBitmap(sobel, currentBitmap);
        loadImageToImageView();
    }
     /**
     * 设置图像
     */
    private void loadImageToImageView() {
        ImageView imgView = (ImageView) findViewById(R.id.image_view);
        imgView.setImageBitmap(currentBitmap);
    }

处理结果图:

Sobel算子

  • Harris角点检测
    Harris焦点检测器是一种在角点检测中最常用的技术,在图像上使用滑动窗口计算亮度的变化。
    下面是OpenCV对该算法在Android上的实现代码:
    /**
     * Harris角点
     */
    private void HarrisCorner() {
        Mat grayMat = new Mat();
        Mat corners = new Mat();
        //将图像转换成灰度
        Imgproc.cvtColor(originalMat, grayMat, Imgproc.COLOR_BGR2GRAY);
        Mat tempDst = new Mat();
        //找出角点
        Imgproc.cornerHarris(grayMat, tempDst, 2, 3, 0.04);
        //在新的图像上绘制角点
        Mat tempDstNorm = new Mat();
        Core.normalize(tempDst, tempDstNorm, 0, 255, Core.NORM_MINMAX);
        Core.convertScaleAbs(tempDstNorm, corners);
        //将Mat转换为位图
        Random r = new Random();
        for (int i = 0; i < tempDstNorm.cols(); i++) {
            for (int j = 0; j < tempDstNorm.rows(); j++) {
                double[] value = tempDstNorm.get(j, i);
                if (value[0] > 150)
                    Core.circle(corners, new Point(i, j), 5, new Scalar(r.nextInt(255)), 2);
            }
        }
        //将Mat转换为位图
        Utils.matToBitmap(corners, currentBitmap);
        loadImageToImageView();
    }
    /**
     * 设置图像
     */
    private void loadImageToImageView() {
        ImageView imgView = (ImageView) findViewById(R.id.image_view);
        imgView.setImageBitmap(currentBitmap);
    }

处理结果图:

Harris角点检测


2.霍夫变换
对于图像分析来说,除了边缘和角点外,还需要检测如直线、圆、椭圆等其他相关形状。例如我们想在一张桌子的图像中检测签字笔等,对于这种情况,一般采用霍夫变换这种技术,它被广泛采用的利用数学等式的参数形式在图像中检测形状的技术。通常我们考虑二维形状的霍夫变换,比如直线和圆,它相对于球体等复杂形状而言更为简单。

  • 霍夫直线
    我们对于霍夫变化一般不会直接对图像执行算法,因为图像中任何一条明显的直线都一定是边缘,反之则不然。OpenCV提供了两种实现霍夫直线的方式:标准霍夫直线和概率霍夫直线。它们的主要区别在于概率霍夫直线选取经过随机采样的边缘点子集,而不是所有的边缘点。因为这种方式处理的点更少,所以这使得算法的执行速度更快,而不会降低算法的效果。
    下面是OpenCV对该算法在Android上的实现代码:

    /**
     * 霍夫直线
     */
    private void HoughLines() {
        Mat grayMat = new Mat();
        Mat cannyEdges = new Mat();
        Mat lines = new Mat();
        //将图像转换成灰度
        Imgproc.cvtColor(originalMat, grayMat, Imgproc.COLOR_BGR2GRAY);
        //这里使用Canny边缘检测技术计算图像中的边缘,使用其他的也可以
        Imgproc.Canny(grayMat, cannyEdges, 10, 100);
        Imgproc.HoughLinesP(cannyEdges, lines, 1, Math.PI / 180, 50, 20, 20);
        Mat houghLines = new Mat();
        houghLines.create(cannyEdges.rows(), cannyEdges.cols(), CvType.CV_8UC1);
        //在图像上绘制直线
        for (int i = 0; i < lines.cols(); i++) {
            double[] points = lines.get(0, i);
            double x1, y1, x2, y2;
            x1 = points[0];
            y1 = points[1];
            x2 = points[2];
            y2 = points[3];
            Point pt1 = new Point(x1, y1);
            Point pt2 = new Point(x2, y2);
            //在一副图像上绘制直线
            Core.line(houghLines, pt1, pt2, new Scalar(255, 0, 0), 1);
        }
        //将Mat转换为位图
        Utils.matToBitmap(houghLines, currentBitmap);
        loadImageToImageView();
    }
    /**
     * 设置图像
     */
    private void loadImageToImageView() {
        ImageView imgView = (ImageView) findViewById(R.id.image_view);
        imgView.setImageBitmap(currentBitmap);
    }

    处理结果图:

    霍夫直线检测

  • 霍夫圆

    与霍夫直线类似,步骤也一样。
    下面是OpenCV对该算法在Android上的实现代码:

    /**
     *霍夫圆
     */
    private void HoughCircles() {
        Mat grayMat = new Mat();
        Mat cannyEdges = new Mat();
        Mat circles = new Mat();
        //将图像转换成灰度
        Imgproc.cvtColor(originalMat, grayMat, Imgproc.COLOR_BGR2GRAY);
       //这里使用Canny边缘检测技术计算图像中的边缘,使用其他的也可以
        Imgproc.Canny(grayMat, cannyEdges, 10, 100);
        Imgproc.HoughCircles(cannyEdges, circles, Imgproc.CV_HOUGH_GRADIENT, 1, cannyEdges.rows() / 15);
        Mat houghCircles = new Mat();
        houghCircles.create(cannyEdges.rows(), cannyEdges.cols(), CvType.CV_8UC1);
        //在图像上绘制圆形
        for (int i = 0; i < circles.cols(); i++) {
            double[] parameters = circles.get(0, i);
            double x, y;
            int r;
            x = parameters[0];
            y = parameters[1];
            r = (int) parameters[2];
            Point center = new Point(x, y);
            //在一副图像上绘制圆形
            Core.circle(houghCircles, center, r, new Scalar(255, 0, 0), 1);
        }
        //将Mat转换为位图
        Utils.matToBitmap(houghCircles, currentBitmap);
        loadImageToImageView();
    }
     /**
     * 设置图像
     */
    private void loadImageToImageView() {
        ImageView imgView = (ImageView) findViewById(R.id.image_view);
        imgView.setImageBitmap(currentBitmap);
    }

处理结果图:

霍夫圆检测


3.轮廓
有时候我们只想关注于感兴趣的目标,这就需要将图像分解成更小的片元,比如我们在一角、五角和一元硬币中分析五角的情况。我们有两种实现途径,一种是使用霍夫圆,另一种就是利用轮廓检测将图像分割为更小的部分,每个部分代表一个特定的硬币。轮廓通常以图像中的边缘来计算,边缘与轮廓的区别在于轮廓是闭合的,边缘可以是任意的。
下面是OpenCV对该算法在Android上的实现代码:

    /**
     * 轮廓检测
     */
    private void Contours() {
        Mat grayMat = new Mat();
        Mat cannyEdges = new Mat();
        Mat hierarchy = new Mat();
        List<MatOfPoint> contourList = new ArrayList<MatOfPoint>(); //A list to store all the contours
        //保存轮廓列表
        Imgproc.cvtColor(originalMat, grayMat, Imgproc.COLOR_BGR2GRAY);
         //这里使用Canny边缘检测技术计算图像中的边缘,使用其他的也可以
        Imgproc.Canny(originalMat, cannyEdges, 10, 100);
        //找出轮廓
        Imgproc.findContours(cannyEdges, contourList, hierarchy, Imgproc.RETR_LIST, Imgproc.CHAIN_APPROX_SIMPLE);
        //在新的图像上绘制轮廓
        Mat contours = new Mat();
        contours.create(cannyEdges.rows(), cannyEdges.cols(), CvType.CV_8UC3);
        Random r = new Random();
        for (int i = 0; i < contourList.size(); i++) {
            Imgproc.drawContours(contours, contourList, i, new Scalar(r.nextInt(255), r.nextInt(255), r.nextInt(255)), -1);
        }
        //将Mat转换为位图
        Utils.matToBitmap(contours, currentBitmap);
        loadImageToImageView();
    }
    /**
     * 设置图像
     */
    private void loadImageToImageView() {
        ImageView imgView = (ImageView) findViewById(R.id.image_view);
        imgView.setImageBitmap(currentBitmap);
    }

处理结果图:

轮廓检测


以上就是图像的基本特征在Android设备上实现的不同算法,也是我们在Android相关应用开发中的基础。

版权声明:本文为博主原创文章,转载需声明出处。

相关文章推荐

玩转Dragonboard 410c开发板USB摄像头——移动侦测

移动侦测是常见的智能化视频监控手段之一,其通过判断和识别移动物体然后进行拍照记录可以有效的降低处理器的计算处理量,只需要在有移动事件触发的时候才进行监控和录像,进而避免监控录制和拍摄大量的无用的照片信...

OpenCV学习笔记(七)—— OpenCV for Android实时图像处理

在上篇中我们已经实现了相机打开和实时图像信息的获取,那么接下来我们可以尝试在获取的图像信息进行一些处理,然后实时显示出来,在这里我们要完成的的几种处理:         灰化、Canny边缘检测、H...

移动侦测的方法

背景减除法 背景减除法 (Background Subtraction ) 是目前运动检测中最常用的一种方法,它是利用当前图像与背景图像的差分来检测出运动区域的一种技术。它一般能够提供最完全的特征数...

OpenCV用形态学方法进行图像线特征和角点的提取

1:图像形态学用于边缘的提取: 我们知道,图像膨胀后边缘会扩张,腐蚀后会紧缩,通过计算膨胀与紧缩的图像之差,就可以粗略的检测出图像的边缘; int _tmain(int argc, _TCHA...

FAST角点检测方法详解

FAST(Features from Accelerated Segment Test)由Edward Rosten和Tom Drummond在2006年首先提出,是近年来一总倍受关注的基于模板和机器...
  • tostq
  • tostq
  • 2015-10-21 23:14
  • 3569

OpenCV学习笔记__角点检测

1、Harris角点检测 引言: a.图像特征类型可以被分为如下三种:     - 边缘     - 角点 (感兴趣关键点)     -&...

Android OpenCV图像识别和图像追踪

首先介绍一下OpenCV中图像识别和跟踪机制:        图像跟踪机制是确定矩目标在3D环境中的姿态,并根据此类信息环绕目标对象绘制轮廓线。在最终的2D图像中,考虑到目标可能相对于相机倾斜,因而...

opencv实现摄像头的实时图像采集与显示

opencv实现摄像头的实时图像采集与显示

Android OpenCV 旋转图像

android opencv的图像旋转方法
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)