android中使用OpenCV之图像边缘检测

目前比较火热的图像识别技术,如车牌号识别、身份证识别、人脸识别等,都广泛运用到了图像边缘检测,今天我所介绍的就是OpenCV边缘检测,实现边缘检测有三个步骤:滤波->增强->检测,opencv中有三个常用的边缘检测算子函数:canny、sobel和laplace。
附上一张原图:


myname.png

canny算子

Canny边缘检测算子是一种多级检测算法,Canny的目标是找到一个最优的边缘检测算法,算法能够尽可能多地标识出图像中的实际边缘,标识出的边缘要与实际图像中的实际边缘尽可能接近,图像中的边缘只能标识一次,并且可能存在的图像噪声不应标识为边缘。Canny算法步骤:降噪->寻找图片的亮梯度->在图像中跟踪边缘。任何边缘检测算法都不可能在未经处理的原始数据上很好地处理,所以第一步是对原始数据与高斯平滑模板作卷积,得到的图像与原始图像相比有些轻微的模糊(blurred)。这样,单独的一个像素噪声在经过高斯平滑的图像上变得几乎没有影响。图像中的边缘可能会指向不同的方向,所以Canny算法使用4个mask检测水平、垂直以及对角线方向的边缘。原始图像与每个mask所作的卷积都存储起来。对于每个点我们都标识在这个点上的最大值以及生成的边缘的方向。这样我们就从原始图像生成了图像中每个点亮度梯度图以及亮度梯度的方向。较高的亮度梯度比较有可能是边缘,但是没有一个确切的值来限定多大的亮度梯度是边缘多大又不是,所以Canny使用了滞后阈值。滞后阈值需要两个阈值——高阈值与低阈值。假设图像中的重要边缘都是连续的曲线,这样我们就可以跟踪给定曲线中模糊的部分,并且避免将没有组成曲线的噪声像素当成边缘。所以我们从一个较大的阈值开始,这将标识出我们比较确信的真实边缘,使用前面导出的方向信息,我们从这些真正的边缘开始在图像中跟踪整个的边缘。在跟踪的时候,我们使用一个较小的阈值,这样就可以跟踪曲线的模糊部分直到我们回到起点。一旦这个过程完成,我们就得到了一个二值图像,每个点表示是否是一个边缘点。
一个获得亚像素精度边缘的改进实现是在梯度方向检测二阶方向导数的过零点:

这里写图片描述

它在梯度方向的三阶方向导数满足符号条件:
这里写图片描述

这里写图片描述

表示用高斯核平滑原始图像得到的尺度空间表示 L计算得到的偏导数。用这种方法得到的边缘片断是连续曲线,这样就不需要另外的边缘跟踪改进。滞后阈值也可以用于亚像素边缘检测。
格罗宁根大学学生的Canny算子实现边缘检测的一个web项目

  /**
   * canny算子 三通道
   * 第一个参数,输入图像,需为单通道8位图像。
   * 第二个参数,输出的边缘图,需要和源图片有一样的尺寸和类型。
   * 第三个参数,第一个滞后性阈值。
   * 第四个参数,第二个滞后性阈值。
   * 第五个参数,表示孔径大小,其有默认值3。
   * 第六个参数,计算图像梯度幅值的标识,有默认值false。
   * 需要注意的是,这个函数阈值1和阈值2两者的小者用于边缘连接,
   * 而大者用来控制强边缘的初始段,推荐的高低阈值比在2:1到3:1之间
   */
CV_EXPORTS_W void Canny( InputArray dx, InputArray dy,
                         OutputArray edges,
                         double threshold1, double threshold2,
                         bool L2gradient = false );
 Mat img(h,w,CV_8UC4,pixels);
    Mat outImg;
    cvtColor(img,outImg,COLOR_BGR2BGR);
    //滤波
     blur(outImg,outImg,Size(3,3));
//    //Canny算子边缘检测
    Canny(outImg,outImg,3,9);
    Mat out;
    out = Scalar::all(0);
    img.copyTo(out,outImg);
    uchar *ptr = img.ptr(0);
    uchar *outPtr = outImg.ptr(0);
    for (int i = 0; i < w * h; ++i) {
        ptr[4*i+0] = outPtr[3*i+0];
        ptr[4*i+1] = outPtr[3*i+1];
        ptr[4*i+2] = outPtr[3*i+2];
    }
这里写图片描述

Sobel算子

它是一个离散微分算子,近似于是一个计算图像强度梯度的函数。在图像中的每个点,Sobel-Feldman算子的结果是相应的梯度向量或者这个向量的范数。Sobel算子基于将图像与水平和垂直方向上的小的可分离的整数值的滤波器进行卷积,因此在计算上相对比较节约时间。另一方面,它产生的梯度相对比较粗糙,特别是对于图像中的高频变化。
运算符使用与原始图像卷积的两个3×3内核来计算导数的近似值- 一个用于水平变化,另一个用于垂直。如果我们将A定义为源图像,则G x和G y分别是包含水平和垂直微分近似的两幅图像,计算结果如下( *这里表示二维信号处理卷积操作):


这里写图片描述

由于Sobel核可以分解为平均值和微分核的乘积,所以他们可以用平滑的方式来计算梯度。例如,G x可以写成:


这里写图片描述

该X坐标在这里被定义为向右方向增加,并y坐标被定义为向下方向增加。在图像中的每个点,可以将得到的梯度近似值结合起来,得到梯度的大小:
QQ20180204-233542@2x.png

使用这些信息,我们也可以计算出梯度的方向:
QQ20180204-233551@2x.png

例如,对于在右侧较亮的垂直边缘,θ是0。

 /**
     * sobel算子 单通道
     * 第一个参数,输入图像
     * 第二个参数,目标图像
     * 第三个参数,输出图像的深度
            使用CV_8U, 取ddepth =-1/CV_16S/CV_32F/CV_64F
            使用CV_16U/CV_16S, 取ddepth =-1/CV_32F/CV_64F
            使用CV_32F, 取ddepth =-1/CV_32F/CV_64F
            使用CV_64F, 取ddepth = -1/CV_64F
     * 第四个参数,x 方向上的差分阶数。
     * 第五个参数,y方向上的差分阶数。
     * 第六个参数,核的大小;必须取1,3,5或7。
     * 第七个参数,计算导数值时可选的缩放因子,默认值是1,表示默认情况下是没有应用缩放的。
     * 第八个参数,表示在结果存入目标图(第二个参数dst)之前可选的delta值,有默认值0。
     * 第九个参数,边界模式,默认值为BORDER_DEFAULT。
     * 一般情况下,都是用ksize x ksize内核来计算导数的。
     * 然而,有一种特殊情况——当ksize为1时,往往会使用3 x 1或者1 x 3的内核。
     * 且这种情况下,并没有进行高斯平滑操作。
     */
CV_EXPORTS_W void Sobel( InputArray src, OutputArray dst, int ddepth,
                         int dx, int dy, int ksize = 3,
                         double scale = 1, double delta = 0,
                         int borderType = BORDER_DEFAULT );
  Mat img(h,w,CV_8UC4,pixels);
   Mat outImg;
  cvtColor(img,outImg,COLOR_BGR2GRAY);//单通道
   Mat outimgX,outimgY,outXY;
    //x方向sobel梯度
    Sobel(outImg,outimgX,CV_8U,1,0);
    //y方向sobel梯度
    Sobel(outImg,outimgY,CV_8U,0,1);
    //合并梯度
    addWeighted(outimgX,0.5,outimgY,0.5,0,outXY);
    uchar *ptr = img.ptr(0);
    uchar *outPtr = outXY.ptr(0);
    for (int i = 0; i < w * h; ++i) {
        ptr[4*i+0] = outPtr[i];
        ptr[4*i+1] = outPtr[i];
        ptr[4*i+2] = outPtr[i];
    }
sobel算子.png

laplacian算子
在opencv中laplacian算子通过二阶导数来检测边缘,由于图像是2D的,所以需要在两个维度上采用导数。Opencv中使用laplacian计算图像的梯度,然后内部有调用了Sobel算子。
laplacian算子定义:

这里写图片描述

/**
       * laplacian函数
       * 第一个参数,输入图像,需为单通道8位图像。
       * 第二个参数,输出的边缘图,需要和源图片有一样的尺寸和通道数。
       * 第三个参数,目标图像的深度。
       *  IPL_DEPTH_8U - 无符号8位整型              0--255
       *  IPL_DEPTH_8S - 有符号8位整型                   -128--127
       *  IPL_DEPTH_16U - 无符号16位整型                0--65535
       *  IPL_DEPTH_16S - 有符号16位整型                -32768--32767
       *  IPL_DEPTH_32S - 有符号32位整型                00.0--1.0
       *  IPL_DEPTH_64F - 双精度浮点数                  0.0--1.0
       * 第四个参数,用于计算二阶导数的滤波器的孔径尺寸,大小必须为正奇数,且有默认值1。
       * 第五个参数,计算拉普拉斯值的时候可选的比例因子,有默认值1。放大或者缩小因子。
       * 第六个参数,表示在结果存入目标图(第二个参数dst)之前可选的delta值,有默认值0。
       * 第七个参数,边界模式,默认值为BORDER_DEFAULT。
       */
CV_EXPORTS_W void Laplacian( InputArray src, OutputArray dst, int ddepth,
 int ksize = 1, double scale = 1, double delta = 0,int borderType = BORDER_DEFAULT );
    Mat img(h,w,CV_8UC4,pixels);
    Mat outImg;
    cvtColor(img,outImg,COLOR_BGR2GRAY);//单通道
     Laplacian(outImg,outImg,CV_8U);
      uchar *ptr = img.ptr(0);
    uchar *outPtr = outXY.ptr(0);
    for (int i = 0; i < w * h; ++i) {
        ptr[4*i+0] = outPtr[i];
        ptr[4*i+1] = outPtr[i];
        ptr[4*i+2] = outPtr[i];
    }

这里写图片描述

本文章著作版权所属:微笑面对,请关注我的CSDN博客:博客地址

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容

  • 不同图像灰度不同,边界处一般会有明显的边缘,利用此特征可以分割图像。需要说明的是:边缘和物体间的边界并不等同,边缘...
    大川无敌阅读 13,840评论 0 29
  • 1、阈值分割 1.1 简介 图像阈值化分割是一种传统的最常用的图像分割方法,因其实现简单、计算量小、性能较稳定而成...
    木夜溯阅读 22,579评论 9 15
  • 在图像处理中经常有一个需求就是要知道图像中物体的边缘,以此来做物体区分或作其他处理,有时还可实现某些滤镜效果例如我...
    wosicuanqi阅读 3,757评论 3 2
  • 这篇文章总结比较全面:http://blog.csdn.net/timidsmile/article/detail...
    rogerwu1228阅读 1,822评论 0 3
  • 今早和朋友聊起书写,无意中谈起这半年来参加的各种写作小组,以及自己办过的那两期,心里很多感慨。 动笔去写,不怕被别...
    穆勒书信时光阅读 404评论 4 2