• 边缘检测算法


     图像边缘的种类可以分为两种:一种称为阶跃性边缘,它两边像素的灰度值有着显著的不同;另一种称为屋顶状边缘,它位于灰度值从增加到减少的变化转折点。对于阶跃性边缘,二阶方向导数在边缘处呈零交叉;而对于屋顶状边缘,二阶导数在边缘处取极值。通常的边缘提取方法是先通过边缘算子找到图像中可能的边缘点,再把这些点连接起来形成封闭的边界。边缘检测困难在于物体之间相接触、互遮挡或者由于噪声等原因引起的边缘间断。

    其中susan和canny算法我用过,可以结合两种算法的结果使用...

    1.susan算子
    SUSAN算子是一种基于图像局部灰度特征的算法,利用一个圆形的模板对图像进行扫描,比较模板内部的点与模板中心点的灰度值,如果灰度差值小于一定的阈值,就认为该点与中心点的灰度相同。统计模板内部与中心点灰度相同的点的个数,与一个阈值进行比较,判断该点是否属于某个区域的边缘点,从而实现对图像的分割。
    //-----------------------------------------------------------------------
    //c/c++描述

    HDIB SUSANEdgeDetectDIB(HDIB hDib){
    SetCursor(LoadCursor(NULL, IDC_WAIT));

    DWORD dwDataLength = GlobalSize(hDib);
    HDIB hNewDib = GlobalAlloc(GHND,dwDataLength);
    if(!hNewDib){
    SetCursor(LoadCursor(NULL, IDC_ARROW));
    return NULL;
    }
    LPBYTE lpDIB = (LPBYTE)GlobalLock(hNewDib);
    if(lpDIB == NULL){
    SetCursor(LoadCursor(NULL, IDC_ARROW));
    return NULL;
    }

    LPBYTE lpDIBSrc = (LPBYTE)GlobalLock(hDib);

    memcpy(lpDIB, lpDIBSrc,
    sizeof(BITMAPINFOHEADER)+PaletteSize(lpDIBSrc));

    DWORD lSrcWidth = DIBWidth(lpDIBSrc);
    DWORD lSrcHeight = DIBHeight(lpDIBSrc);
    WORD wBitCount =((LPBITMAPINFOHEADER)lpDIBSrc)->biBitCount;
    DWORD lSrcRowBytes =WIDTHBYTES(lSrcWidth*((DWORD)wBitCount));
    LPBYTE lpOldBits = FindDIBBits(lpDIBSrc);
    LPBYTE lpData = FindDIBBits(lpDIB);

    //图像变换开始//////////////////////////////////////////
    DWORD i, j, h, k, offset;
    int NearPoint[37];
    int OffSetX[37] = { -1, 0, 1,
    -2,-1, 0, 1, 2,
    -3,-2,-1, 0, 1, 2, 3,
    -3,-2,-1, 0, 1, 2, 3,
    -3,-2,-1, 0, 1, 2, 3,
    -2,-1, 0, 1, 2,
    -1, 0, 1 };
    int OffSetY[37] = { -3,-3,-3,
    -2,-2,-2,-2,-2,
    -1,-1,-1,-1,-1,-1,-1,
    0, 0, 0, 0, 0, 0, 0,
    1, 1, 1, 1, 1, 1, 1,
    2, 2, 2, 2, 2,
    3, 3, 3 };

    if(wBitCount == 8){
    int thre, same, max, min;

    //统计象素亮度最大值和最小值
    max = min = 0;
    for(i=0;i<lSrcHeight;i++)
    for(j=0;j<lSrcWidth;j++){
    offset = lSrcRowBytes*i+j;
    if(max < (int)(*(lpOldBits+offset)))
    max = (int)(*(lpOldBits+offset));
    if(min > (int)(*(lpOldBits+offset)))
    min = (int)(*(lpOldBits+offset));
    }

    //相似度阈值为最大值和最小值差的1/10
    thre = (max-min)/10;

    for(i=3;i<lSrcHeight-3;i++)
    for(j=3;j<lSrcWidth-3;j++){
    //统计圆形邻域内相似的点的个数
    same = 0;
    for(h=0;h<37;h++)
    NearPoint[h] =(int)(*(lpOldBits+lSrcRowBytes*(i+OffSetY[h])+(j+OffSetX[h])));
    for(h=0;h<37;h++)
    if(((int)abs(NearPoint[h]-NearPoint[18])) <= thre) same++;

    if(same > 27)
    *(lpData+lSrcRowBytes*i+j) = 255;
    else *(lpData+lSrcRowBytes*i+j) = 0;
    }
    }

    if(wBitCount == 24){
    int theSame[3], theMax[3], theMin[3], theThre[3];

    memset(theMax, 0, sizeof(int)*3);
    memset(theMin, 0, sizeof(int)*3);
    for(i=0;i<lSrcHeight;i++)
    for(j=0;j<lSrcWidth;j++){
    offset = lSrcRowBytes*i+j*3;
    for(k=0;k<3;k++){
    if(theMax[k] < (int)(*(lpOldBits+offset+k)))
    theMax[k] = (int)(*(lpOldBits+offset+k));
    if(theMin[k] > (int)(*(lpOldBits+offset+k)))
    theMin[k] = (int)(*(lpOldBits+offset+k));
    }
    }

    for(k=0;k<3;k++)
    theThre[k] = (theMax[k]-theMin[k])/10;

    for(i=3;i<lSrcHeight-3;i++)
    for(j=3;j<lSrcWidth-3;j++){
    memset(theSame, 0, sizeof(int)*3);
    for(k=0;k<3;k++){
    for(h=0;h<37;h++)
    NearPoint[h] =(int)(*(lpOldBits+lSrcRowBytes*(i+OffSetY[h])+(j+OffSetX[h])*3+k));
    for(h=0;h<37;h++)
    if(((int)abs(NearPoint[h]-NearPoint[18])) <= theThre[k])theSame[k] ++;
    }

    if((theSame[0] > 27) && (theSame[1] > 27) &&(theSame[2] > 27))
    memset(lpData+lSrcRowBytes*i+j*3, 255, 3);
    else
    memset(lpData+lSrcRowBytes*i+j*3, 0, 3);
    }
    }

    GlobalUnlock(hDib);
    GlobalUnlock(hNewDib);
    SetCursor(LoadCursor(NULL, IDC_ARROW));

    return hNewDib;
    }


    2.canny算子
    Canny边缘检测基本原理
    (1)图象边缘检测必须满足两个条件:一能有效地抑制噪声;二必须尽量精确确定边缘的位置。
    (2)根据对信噪比与定位乘积进行测度,得到最优化逼近算子。这就是Canny边缘检测算子。
    (3)类似与Marr(LoG)边缘检测方法,也属于先平滑后求导数的方法。

    算法比较内容比较多,有需要的朋友可以到这儿看(http://www.pcdog.com/edu/develop-tools/2005/08/f067918.html).

    3.sobel算子

    Sobel 算子有两个,一个是检测水平边沿的 ;另一个是检测垂直平边沿的。与 和相比,Sobel算子对于象素的位置的影响做了加权,因此效果更好。
    Sobel 算子另一种形式是各向同性Sobel(IsotropicSobel)算子,也有两个,一个是检测水平边沿的,另一个是检测垂直平边沿的。各向同性Sobel算子和普通Sobel算子相比,它的位置加权系数更为准确,在检测不同方向的边沿时梯度的幅度一致。由于建筑物图像的特殊性,我们可以发现,处理该类型图像轮廓时,并不需要对梯度方向进行运算,所以程序并没有给出各向同性Sobel算子的处理方法。
    由于Sobel算子是滤波算子的形式,用于提”咴担可以利用快速卷积函数,简单有效,因此应用广泛。美中不足的是,Sobel算子并没有将图像的主体与背景严格地区分开来,换言之就是Sobel算子没有基于图像灰度进行处理,由于Sobel算子没有严格地模拟人的视觉生理特征,所以提取的图像轮廓有时并不能令人满意。在观测一幅图像的时候,我们往往首先注意的是图像与背景不同的部分,正是这个部分将主体突出显示,基于该理论,我们给出了下面阈值化轮廓提取算法,该算法已在数学上证明当像素点满足正态分布时所求解是最优的。

    /// <summary>
    /// 按 Sobel 算子进行边缘检测
    /// </summary>
    /// <param name="b">位图流</param>
    /// <returns></returns>
    public Bitmap Sobel(Bitmap b)
    {
    Matrix3x3 m = new Matrix3x3();

    // -1 -2 -1
    // 0 0 0
    // 1 2 1
    m.Init(0);
    m.TopLeft = m.TopRight = -1;
    m.BottomLeft = m.BottomRight = 1;
    m.TopMid = -2;
    m.BottomMid = 2;
    Bitmap b1 = m.Convolute((Bitmap)b.Clone());

    // -1 0 1
    // -2 0 2
    // -1 0 1
    m.Init(0);
    m.TopLeft = m.BottomLeft = -1;
    m.TopRight = m.BottomRight = 1;
    m.MidLeft = -2;
    m.MidRight = 2;
    Bitmap b2 = m.Convolute((Bitmap)b.Clone());

    // 0 1 2
    // -1 0 1
    // -2 -1 0
    m.Init(0);
    m.TopMid = m.MidRight = 1;
    m.MidLeft = m.BottomMid = -1;
    m.TopRight = 2;
    m.BottomLeft = -2;
    Bitmap b3 = m.Convolute((Bitmap)b.Clone());

    // -2 -1 0
    // -1 0 1
    // 0 1 2
    m.Init(0);
    m.TopMid = m.MidLeft = -1;
    m.MidRight = m.BottomMid = 1;
    m.TopLeft = -2;
    m.BottomRight = 2;
    Bitmap b4 = m.Convolute((Bitmap)b.Clone());

    // 梯度运算
    b = Gradient(Gradient(b1, b2), Gradient(b3, b4));

    b1.Dispose(); b2.Dispose(); b3.Dispose(); b4.Dispose();

    return b;
    } // end of Sobel


    4.还有Laplace,Gobar,Roberts等等... 没有详细了解过,也不介绍了.

    csdn提供的边缘检测算法源代码,有需要的可以去下载看看:
    http://download.csdn.net/source/150053
  • 相关阅读:
    Dynamic 365 中创建编码规则
    程序员和产品经理之间的恩怨情仇
    Scrum已经俘获中国开发者的心? ——从《2017年开发者调查报告》看真相!
    不懂营销的产品经理不是好的产品经理
    关于程序猿之间丧心病狂的鄙视链——编辑器篇
    国内五款好用的开源建站系统
    程序员听到bug后的N种反应,太形象了
    功能至上!国内外最实用的协作类软件盘点
    关于程序员之间丧心病狂的鄙视链——编程语言篇
    结对编程体会
  • 原文地址:https://www.cnblogs.com/feisky/p/1586637.html
Copyright © 2020-2023  润新知