zoukankan      html  css  js  c++  java
  • Hough变换在opencv中的应用

    霍夫曼变换(Hough Transform)的原理

    霍夫曼变换是一种可以检测出某种特殊形状的算法,OpenCV中用霍夫曼变换来检测出图像中的直线、椭圆和其他几何图形。由它改进的算法,可以用来检测任何形状的图形。

    传统Hough变换 : 枚举统计法

    找到通过足够多数量的像素点的所有直线,它分析每个单独的像素,并识别出所有的可能经过它的直线。

    当同一条直线穿过许多点,便意味着这条线的存在足够明显。

    累加器


    累加器就是用来记录某条直线被识别了多少次,霍夫曼最直接的想法是,计算所有可能的直线,找出重复数量最多的那几条,重复次数就是识别的阈值。

    演算步骤

    Hough transform演算步骤(以直线为例):

    直线公式: y = ax – b

    称(x,y)为图像空间的坐标,(a,b)为参数空间

    1. 在图像上找出所有可能的特征点
    2. 对于每个特征点
        1. 对于每个a,计算通过(x,y)的所有直线(a,b)     
        2. 在累加器的(a,b)位置上加一
        
       重复步骤2,直到所有的特征点都计算完毕
    1. 找到累加器里的最大值
    2. 将每一个极大值,映射回图片上代表的每一条直线

    极坐标


    OpenCV实际采用的是极坐标(r,s),以左上角为原点:

        r = xcos(s) + ysin(s)
        
    代码:

     

    // 选择特征点 (x, y)
    int x = 50, y = 30;
    // 计算通过它的所有直线
    for(inti = 0; i < 180; i++) {
        double s = i * PI/180. ;
        double r = x*cos(s) + y*sin(s);
        // j对应的r从 -100 到 100
        int j = static_cast<int>(r + 100.5);
         
        std::cout << i << ","<<j<<std::endl;
        // 填入累加器,极坐标 (j代表r,i代表s)
        acc.at<uchar>(j,i)++;
    }

    性能


    由上面的数学原理可知,Hough转换是一个运算耗时,需要大量内存的算法

     

    概率Hough变换

    为了改进原算法,提出了一个优化方案,即概率霍夫曼变换
    在原算法的基础上做了少许的修改

    1. 不再逐行扫描像素点,而是随机挑选
    2. 某个直线达到投票值后,扫描并移除所有经过的点,这次扫描结束后还可以得到线段长度
    3. 增加两个参数:线段最小长度、组成连续线段的最大像素间隔

    算法复杂度增加,但是参与投票的像素点少了,补偿了整个算法的复杂度。

    检测其他几何体

    霍夫曼变换也可用于检测其他几何体,事实上只要是可以用参数方程表示的东西都可以用Hough进行检测

    检测圆形

    r^2 = (x – a)^2 + (y – b)^2

    方程有3个参数,需要3维累加器,如同直线检测:

     

    // 对某个特征点 (怎么选择是一种优化)
    int x, y;
    for(a = 0; a < max_a; a++)
        for(b = 0; b < max_b; b++)
        {
            r = (int)sqrt((x-a)*(x-a) + (y-b)*(y-b));
            if(r > 0 && r < max_r)
                acc.at<uchar>(a, b, r)++;
        }

    维度变高后,复杂度和可靠度都会变坏,因为精确定位局部峰值变的困难了,OpenCV做了优化,比如只增加圆环梯度方向上的累加器,对结果求直方图而非极值,峰值对应的是检测到的园的半径


    广义霍夫曼变换


    虽然很难用参数表示一些形状,但原理是相同的:创建一个累加器,用来表示所有可能在目标形状上的位置
    为了检测无法被参数化的(没有解析模型)不规则形状泛化Hough变换被提出,Generalized Hough Transform(GHT)
    广义hough变换,如果再考虑旋转和缩放就需要在更高维度上搜索.

    5个参数表示

    定义任意形状的表示参数:

    X,Y,r,s,a,thea,其中,XY为形状内的一个参考点,s是缩放因子,thea是方向

    分为两大步AB


    A:计算R-table

    计算R-Table,r是到原点的距离,a是梯度与x轴的夹角(0-180),%代表该点切线(梯度垂直)方向与X轴的夹角
        
    r-table是r-table[%] = (r,a),(r',a')

    %1 : (r1, a1), (r1',a1')

    %2 : (r2, a2), (r2', a2')

    … : …

    %n : (rn, an), (rn', an')

    1. 选取参考点(xc,yc)
    2. 初始化R-table为空
    3. 对每个边缘点,计算(r,a)值
       1. r = sqrt((x-xc)^2 + (y-yc)^2)
       1. a = tan'((y-yc)/(x-xc))
    4. 计算%(切线),并将(r,a)加入与%最接近的%i
    5. 重复4、5,直到所有的边缘点都已经加入R-table

    B:形状检测


    1. 建立2维的hough table H(xc, yc),初始化为0
    2. 针对每一个边缘点,计算切线(垂直梯度)夹角%
    3. 在R-table中,查找最接近%的%i,对其内的所有(r,a),计算对应的原点(xc,yc)
        
        xc = x + rcos(a)
        
        yc = y + rsin(a)
        
    4.     将H(xc, yc)累加1,重复2、3,直到所有的边缘点都完成检测
    5.     找出H(xc,yc)中的局部最大值,其(xc,yc)即为检测出来的形状

    考虑旋转和缩放


    上面的过程没考虑旋转thea和缩放因子,考虑内的H变为

    H(xc, yc, thea, s)

    B中的3步骤改为

        xc = x + r.Scos(a + thea)
        yc = y + r.Ssin(a + thea)

    问题

    GHT占用内存大,计算复杂,单匹配固定形状的精度高,也许在未来能有更优化的版本

  • 相关阅读:
    IE 11 使用 flexbox 垂直居中 bug
    Electron build 无法下载 winCodeSign 等资源
    Electron 开发环境下总是 crash
    解决 Electron 包下载太慢问题
    Netty--数据通信和心跳检测
    Netty编解码技术和UDP实现
    Netty入门
    Java 网络IO编程(BIO、NIO、AIO)
    java.util.concurrent常用类(CountDownLatch,Semaphore,CyclicBarrier,Future)
    JDK多任务执行框架(Executor框架)
  • 原文地址:https://www.cnblogs.com/james1207/p/3299613.html
Copyright © 2011-2022 走看看