精华内容
下载资源
问答
  • 静态手势图像轮廓特征提取算法研究_陶桑彪 知网论文
  • 图像特征提取新领域:pww轮廓特征提取
  • 图像特征提取新领域:pww轮廓特征提取 1、高清视频中实现实时提取图像特征 2、图像特征点定位准确,快速 3、用于模式识别,替代surf算法 4、对于很多应用,需要前期处理。 5、时间有限,只能写这么多给大家,其他的...
  • http://download.csdn.net/index.php/mobile//user/downloads/pww71/4
  • pww轮廓特征提取vc2010

    2016-06-09 13:35:58
    图像特征提取新领域:pww轮廓特征提取
  • 医学成像技术是生物医学工程专业的一门重要的专业课程。课程主要涉及X光仪器,CT...让学生练习CT图像的重建有助于学生理解CT算法的内容,熟悉数字图像重建的过程。同时也能培养学生的团队精神和解决实际问题的能力。
  • 轮廓特征提取MATLAB实现

    热门讨论 2009-10-29 16:01:42
    提取图像轮廓特征,适用于灰度图像,用MATLAB程序实现,在MATLAB中可直接运行
  • 基于图像特征分析的物体轮廓提取
  • 图像基础——图像形状特征提取

    千次阅读 2020-07-28 22:24:12
    图像形状特征提取简单形状特征矩形度球状性圆形性质心坐标 cv.moments()中心距Opencv中图像轮廓拟合轮廓的查找与绘制OpenCV中轮廓的周长与面积几何图形的最小外包与拟合最小外包矩形 cv.minAreaRect()最小外包圆形 ...

    简单形状特征

    矩形度

    矩形度体现物体对其外接矩形的充满程度,反映一个物体与矩形相似程度的一个参数。用物体的面积与其最小外接矩形的面积之比描述,即:

    AO是该物体的面积,而AMER是其外接矩形的面积。当物体为矩形时,R取得最大值1.0;圆形物体的R取值为π/4;细长的、弯曲的物体的R的取值变小。

    与矩形度相关的辅助特征为长宽比:

    其中W表示物体外接矩形的宽度,L表示外接矩形的长度。利用长宽比可以将细长的物体与圆形或方形的物体区分开。

    球状性

    球状性(Sphericity)既可以描述二维目标,也可以描述三维目标,其定义为:


    描述二维目标时,ri表示目标区域内切圆的半径,rc表示目标区域外接圆的半径,两个圆的圆心都在区域的重心上。

    可知S的取值范围为0<S≤1。当目标区域为圆形时,目标的球状性值S达到最大值1,当目标区域为其他形状时,S<1。显然,S不受区域平移、旋转和尺度变化的影响。

    圆形性

    目标圆形性(Doularity)是指用目标区域R的所有边界点定义的特征量,其定义式为:

    设(xi,yi)为图像边界点坐标,([插图])为图像的重心坐标,其中μR是从区域重心到边界点([插图])的平均距离,定义为:

    而σR是从区域重心到边界点的距离均方差,定义为:

    针对灰度图像,区域重心可以定义为:

    质心坐标 cv.moments()

    由于图像区域的某些矩对于平移、旋转、尺度等几何变换具有一些不变的特性,使得矩的表示方法在物体的分类与识别方面具有重要的意义。对于二元有界函数f(x,y),它的(j+k)阶矩为:

    二值图像中一个物体的质心坐标为:

    下面代码的图例后面可以看到。

    filename = 'rang.jpg'
    img = cv.imread(filename)
    gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
    ret,binary = cv.threshold(gray,127,255,cv.THRESH_BINARY)
    plt.imshow(binary,'gray')
    plt.show()
    row,col = img.shape[:2]
    contours,hierarchy = cv.findContours(binary,cv.RETR_TREE,cv.CHAIN_APPROX_SIMPLE)
    dic = cv.moments(contours[0])
    print('正方形的矩的质心为:{}'.format((dic['m10']/dic['m00'],dic['m01']/dic['m00'])))
    

    该矩的质心为:(627.5, 264.5)

    中心距

    为了获得矩的不变特征,往往采用中心矩以及归一化的中心距。中心距的定义为:

    中心矩以质心作为原点进行计算,因此它具有位置无关性。

    Opencv中图像轮廓拟合

    轮廓的查找与绘制

    在OpenCV中提供了cv2.findContours()和cv2.drawContours()函数来实现对图像轮廓的查找与绘制。

    • 方法说明
    1. cv2.findContours()

    img,contours,hierarchy = cv.fingContours(image,mode,method)
    参数说明:
    1、image表示8位单通道二值图像。
    2、mode表示轮廓检索模式
    3、method表示轮廓的近似方法
    返回值说明:
    1、image表示8位单通道原始图像
    2、contours表示返回的轮廓
    3、hierarchy表示轮廓的层次信息
    具体参数值参考这里

    1. cv2.drawContours()

    image = cv2.drawContours(image,contours,contourIdx,color,[,thickness ,lineType,hierarchy,maxLevel,offset])
    参数说明:
    1、image表示待绘制轮廓的图像
    2、 contours表示需要绘制的轮廓。
    3、contourIdx表示需要绘制的边缘索引,一般填-1
    4、color表示绘制的轮廓颜色
    5、thickness表示绘制轮廓的粗细
    6、lineType表示绘制轮廓所选用的线型
    7、hierarchy对应cv2.findContours()函数中同样参数的信息
    8、maxLevel控制所绘制轮廓层次的深度
    9、offset表示轮廓的偏移程度

    • 绘制一幅图像内的轮廓
    filename = 'rang.jpg'
    img = cv.imread(filename)
    gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
    ret,binary = cv.threshold(gray,127,255,cv.THRESH_BINARY)
    plt.imshow(binary,'gray')
    plt.show()
    contours,hierarchy = cv.findContours(binary,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)
    print(len(contours))   # 2
    img1 = cv.drawContours(img,contours,-1,(0,255,0),3)
    plt.imshow(img1)
    plt.show()
    


    • 利用查找绘制轮廓的方法提取出一幅图像的前景信息
    filename = 'rang.jpg'
    img = cv.imread(filename)
    gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
    ret,binary = cv.threshold(gray,127,255,cv.THRESH_BINARY)
    contours,hierarchy = cv.findContours(binary,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)
    mask = np.zeros(img.shape,np.uint8)  #制作掩膜
    img1 = cv.drawContours(mask,contours,-1,(255,255,255),-1)
    log_img = cv.bitwise_and(img,mask)  #取前景
    
    

    OpenCV中轮廓的周长与面积

    在OpenCV中,当查找并绘制出图像的轮廓后,可以通过cv2.arcLength()函数和cv2. contourArea()函数计算轮廓的周长与面积。

    • 周长 cv2.arcLength()

    ret = cv2.arcLength(contour,booled)
    参数说明:
    1、ret表示返回的轮廓周长
    2、contour表示输入的轮廓
    3、 booled表示轮廓的封闭性

    filename = 'rang.jpg'
    img = cv.imread(filename)
    gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
    ret,binary = cv.threshold(gray,127,255,cv.THRESH_BINARY)
    contours,hierarchy = cv.findContours(binary,cv.RETR_EXTERNAL,cv.CHAIN_APPROX_SIMPLE)
    for i in range(len(contours)):
        print("第%d个轮廓的周长为:%f"%(i+1,cv.arcLength(contours[i],True)))
    

    第1个轮廓的周长为:944.000000
    第2个轮廓的周长为:1079.016364

    • 面积计算 cv.contourArea()

    ret = cv.contourArea(contour[,booled])

    filename = 'rang.jpg'
    img = cv.imread(filename)
    gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
    ret,binary = cv.threshold(gray,127,255,cv.THRESH_BINARY)
    plt.imshow(binary,'gray')
    plt.show()
    contours,hierarchy = cv.findContours(binary,cv.RETR_LIST,cv.CHAIN_APPROX_SIMPLE)
    for i in range(len(contours)):
        print("第%d个轮廓的面积为:%f"%(i+1,abs(cv.contourArea(contours[i],True))))
    

    第1个轮廓的面积为:55671.000000
    第2个轮廓的面积为:23783.500000

    几何图形的最小外包与拟合

    最小外包矩形 cv.minAreaRect()

    在OpenCV中提供了cv2.minAreaRect()函数用来绘制轮廓的最小外包矩形框,其一般格式为:
    ret = cv2.minAreaRect(contours)
    ret表示返回的矩形特征信息

    • 注意

    返回值ret的结构不符合cv2.drawContours()函数的参数结构要求。因此,必须使用cv2.boxPoints()函数将上述返回值ret转换为符合要求的结构。
    point = cv.boxPoints(box)
    1、box表示cv2.minAreaRect()函数返回值类型的值。
    2、points表示返回的符合结构的矩形特征信息。

    filename = 'rang.jpg'
    img = cv.imread(filename)
    gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
    ret,binary = cv.threshold(gray,127,255,cv.THRESH_BINARY)
    contours,hierarchy = cv.findContours(binary,cv.RETR_LIST,cv.CHAIN_APPROX_SIMPLE)
    rect = cv.minAreaRect(contours[1])
    points = cv.boxPoints(rect)
    points = np.int0(points)  #取整
    img1 = cv.drawContours(img,[points],0,(0,0,255),2)
    plt.imshow(img1)
    plt.show()
    

    最小外包圆形 cv. minEnclosingCircle () cv.circle()

    在OpenCV中提供了cv2. minEnclosingCircle ()函数来绘制轮廓的最小外包圆形,其一般格式为:
    center,radius = cv2. minEnclosingCircle(point)

    在绘制圆形外包时会用到cv.circle()函数。

    filename = 'rang.jpg'
    img = cv.imread(filename)
    gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
    ret,binary = cv.threshold(gray,127,255,cv.THRESH_BINARY)
    contours,hierarchy = cv.findContours(binary,cv.RETR_LIST,cv.CHAIN_APPROX_SIMPLE)
    (x,y),r = cv.minEnclosingCircle(contours[0])
    center = (int(x),int(y))
    r = int(r)
    img1 = cv.circle(img,center,r,(0,0,255),4)
    plt.imshow(img1)
    plt.show()
    

    最小外包三角形 cv.minEnclosingTriangle() cv.line()

    在OpenCV中提供了cv2.minEnclosingTriangle()函数来绘制轮廓的最小外包三角形,其一般格式为:
    ret,triangle = cv2.minEnclosingTriangle(point)
    1、ret表示最小外包三角形的面积。
    2、triangle表示最小外包三角形的三个顶点集。 shape为(3, 1, 2)

    在绘制三角形外包时会用到cv.line()函数。

    filename = 'rang.jpg'
    img = cv.imread(filename)
    gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
    ret,binary = cv.threshold(gray,127,255,cv.THRESH_BINARY)
    contours,hierarchy = cv.findContours(binary,cv.RETR_LIST,cv.CHAIN_APPROX_SIMPLE)
    area,trg = cv.minEnclosingTriangle(contours[0])
    for i in range(0,3):
        cv.line(img,tuple(trg[i][0]),tuple(trg[(i+1)%3][0]),(0,0,255),4)
    plt.imshow(img)
    plt.show()
    

    最小外包椭圆 cv. fitEllipse() cv.ellipse()

    在OpenCV中提供了cv. fitEllipse()函数来绘制轮廓的最小外包椭圆,其一般格式为:
    ret = cv. fitEllipse(points)
    ret表示返回的椭圆特征信息,包括中心点、轴长度和旋转角等,元组类型,如:((224.43301391601562, 268.66680908203125),
    (214.72067260742188, 235.9137420654297),
    1.1991876363754272)

    filename = 'rang.jpg'
    img = cv.imread(filename)
    gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
    ret,binary = cv.threshold(gray,127,255,cv.THRESH_BINARY)
    contours,hierarchy = cv.findContours(binary,cv.RETR_LIST,cv.CHAIN_APPROX_SIMPLE)
    a = cv.fitEllipse(contours[1])
    cv.ellipse(img,a,(0,0,255),4)
    plt.imshow(img)
    plt.show()
    

    最优拟合直线 cv. fitLine()

    在OpenCV中提供了cv2. fitLine()函数来绘制轮廓的最优拟合直线,其一般格式为:
    line = cv. fitLine(points,distType,param,reps,aeps)
    参数说明:
    1、line表示返回的最优拟合直线参数。 [a,b,c,d]
    2、distType表示距离类型。
    3、param表示距离参数,与所用距离类型相关。
    4、reps表示最优拟合直线的径向精度,一般为0.01。
    5、aeps表示最优拟合直线的角度精度,一般为0.01。

    filename = 'rang.jpg'
    img = cv.imread(filename)
    gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
    ret,binary = cv.threshold(gray,127,255,cv.THRESH_BINARY)
    
    row,col = img.shape[:2]
    contours,hierarchy = cv.findContours(binary,cv.RETR_LIST,cv.CHAIN_APPROX_SIMPLE)
    [vx,vy,x,y] = cv.fitLine(contours[1],cv.DIST_L2,0,0.01,0.01)
    #计算直线绘制参数
    ly = int((-x*vy/vx)+y)
    ry = int(((col-x)*vy/vx)+y)
    cv.line(img,(col-1,ry),(0,ly),(0,0,255),4)
    plt.imshow(img)
    plt.show()
    

    展开全文
  • MATLAB对图像处理的填充边缘检测轮廓特征提取。 主要函数:及其功能说明如下: imfill函数与bwperim函数:* 1、使用边缘检测和形态学检测细胞 此示例说明如何使用边缘检测和基本形态学检测到相对于背景的对象。 2、...

    MATLAB对图像处理的填充边缘检测轮廓特征提取。
    主要函数:及其功能说明如下:

    imfill函数与bwperim函数*
    1、使用边缘检测和形态学检测细胞
    此示例说明如何使用边缘检测和基本形态学检测到相对于背景的对象。
    2、使用纹理滤波器的纹理分割
    此示例说明如何使用熵滤波器进行纹理分割。
    3、标识圆形对象
    此示例说明如何跟踪区域边界并根据对象的圆度对其进行分类。

    往往结合起来一起使用,效果会更好一些。

    源码如下:

    clear all;close all;clc;
    
    RGB = imread('dshfg.jfif');
    I  = im2gray(RGB);
    im=im2bw(RGB);
    
    subplot(131);
    imshow(RGB);title('原始图像');
    
    im22=imfill(im,'holes');             %填充  
    im33=bwperim(im22);                   %轮廓提取  
    
    subplot(132);
    imshow(im22); title('填充效果');%显示  
    
    subplot(133);
    imshow(im33);title('显示轮廓');
    

    效果如图:
    在这里插入图片描述
    尤其是对特殊图片的特征检测,比较明显。在这里插入图片描述

    展开全文
  • 图像边缘和轮廓特征提取方法

    千次阅读 2019-04-02 20:32:00
    图像锐化是为了突出图像上地物的边缘、轮廓,或某些线性目标要素的特征。这种滤波方法提高了地物边缘与周围像元之间的反差,因此也被称为边缘增强。 2图像平滑 概念 图像平滑是指用于突出图像的宽大区域、低...

    Part1:先介绍几个关于图像处理的概念

    1 图像锐化

    图像锐化(image sharpening)是补偿图像的轮廓,增强图像的边缘及灰度跳变的部分,使图像变得清晰,分为空域处理和频域处理两类。图像锐化是为了突出图像上地物的边缘、轮廓,或某些线性目标要素的特征。这种滤波方法提高了地物边缘与周围像元之间的反差,因此也被称为边缘增强。

    2图像平滑

    概念

    图像平滑是指用于突出图像的宽大区域、低频成分、主干部分或抑制图像噪声和干扰高频成分的图像处理方法,目的是使图像亮度平缓渐变,减小突变梯度,改善图像质量。

    方法

    图像平滑的方法包括:插值方法,线性平滑方法,卷积法等等。这样的处理方法根据图像噪声的不同进行平滑,比如椒盐噪声,就采用线性平滑方法!

    3理解低频信号和高频信号

       图像中的低频信号和高频信号也叫做低频分量和高频分量。 简单一点说,图像中的高频分量,指的是图像强度(亮度/灰度)变化剧烈的地方,也就是我们常说的边缘(轮廓);图像中的低频分量,指的是图像强度(亮度/灰度)变换平缓的地方,也就是大片色块的地方。  人眼对图像中的高频信号更为敏感,举个例子,在一张白纸上有一行字,那么我们肯定直接聚焦在文字上,而不会太在意白纸本身,这里文字就是高频信号,而白纸就是低频信号。 

      图像的高低频是对图像各个位置之间强度变化的一种度量方法. 低频分量:主要对整副图像的强度的综合度量. 高频分量:主要是对图像边缘和轮廓的度量.   如果一副图像的各个位置的强度大小相等,则图像只存在低频分量,从图像的频谱图上看,只有一个主峰,且位于频率为零的位置. 

       如果一副图像的各个位置的强度变化剧烈,则图像不仅存在低频分量,同时也存在多种高频分量,从图像的频谱上看,不仅有一个主峰,同时也存在多个旁峰. 

    Part2:常见的边缘检测算子的原理

     不同图像灰度不同,边界处一般会有明显的边缘,利用此特征可以分割图像。需要说明的是:边缘和物体间的边界并不等同,边缘指的是图像中像素的值有突变的地方,而物体间的边界指的是现实场景中的存在于物体之间的边界。有可能有边缘的地方并非边界,也有可能边界的地方并无边缘,因为现实世界中的物体是三维的,而图像只具有二维信息,从三维到二维的投影成像不可避免的会丢失一部分信息;另外,成像过程中的光照和噪声也是不可避免的重要因素。正是因为这些原因,基于边缘的图像分割仍然是当前图像研究中的世界级难题,目前研究者正在试图在边缘提取中加入高层的语义信息。

            在实际的图像分割中,往往只用到一阶和二阶导数,虽然,原理上,可以用更高阶的导数,但是,因为噪声的影响,在纯粹二阶的导数操作中就会出现对噪声的敏感现象,三阶以上的导数信息往往失去了应用价值。二阶导数还可以说明灰度突变的类型。在有些情况下,如灰度变化均匀的图像,只利用一阶导数可能找不到边界,此时二阶导数就能提供很有用的信息。二阶导数对噪声也比较敏感,解决的方法是先对图像进行平滑滤波,消除部分噪声,再进行边缘检测。不过,利用二阶导数信息的算法是基于过零检测的,因此得到的边缘点数比较少,有利于后继的处理和识别工作。

          各种算子的存在就是对这种导数分割原理进行的实例化计算,是为了在计算过程中直接使用的一种计算单位。

    1.Sobel算子

            其主要用于边缘检测,在技术上它是以离散型的差分算子,用来运算图像亮度函数的梯度的近似值, Sobel算子是典型的基于一阶导数的边缘检测算子,由于该算子中引入了类似局部平均的运算,因此对噪声具有平滑作用,能很好的消除噪声的影响。Sobel算子对于象素的位置的影响做了加权,与Prewitt算子、Roberts算子相比因此效果更好。

           Sobel算子包含两组3x3的矩阵,分别为横向及纵向模板,将之与图像作平面卷积,即可分别得出横向及纵向的亮度差分近似值。实际使用中,常用如下两个模板来检测图像边缘。

                           

    检测水平边沿 横向模板 :           检测垂直平边沿 纵向模板:

     

    图像的每一个像素的横向及纵向梯度近似值可用以下的公式结合,来计算梯度的大小。

     

                                                                                 

    然后可用以下公式计算梯度方向。

                                                                               

     

    在以上例子中,如果以上的角度Θ等于零,即代表图像该处拥有纵向边缘,左方较右方暗。

    缺点是Sobel算子并没有将图像的主题与背景严格地区分开来,换言之就是Sobel算子并没有基于图像灰度进行处理,由于Sobel算子并没有严格地模拟人的视觉生理特征,所以提取的图像轮廓有时并不能令人满意。

     

    2. Isotropic Sobel算子

     

            Sobel算子另一种形式是(Isotropic Sobel)算子,加权平均算子,权值反比于邻点与中心点的距离,当沿不同方向检测边缘时梯度幅度一致,就是通常所说的各向同性Sobel(Isotropic Sobel)算子。模板也有两个,一个是检测水平边沿的 ,另一个是检测垂直平边沿的 。各向同性Sobel算子和普通Sobel算子相比,它的位置加权系数更为准确,在检测不同方向的边沿时梯度的幅度一致。

     

    3. Roberts算子

     

    罗伯茨算子、Roberts算子是一种最简单的算子,是一种利用局部差分算子寻找边缘的算子,他采用对角线方向相邻两象素之差近似梯度幅值检测边缘。检测垂直边缘的效果好于斜向边缘,定位精度高,对噪声敏感,无法抑制噪声的影响。1963年,Roberts提出了这种寻找边缘的算子。
    Roberts边缘算子是一个2x2的模板,采用的是对角方向相邻的两个像素之差。从图像处理的实际效果来看,边缘定位较准,对噪声敏感。适用于边缘明显且噪声较少的图像分割。Roberts边缘检测算子是一种利用局部差分算子寻找边缘的算子,Robert算子图像处理后结果边缘不是很平滑。经分析,由于Robert算子通常会在图像边缘附近的区域内产生较宽的响应,故采用上述算子检测的边缘图像常需做细化处理,边缘定位的精度不是很高。

     

     

    4. Prewitt算子

            Prewitt算子是一种一阶微分算子的边缘检测,利用像素点上下、左右邻点的灰度差,在边缘处达到极值检测边缘,去掉部分伪边缘,对噪声具有平滑作用 。其原理是在图像空间利用两个方向模板与图像进行邻域卷积来完成的,这两个方向模板一个检测水平边缘,一个检测垂直边缘。

     对数字图像f(x,y),Prewitt算子的定义如下:

    G(i)=|[f(i-1,j-1)+f(i-1,j)+f(i-1,j+1)]-[f(i+1,j-1)+f(i+1,j)+f(i+1,j+1)]|
    G(j)=|[f(i-1,j+1)+f(i,j+1)+f(i+1,j+1)]-[f(i-1,j-1)+f(i,j-1)+f(i+1,j-1)]|
    则 P(i,j)=max[G(i),G(j)]或 P(i,j)=G(i)+G(j)
    经典Prewitt算子认为:凡灰度新值大于或等于阈值的像素点都是边缘点。即选择适当的阈值T,若P(i,j)≥T,则(i,j)为边缘点,P(i,j)为边缘图像。这种判定是欠合理的,会造成边缘点的误判,因为许多噪声点的灰度值也很大,而且对于幅值较小的边缘点,其边缘反而丢失了。

     

    Prewitt算子对噪声有抑制作用,抑制噪声的原理是通过像素平均,但是像素平均相当于对图像的低通滤波,所以Prewitt算子对边缘的定位不如Roberts算子。

     

    因为平均能减少或消除噪声,Prewitt梯度算子法就是先求平均,再求差分来求梯度。水平和垂直梯度模板分别为:

    检测水平边沿 横向模板                 检测垂直平边沿 纵向模板:

    该算子与Sobel算子类似,只是权值有所变化,但两者实现起来功能还是有差距的,据经验得知Sobel要比Prewitt更能准确检测图像边缘。

     

    5.Laplacian算子

             Laplace算子是一种各向同性算子,二阶微分算子,在只关心边缘的位置而不考虑其周围的象素灰度差值时比较合适。Laplace算子对孤立象素的响应要比对边缘或线的响应要更强烈,因此只适用于无噪声图象。存在噪声情况下,使用Laplacian算子检测边缘之前需要先进行低通滤波。所以,通常的分割算法都是把Laplacian算子和平滑算子结合起来生成一个新的模板。

     

    拉普拉斯算子也是最简单的各向同性微分算子,具有旋转不变性。一个二维图像函数的拉普拉斯变换是各向同性的二阶导数,定义

                                                                               

    了更适合于数字图像处理,将拉式算子表示为离散形式:

    另外,拉普拉斯算子还可以表示成模板的形式,如下图所示,

     

    离散拉普拉斯算子的模板:, 其扩展模板: 。


          拉式算子用来改善因扩散效应的模糊特别有效,因为它符合降制模型。扩散效应是成像过程中经常发生的现象。

          Laplacian算子一般不以其原始形式用于边缘检测,因为其作为一个二阶导数,Laplacian算子对噪声具有无法接受的敏感性;同时其幅值产生算边缘,这是复杂的分割不希望有的结果;最后Laplacian算子不能检测边缘的方向;所以Laplacian在分割中所起的作用包括:(1)利用它的零交叉性质进行边缘定位;(2)确定一个像素是在一条边缘暗的一面还是亮的一面;一般使用的是高斯型拉普拉斯算子(Laplacian of a Gaussian,LoG),由于二阶导数是线性运算,利用LoG卷积一幅图像与首先使用高斯型平滑函数卷积改图像,然后计算所得结果的拉普拉斯是一样的。所以在LoG公式中使用高斯函数的目的就是对图像进行平滑处理,使用Laplacian算子的目的是提供一幅用零交叉确定边缘位置的图像;图像的平滑处理减少了噪声的影响并且它的主要作用还是抵消由Laplacian算子的二阶导数引起的逐渐增加的噪声影响。

    6.Canny算子

          该算子功能比前面几种都要好,但是它实现起来较为麻烦,Canny算子是一个具有滤波,增强,检测的多阶段的优化算子,在进行处理前,Canny算子先利用高斯平滑滤波器来平滑图像以除去噪声,Canny分割算法采用一阶偏导的有限差分来计算梯度幅值和方向,在处理过程中,Canny算子还将经过一个非极大值抑制的过程,最后Canny算子还采用两个阈值来连接边缘。

    Canny边缘检测算法

    step1: 用高斯滤波器平滑图象;

    step2: 用一阶偏导的有限差分来计算梯度的幅值和方向;

    step3: 对梯度幅值进行非极大值抑制

    step4: 用双阈值算法检测和连接边缘


    几种算子的比较
    Robert算子定位比较精确,但由于不包括平滑,所以对于噪声比较敏感。Prewitt算子和Sobel算子都是一阶的微分算子,而前者是平均滤波,后者是加权平均滤波且检测的图像边缘可能大于2个像素。这两者对灰度渐变低噪声的图像有较好的检测效果,但是对于混合多复杂噪声的图像,处理效果就不理想了。LOG滤波器方法通过检测二阶导数过零点来判断边缘点。LOG滤波器中的a正比于低通滤波器的宽度,a越大,平滑作用越显著,去除噪声越好,但图像的细节也损失越大,边缘精度也就越低。所以在边缘定位精度和消除噪声级间存在着矛盾,应该根据具体问题对噪声水平和边缘点定位精度要求适当选取。
    讨论和比较了几种常用的边缘检测算子。梯度算子计算简单,但精度不高,只能检测出图像大致的轮廓,而对于比较细的边缘可能会忽略。Prewitt 和Sobel 算子比Roberts 效果要好一些。LOG 滤波器和Canny 算子的检测效果优于梯度算子,能够检测出图像较细的边缘部分。不同的系统,针对不同的环境条件和要求,选择合适的算子来对图像进行边缘检测。

    Part3:算子代码

    sobel算子MATLAB实现

     

     1 f=imread('D:/picture/ZiXia.jpg');
     2 f=rgb2gray(f);         %转化成灰度图
     3 f=im2double(f);           %函数im2double 将其值归一化到0~1之间
     4 %使用垂直Sobcl箅子.自动选择阈值
     5 [VSFAT Threshold]=edge(f, 'sobel','vertical');                    %边缘探测
     6 figure,imshow(f),title(' 原始图像,');                      %显示原始图像
     7 figure,imshow(VSFAT),title( '垂直图像边缘检测');
     8 %显示边缘探测图像
     9 %使用水平和垂直Sobel算子,自动选择阈值
    10 SFST=edge(f,'sobel',Threshold);
    11 figure,imshow(SFST),title('水平和垂直图像边缘检测');
    12 %显示边缘探测图像
    13 %使用指定45度角Sobel算子滤波器,指定阂值
    14 s45=[-2 -1 0;-1 0 1;0 1 2];
    15 SFST45=imfilter(f,s45,'replicate');%功能:对任意类型数组或多维图像进行滤波。
    16 SFST45=SFST45>=Threshold;
    17 figure,imshow(SFST45),title('45度角图像边缘检测') ;
    18 %显示边缘探测图像 

     

    Roberts算子MATLAB实现

     1 clear all;
     2 clc;
     3 sourcePic=imread('D:/picture/ZiXia.jpg');
     4 grayPic=mat2gray(sourcePic);
     5 [m,n]=size(grayPic);
     6 newGrayPic=grayPic;
     7 robertsNum=0;
     8 robertThreshold=0.2;
     9 for j=1:m-1
    10     for k=1:n-1
    11         robertsNum = abs(grayPic(j,k)-grayPic(j+1,k+1)) + abs(grayPic(j+1,k)-grayPic(j,k+1));
    12         if(robertsNum > robertThreshold)
    13             newGrayPic(j,k)=255;
    14         else
    15             newGrayPic(j,k)=0;
    16         end
    17     end
    18 end
    19 figure,imshow(newGrayPic);
    20 title('roberts算子的处理结果')

     PreWitt边缘算子MATLAB实现

     1 clear;
     2 sourcePic=imread('D:/picture/ZiXia.jpg');
     3 grayPic=mat2gray(sourcePic);
     4 [m,n]=size(grayPic);
     5 newGrayPic=grayPic;
     6 PrewittNum=0;
     7 PrewittThreshold=0.5;%设定阈值
     8 for j=2:m-1 %进行边界提取
     9     for k=2:n-1
    10         PrewittNum=abs(grayPic(j-1,k+1)-grayPic(j+1,k+1)+grayPic(j-1,k)-grayPic(j+1,k)+grayPic(j-1,k-1)-grayPic(j+1,k-1))+abs(grayPic(j-1,k+1)+grayPic(j,k+1)+grayPic(j+1,k+1)-grayPic(j-1,k-1)-grayPic(j,k-1)-grayPic(j+1,k-1));
    11         if(PrewittNum > PrewittThreshold)
    12             newGrayPic(j,k)=255;
    13         else
    14             newGrayPic(j,k)=0;
    15         end
    16     end
    17 end
    18 figure,imshow(newGrayPic);
    19 title('Prewitt算子的处理结果')

    Laplacian边缘算子

     1 clear;
     2 sourcePic=imread('lena.jpg');%图像读入
     3 grayPic=mat2gray(sourcePic);%实现图像的矩阵归一化操作
     4 [m,n]=size(grayPic);
     5 newGrayPic=grayPic;
     6 LaplacianNum=0;%经Laplacian操作得到的每个像素的值
     7 LaplacianThreshold=0.2;%设定阈值
     8 for j=2:m-1 %进行边界提取
     9     for k=2:n-1
    10         LaplacianNum=abs(4*grayPic(j,k)-grayPic(j-1,k)-grayPic(j+1,k)-grayPic(j,k+1)-grayPic(j,k-1));
    11         if(LaplacianNum > LaplacianThreshold)
    12             newGrayPic(j,k)=255;
    13         else
    14             newGrayPic(j,k)=0;
    15         end
    16     end
    17 end
    18 figure,imshow(newGrayPic);
    19 title('Laplacian算子的处理结果')

    canny边缘算子

     

    1 I = imread('D:/picture/ZiXia.jpg');  % 读入图像
    2 I=rgb2gray(I);               % 转化为灰色图像
    3 imshow(I);title('原图')
    4 BW1 = edge(I,'canny');  % 调用canny函数
    5 figure,imshow(BW1);     % 显示分割后的图像,即梯度图像
    6 title('matlab canny')

     使用封装好的函数实现上述算子

     1 image=imread('C:/lenagray.jpg')
     2 image=im2double(image);
     3 image1=edge(image, 'roberts');;
     4 subplot(231);
     5 imshow(image1);
     6 title('roberts算子的处理结果')
     7 image2=imfilter(image,fspecial('prewitt'));
     8 subplot(232);
     9 imshow(image2);
    10 title('Prewitt算子的处理结果')
    11 image3=imfilter(image,fspecial('sobel'));
    12 subplot(233);
    13 imshow(image3);
    14 title('sobel算子的处理结果')
    15 image1=edge(image, 'canny');;
    16 subplot(234);
    17 imshow(image1);
    18 title('canny算子的处理结果')
    19 imfilter(image,fspecial('Laplacian'));
    20 subplot(235);
    21 imshow(image1);
    22 title('Laplacian算子的处理结果')

     

     

    转载于:https://www.cnblogs.com/henuliulei/p/10645109.html

    展开全文
  • 基于主动轮廓模型的沉香显微图像特征提取算法研究,王海丰,张鲲,为了对沉香进行分类识别,提出一种基于沉香显微图像的木纤维分割及特征提取方法。使用主动轮廓模型对沉香显微图像进行轮廓提取,
  • 轮廓跟踪,特征轮廓提取轮廓内部填充

    参考:http://blog.csdn.net/fengbingchun/article/details/6199563

    7.3 

    轮廓提取


    实例如图7.9、图7.10所示。

    数字图像处理笔记2- <wbr>边沿检测与提取,轮廓跟踪(转)

    7.9     原图

    数字图像处理笔记2- <wbr>边沿检测与提取,轮廓跟踪(转)

    7.10   轮廓提取

    轮廓提取的算法非常简单,就是掏空内部点:如果原图中有一点为黑,且它的8个相邻点都是黑色时(此时该点是内部点),则将该点删除。要注意的是,我们处理的虽然是二值图,但实际上是256级灰度图,不过只用到了0255两种颜色。源程序如下:

    BOOL Outline(HWND hWnd)

    {

           DWORD                             OffBits,BufSize;

         LPBITMAPINFOHEADER    lpImgData;

           LPSTR                   lpPtr;

    HLOCAL                             hTempImgData;

           LPBITMAPINFOHEADER    lpTempImgData;

           LPSTR                   lpTempPtr;

           HDC                      hDc;

           HFILE                     hf;

           LONG                    x,y;

           int                                        num;

           int                               nw,n,ne,w,e,sw,s,se;

    //我们处理的实际上是256级灰度图,不过只用到了0255两种颜色。

    if( NumColors!=256){

    MessageBox(hWnd,"Must be a mono bitmap with grayscale palette!",

    "Error Message",MB_OK|MB_ICONEXCLAMATION);

    return FALSE;

    }

    OffBits=bf.bfOffBits-sizeof(BITMAPFILEHEADER);

    //BufSize为缓冲区大小

           BufSize=OffBits+bi.biHeight*LineBytes;

           //为新图缓冲区分配内存

           if((hTempImgData=LocalAlloc(LHND,BufSize))==NULL)

       {

                MessageBox(hWnd,"Error alloc memory!","Error Message",MB_OK|

    MB_ICONEXCLAMATION);

    return FALSE;

        }

         lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData);   

           lpTempImgData=(LPBITMAPINFOHEADER)LocalLock(hTempImgData);

    //拷贝头信息和位图数据

           memcpy(lpTempImgData,lpImgData,BufSize);

           for (y=1;y<bi.biHeight-1;y++){ //注意y的范围是从1到高度-2

                  //lpPtr指向原图数据,lpTempPtr指向新图数据

                  lpPtr=(char *)lpImgData+(BufSize-LineBytes-y*LineBytes);

                  lpTempPtr=(char *)lpTempImgData+(BufSize-LineBytes-y*LineBytes);

                  for (x=1;x<bi.biWidth-1;x++){

                         if(*(lpPtr+x)==0){ //是个黑点

                                //查找八个相邻点

                                nw=(unsigned char)*(lpPtr+x+LineBytes-1);

                                n=(unsigned char)*(lpPtr+x+LineBytes);

                                ne=(unsigned char)*(lpPtr+x+LineBytes+1);

                                w=(unsigned char)*(lpPtr+x-1);

                                e=(unsigned char)*(lpPtr+x+1);

                                sw=(unsigned char)*(lpPtr+x-LineBytes-1);

                                s=(unsigned char)*(lpPtr+x-LineBytes);

                                se=(unsigned char)*(lpPtr+x-LineBytes+1);

                                num=nw+n+ne+w+e+sw+s+se;

                                if(num==0) //说明都是黑点

                                       *(lpTempPtr+x)=(unsigned char)255; //删除该黑点

                         }

                  }

           }

         if(hBitmap!=NULL)

               DeleteObject(hBitmap);

           hDc=GetDC(hWnd);    

           //创立一个新的位图

           hBitmap=CreateDIBitmap(hDc,(LPBITMAPINFOHEADER)lpTempImgData,

    (LONG)CBM_INIT,

    (LPSTR)lpTempImgData+

    sizeof(BITMAPINFOHEADER)+

    NumColors*sizeof(RGBQUAD),

    (LPBITMAPINFO)lpTempImgData,

    DIB_RGB_COLORS);

    hf=_lcreat("c://outline.bmp",0);

           _lwrite(hf,(LPSTR)&bf,sizeof(BITMAPFILEHEADER));

           _lwrite(hf,(LPSTR)lpTempImgData,BufSize);

           _lclose(hf);

           //释放内存和资源

          ReleaseDC(hWnd,hDc);

           LocalUnlock(hTempImgData);

           LocalFree(hTempImgData);

           GlobalUnlock(hImgData);

           return TRUE;

    }

    7.4 种子填充

    种子填充

    种子填充算法用来在封闭曲线形成的环中填充某中颜色,在这里我们只填充黑色。

    种子填充其实上是图形学中的算法,其原理是:准备一个堆栈,先将要填充的点push进堆栈中;以后,每pop出一个点,将该点涂成黑色,然后按左上右下的顺序查看它的四个相邻点,若为白(表示还没有填充),则将该邻点push进栈。一直循环,直到堆栈为空。此时,区域内所有的点都被涂成了黑色。

    这里,我们自己定义了一些堆栈的数据结构和操作,实现了堆栈的初始化、pushpop、判断是否为空、及析构。

    //堆栈结构

    typedef struct{

                    HGLOBAL hMem; //堆栈全局内存句柄

                   POINT *lpMyStack; //指向该句柄的指针

                    LONG  ElementsNum; //堆栈的大小

                    LONG  ptr; //指向栈顶的指针

                    }MYSTACK;

    //初始化堆栈的操作,第二个参数指定堆栈的大小

    BOOL InitStack(HWND hWnd,LONG StackLen)

    {

           SeedFillStack.ElementsNum=StackLen; //将堆栈的大小赋值

           if((SeedFillStack.hMem=GlobalAlloc(GHND,SeedFillStack.ElementsNum*

    sizeof(POINT)))==NULL)

           {

                  //内存分配错误,返回FALSE;

         MessageBox(hWnd,"Error alloc memory!","ErrorMessage",MB_OK|

    MB_ICONEXCLAMATION);

                  return FALSE;

           }

           SeedFillStack.lpMyStack=(POINT *)GlobalLock(SeedFillStack.hMem);

           //缓冲区全部清零

    memset(SeedFillStack.lpMyStack,0,SeedFillStack.ElementsNum*

    sizeof(POINT));

    //堆顶指针为零

           SeedFillStack.ptr=0;

           //成功,返回TRUE

           return TRUE;

    }

    //析构函数

    void DeInitStack()

    {

           //释放内存,重置堆栈大小及栈顶指针。

           GlobalUnlock(SeedFillStack.hMem);

           GlobalFree(SeedFillStack.hMem);

           SeedFillStack.ElementsNum=0;

           SeedFillStack.ptr=0;

    }

    //push操作

    BOOL MyPush(POINT p)

    {

           POINT *TempPtr;

           if(SeedFillStack.ptr>=SeedFillStack.ElementsNum)

                  return FALSE; //栈已满,返回FALSE

           //进栈,栈顶指针加1

           TempPtr=(POINT *)(SeedFillStack.lpMyStack+SeedFillStack.ptr++);

           (*TempPtr).x=p.x;

           (*TempPtr).y=p.y;

           return TRUE;

    }

    //pop操作

    POINT MyPop()

    {

           POINT InvalidP;

           InvalidP.x=-1;

           InvalidP.y=-1;

           if(SeedFillStack.ptr<=0)

                  return InvalidP; //栈为空,返回无效点

           SeedFillStack.ptr--; //栈顶指针减1

           //返回栈顶点

           return *(SeedFillStack.lpMyStack+SeedFillStack.ptr);

    }

    //判断堆栈是否为空

    BOOL IsStackEmpty()

    {

           return (SeedFillStack.ptr==0)?TRUE:FALSE;

    }

    如果读者对堆栈的概念还不清楚,请参阅有关数据结构方面的书籍,这里就不详述了。

    要注意的是:(1)要填充的区域是封闭的;(2)我们处理的虽然是二值图,但实际上是256级灰度图,不过只用到了0255两种颜色;(3)在菜单中选择种子填充命令时,提示用户用鼠标点取一个要填充区域中的点,处理是在WM_LBUTTONDOWN中。

    MYSTACK SeedFillStack;

    BOOL SeedFill(HWND hWnd)

    {

    DWORD                   OffBits,BufSize;

         LPBITMAPINFOHEADER    lpImgData;

           HLOCAL                  hTempImgData;

           LPBITMAPINFOHEADER    lpTempImgData;

           LPSTR                   lpTempPtr,lpTempPtr1;

           HDC                                      hDc;

           HFILE                    hf;

           POINT                   CurP,NeighborP;

    //我们处理的实际上是256级灰度图,不过只用到了0255两种颜色。

           if( NumColors!=256){

    MessageBox(hWnd,"Must be a mono bitmap with grayscale palette!",

    "Error Message",MB_OK|MB_ICONEXCLAMATION);

    return FALSE;

    }

    OffBits=bf.bfOffBits-sizeof(BITMAPFILEHEADER);

    //BufSize为缓冲区大小

           BufSize=OffBits+bi.biHeight*LineBytes;

    //为新图缓冲区分配内存

           if((hTempImgData=LocalAlloc(LHND,BufSize))==NULL)

       {

                MessageBox(hWnd,"Error alloc memory!","Error Message",MB_OK|

    MB_ICONEXCLAMATION);

    return FALSE;

        }

         lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData);   

           lpTempImgData=(LPBITMAPINFOHEADER)LocalLock(hTempImgData);

    //拷贝头信息和位图数据

           memcpy(lpTempImgData,lpImgData,BufSize);

           if(!InitStack(hWnd,(LONG)bi.biHeight*bi.biWidth)){  //初始化堆栈

                  //若失败,释放内存,返回

                  LocalUnlock(hTempImgData);

                  LocalFree(hTempImgData);

                  GlobalUnlock(hImgData);

                  return FALSE;

           }

           lpTempPtr=(char*)lpTempImgData+

    (BufSize-LineBytes-SeedPoint.y*LineBytes)+SeedPoint.x;

           if(*lpTempPtr==0){

                  //鼠标点到了黑点上,提示用户不能选择边界上的点,返回FALSE

    MessageBox(hWnd,"The point you select is a contour point!",

    "Error Message",MB_OK|MB_ICONEXCLAMATION);

                  LocalUnlock(hTempImgData);

                  LocalFree(hTempImgData);

                  GlobalUnlock(hImgData);

                  DeInitStack();

    return FALSE;

           }

           //push该点(用户用鼠标选择的,处理是在WM_LBUTTONDOWN

           MyPush(SeedPoint);

           while(!IsStackEmpty()) //堆栈不空则一直处理

           {

                  CurP=MyPop(); //pop栈顶的点

                  lpTempPtr=(char*)lpTempImgData+

    (BufSize-LineBytes-CurP.y*LineBytes)+CurP.x;

                  //将该点涂黑

                  *lpTempPtr=(unsigned char)0;

                  //左邻点

                  if(CurP.x>0) //注意判断边界

                  {

                         NeighborP.x=CurP.x-1;

                         NeighborP.y=CurP.y;

                         lpTempPtr1=lpTempPtr-1;

                         if(*lpTempPtr1!=0) //如果为白,表示还没有填,进栈

                                MyPush(NeighborP);

                  }

    //上邻点

                  if(CurP.y>0) //注意判断边界

                  {

                         NeighborP.x=CurP.x;

                         NeighborP.y=CurP.y-1;

                         lpTempPtr1=lpTempPtr+LineBytes;

                         if(*lpTempPtr1!=0) //如果为白,表示还没有填,进栈

                                MyPush(NeighborP);

                  }

    //右邻点

                  if(CurP.x<bi.biWidth-1) //注意判断边界

                  {

                         NeighborP.x=CurP.x+1;

                         NeighborP.y=CurP.y;

                         lpTempPtr1=lpTempPtr+1;

                         if(*lpTempPtr1!=0) //如果为白,表示还没有填,进栈

                                MyPush(NeighborP);

                  }

                  //下邻点

                  if(CurP.y<bi.biHeight-1) //注意判断边界

                  {

                         NeighborP.x=CurP.x;

                         NeighborP.y=CurP.y+1;

                         lpTempPtr1=lpTempPtr-LineBytes;

                         if(*lpTempPtr1!=0) //如果为白,表示还没有填,进栈

                                MyPush(NeighborP);

                  }

           }

           //析构堆栈,释放内存

           DeInitStack();

    if(hBitmap!=NULL)

               DeleteObject(hBitmap);

           hDc=GetDC(hWnd);    

           //创建新的位图

           hBitmap=CreateDIBitmap(hDc,(LPBITMAPINFOHEADER)lpTempImgData,

    (LONG)CBM_INIT,

    (LPSTR)lpTempImgData+

    sizeof(BITMAPINFOHEADER)+

    NumColors*sizeof(RGBQUAD),

    (LPBITMAPINFO)lpTempImgData,

    DIB_RGB_COLORS);

           hf=_lcreat("c://seed.bmp",0);

           _lwrite(hf,(LPSTR)&bf,sizeof(BITMAPFILEHEADER));

           _lwrite(hf,(LPSTR)lpTempImgData,BufSize);

           _lclose(hf);

           //释放内存和资源

          ReleaseDC(hWnd,hDc);

           LocalUnlock(hTempImgData);

           LocalFree(hTempImgData);

           GlobalUnlock(hImgData);

           return TRUE;

    }

    7.5 轮廓跟踪

    外轮廓跟踪

    轮廓跟踪,顾名思义就是通过顺序找出边缘点来跟踪出边界。图7.9经轮廓跟踪后得到的结果如图7.11所示。

    数字图像处理笔记2- <wbr>边沿检测与提取,轮廓跟踪(转)

    7.11    7.9轮廓跟踪后的结果

    一个简单二值图象闭合边界的轮廓跟踪算法很简单:首先按从上到下,从左到右的顺序搜索,找到的第一个黑点一定是最左上方的边界点,记为A。它的右,右下,下,左下四个邻点中至少有一个是边界点,记为B。从开始B找起,按右,右下,下,左下,左,左上,上,右上的顺序找相邻点中的边界点C。如果C就是A点,则表明已经转了一圈,程序结束;否则从C点继续找,直到找到A为止。判断是不是边界点很容易:如果它的上下左右四个邻居都是黑点则不是边界点,否则是边界点。源程序如下,其中函数IsContourP用来判断某点是不是边界点。

    BOOL Contour(HWND hWnd)

    {

           DWORD                             OffBitsBufSize;

    LPBITMAPINFOHEADER    lpImgData;

           LPSTR                   lpPtr;

           HLOCAL                  hTempImgData;

           LPBITMAPINFOHEADER    lpTempImgData;

           LPSTR                   lpTempPtr;

           HDC                      hDc;

           HFILE                    hf;

           LONG                    x,y;

           POINT                   StartP,CurP;

           BOOL                     found;

           int                        i;

    int       direct[8][2]={{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1},{0,-1},{1,-1}};

    //我们处理的实际上是256级灰度图,不过只用到了0255两种颜色。

           if( NumColors!=256){

    MessageBox(hWnd,"Must be a mono bitmap with grayscale palette!",

    "Error Message",MB_OK|MB_ICONEXCLAMATION);

    return FALSE;

    }

    //到位图数据的偏移值

           OffBits=bf.bfOffBits-sizeof(BITMAPFILEHEADER);

           //缓冲区大小

    BufSize=OffBits+bi.biHeight*LineBytes;

    //为新图缓冲区分配内存

           if((hTempImgData=LocalAlloc(LHND,BufSize))==NULL)

         {

           MessageBox(hWnd,"Error alloc memory!","Error Message",

    MB_OK|MB_ICONEXCLAMATION);

    return FALSE;

    }

          lpImgData=(LPBITMAPINFOHEADER)GlobalLock(hImgData);

           lpTempImgData=(LPBITMAPINFOHEADER)LocalLock(hTempImgData);

           //新图缓冲区初始化为255

           memset(lpTempImgData,(BYTE)255,BufSize);

           //拷贝头信息

           memcpy(lpTempImgData,lpImgData,OffBits);

           //找到标志置为假

           found=FALSE;

           for (y=0;y<bi.biHeight && !found; y++){

                  lpPtr=(char *)lpImgData+(BufSize-LineBytes-y*LineBytes);

                  for (x=0;x<bi.biWidth && !found; x++)

                         if (*(lpPtr++) ==0) found=TRUE;

    //找到了最左上的黑点,一定是个边界点

           }

           if(found){ //如果找到了,才做处理

    //从循环退出时,xy坐标都做了加1的操作。在这里把它们减1,得到

    //起始点坐标StartP

                  StartP.x=x-1;

                  StartP.y=y-1;

                  lpTempPtr=(char*)lpTempImgData+

    (BufSize-LineBytes-StartP.y*LineBytes)+StartP.x;

                  *lpTempPtr=(unsigned char)0; //起始点涂黑

                  //右邻点

                CurP.x=StartP.x+1;

                  CurP.y=StartP.y;

                  lpPtr=(char *)lpImgData+(BufSize-LineBytes-CurP.y*LineBytes)+CurP.x;

                  if(*lpPtr!=0){ //若右邻点为白,则找右下邻点

                       CurP.x=StartP.x+1;

                         CurP.y=StartP.y+1;

                         lpPtr=(char*)lpImgData+

    (BufSize-LineBytes-CurP.y*LineBytes)+CurP.x;

                         if(*lpPtr!=0){ //若仍为白,则找下邻点

                              CurP.x=StartP.x;

                                CurP.y=StartP.y+1;

                         }

                         else{ //若仍为白,则找左下邻点

                              CurP.x=StartP.x-1;

                                CurP.y=StartP.y+1;

                         }

                  }

                  while (! ( (CurP.x==StartP.x) &&(CurP.y==StartP.y))){ //知道找到起始点,

    //循环才结束

                         lpTempPtr=(char*)lpTempImgData+

    (BufSize-LineBytes-CurP.y*LineBytes)+CurP.x;

                         *lpTempPtr=(unsigned char)0;

                         for(i=0;i<8;i++){

    //按右,右上,上,左上,左,左下,下,右下的顺序找相邻点

    //direct[i]中存放的是该方向x,y的偏移值

                                x=CurP.x+direct[i][0];

                                y=CurP.y+direct[i][1];

                  //lpPtr指向原图数据,lpTempPtr指向新图数据

                                lpTempPtr=(char*)lpTempImgData+

    (BufSize-LineBytes-y*LineBytes)+x;

                                lpPtr=(char *)lpImgData+(BufSize-LineBytes-y*LineBytes)+x;

                                if(((*lpPtr==0)&&(*lpTempPtr!=0))||

    ((x==StartP.x)&&(y==StartP.y)))

                                //原图中为黑点,且新图中为白点(表示还没搜索过)时才处理

                                //另一种可能是找到了起始点

                                       if(IsContourP(x,y,lpPtr)){ //若是个边界点

                                              //记住当前点的位置

                                CurP.x=x;

                                              CurP.y=y;

                                              break;

                                       }

                         }

                  }

           }

        if(hBitmap!=NULL)

               DeleteObject(hBitmap);

           hDc=GetDC(hWnd);

           //创立一个新的位图

           hBitmap=CreateDIBitmap(hDc,(LPBITMAPINFOHEADER)lpTempImgData,

    (LONG)CBM_INIT,

    (LPSTR)lpTempImgData+

    sizeof(BITMAPINFOHEADER)+

    NumColors*sizeof(RGBQUAD),

                                      (LPBITMAPINFO)lpTempImgData,

    DIB_RGB_COLORS);

           hf=_lcreat("c://contour.bmp",0);

           _lwrite(hf,(LPSTR)&bf,sizeof(BITMAPFILEHEADER));

           _lwrite(hf,(LPSTR)lpTempImgData,BufSize);

           _lclose(hf);

           //释放内存和资源

          ReleaseDC(hWnd,hDc);

           LocalUnlock(hTempImgData);

           LocalFree(hTempImgData);

           GlobalUnlock(hImgData);

           return TRUE;

    }

    //判断某点是不是边界点,参数x,y 为该点坐标,lpPtr为指向原数据的指针

    BOOL IsContourP(LONG x,LONG y, char *lpPtr)

    {

           int    num,n,w,e,s;

           n=(unsigned char)*(lpPtr+LineBytes); //上邻点

           w=(unsigned char)*(lpPtr-1); //左邻点

           e=(unsigned char)*(lpPtr+1); //右邻点

           s=(unsigned char)*(lpPtr-LineBytes); //下邻点

           num=n+w+e+s;

           if(num==0) //全是黑点,说明是个内部点而不是边界点

                  return FALSE;

           return TRUE;

    }

    展开全文
  •  轮廓可以说是一个很好的图像目标的外部特征,这种特征对于我们进行图像分析,目标识别和理解等更深层次的处理都有很重要的意义。那么,怎么取提取轮廓呢? 轮廓提取的基本原理:  (针对二值化的轮廓提取是这样...
  • 图像的边沿特征提取轮廓跟踪,不下是你的错,很好用
  • 通过对叶片图像预处理得到叶片的轮廓曲线、结合基于链码的拐点检测方法和基于链码差的边界凹凸性判别方法确定锯齿点和叶裂点、改进基于链码的目标面积计算方法计算锯齿和叶裂的面积。从锯齿和叶裂的面积和周长占整个...
  • 针对严重滑动磨粒、疲劳剥块和层状磨粒等磨粒的图像识别问题, 提出了基于形状标记和双谱分析的图像形状特征提取方法. 首先根据中心距离函数、累积角函数、最远点距离函数和三角形区域表示等4种形状标记方法, 将二维...
  • 针对传统轮廓提取方法对建筑物立面图像处理存在的处理耗时问题,提出一种结合视觉显著模型与水平集算法的建筑物立面轮廓提取算法。通过视觉显著特征与超像素分块信息滤除大量无关背景;对所得的显著分块,以超像素...
  • 基于MSTAR项目的真实SAR图像的实验结果表明,本文所提出的方法能准确地获得SAR图像目标轮廓,可用于执行实际的SAR图像轮廓提取任务,为后续的SAR图像自动识别和特征级图像融合等任务提供了较为优良的输入信息。
  • 图像特征提取

    千次阅读 2017-04-06 17:25:50
    图像特征提取 1) 图像的边缘检测:是指灰度急剧变化的那些像素的集合,它是图像最基本的特征。边缘检测的基本思想是先检测图像中的边缘点,再按照某种测率将边缘点连接起轮廓,从而构成分割区域。 2) Canny...
  • 快速,准确提取图像特征线即轮廓,并能保存下特征点坐标
  • 图像底层特征提取是计算机视觉的基本步骤 1:边缘和轮廓能反映图像内容; 2:如果能对边缘和关键点可靠提取的话,很多视觉问题就基本上得到了解决边缘的定义 “边缘是图像中亮度突然变化的区域。” “图像灰度构成...
  • 图像拼接1 特征提取

    2018-01-05 20:03:00
    图像特征提取图像拼接中占据至关重要的地位,旨在从图像中提取显著特征并用数学语言加以描述。 图像特征包括:特征点、边缘、轮廓、闭合区域以及统计特征等。 一般来说,特征点是指图像中具有某些特性的结构特征...
  • 图像特征提取

    2019-09-29 14:27:35
    方向梯度直方图(Histogram of Oriented Gradient, HOG)特征是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子。它通过计算和统计图像局部区域的梯度方向直方图来构成特征。Hog特征结合SVM分类器已经被...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 810
精华内容 324
关键字:

图像轮廓特征提取