美文网首页
轮廓检测

轮廓检测

作者: OurNote | 来源:发表于2019-12-20 18:05 被阅读0次
    Canny 算法

    Canny 算法采用两个颜色变化阈值检测图像轮廓,默认得到二值图,其中用非零像素表示轮廓。
    在低阈值时得到很多轮廓,有些是连续的线,有些离散点。
    在高阈值时得到较少轮廓,原本连续的线也可能变成了离散点。
    最后 Canny 算法将两部分融合:从低阈值轮廓中提取那些连续的线,叠加到高阈值轮廓中。

    cv::Mat contours;
    
    cv::Canny(image,    // 输入图片
              contours, // 输出图片
              125,      // 低阈值
              350);     // 高阈值
    

    这种采用两个阈值的策略称为滞后阈值化。

    Hough transform 霍夫变换
    hough1.jpg

    平面中的一条直线有很多种表示方式,例如

    • 用斜率和截距 (m,b) 表示:y=mx+b,即在给定 (m,b) 的条件下,满足这个表达式的 (x,y) 点构成一条直线
    • 用法线段 (r, \theta) 表示: r =x\cos\theta + y\sin \theta,即在给定 (r, \theta) 的条件下,满足这个式子的 (x,y) 构成一条直线。

    对于 (r, \theta) 形式,可以进一步整理: r =x\cos\theta + y\sin \theta = \sqrt{x^2+y^2}\sin(\theta+\phi),其中 \tan \phi = x/y。从这个式子来看,如果固定 (x,y),而把 (r, \theta) 作为变量,就可以得到经过点 (x,y) 的所有直线的集合,而且 r\theta 是正弦关系,在 (r, \theta) 平面中表示为:

    hough2.jpg

    也就是说,在 (r, \theta) 平面中,一个点表示一条直线,一条线对应一个点,而多条线的交点对应了穿过多个点的一条直线

    hough3.jpg

    因此,在检测直线时,可以设定一个阈值,多条线相交于该点,则表明存在与该点对应的直线。
    在进行 Hough 变换时,一般先用 Canny 算法得到二值初始轮廓图,其中非零像素表示潜在的轮廓点。
    将上述二值散点图送入 Hough 算法,得到若干交点,如果交点中汇集的曲线数量超过某一阈值,则认为它对应了一条直线。函数最后返回的是一个向量,其中每个元素是一组 (r, \theta),对应了一条直线。\theta 取值在 0~\pi 之间,r 的取值可以为负数。

    程序实现:

    cv::Mat contours;
    
    cv::Canny(image, contours, 125, 350);
    
    std::vector<cv::Vec2f> lines;
    
    cv::HoughLines(contours,  // 输入来自 Canny 算法的轮廓散点
                   lines,   // 输出向量,里面包含了识别出的直线簇,每个都是二元组 (r, theta)
                   1,  // 法线段 r 的分辨率,即搜索 r 时的步长为 1 个像素
                   M_PI/180,  // 夹角 theta 的分辨率,即搜索 theta 时的步长为 1 度
                   60); // 最小交汇曲线数目
    
    概率霍夫变换

    在标准霍夫变换中,轮廓散点是逐行扫描,对每个扫描到的散点绘制一条 (r, \theta) 曲线。
    而在概率霍夫变化中,随机选择像素点,而不是逐行扫描。当达到阈值时,不再考虑其他散点的投票。因此速度可能会比标准的霍夫变换快一些。
    另外还有两个参数

    • 返回线段的最小长度
    • 属于一条直线的两个散点允许的最大间隔

    返回的 Lines 是四维的,包含了两个端点的坐标 (x1, y1, x2, y2)

    cv::HoughLinesP(binary,  
                    lines,
                    deltaRho, 
                    deltaTheta,
                    minVote,  // 上述 5 个参数与标准霍夫变换相同。
                    minLength, // 返回线段的最小长度
                    maxGap);  // 属于同一条线段的散点之间最大间隔
    
    几何图形拟合轮廓

    在检测完图形轮廓散点之后,为了描述简便,常用某些规则几何图形拟合/包裹相应的轮廓。

    • 矩形拟合

      std::vector<cv::Point> points;  // 点集
      
      cv::Rect r0 = cv::boundingRect(points); // r0 为拟合得到的矩形
      
    • 圆形拟合

      float radius;
      
      cv::Point2f center;
      
      cv::minEnclosingCircle(points, center, radius); // 得到圆心和半径
      
      cv::circle(image, center, static_cast<int>(radius), 0, 2); // radius 必须是 int 类型
      
    • 多边形拟合

      std::vector<cv::Point> poly;
      
      cv::approxPolyDP(points, poly, 5, true); // 拟合时并不明确指定用几边形,根据需要计算得到。5 表示允许的最大拟合差距为 5, true 表示多边形是否是闭合的
      
      cv::polylines(image, poly, true, 0, 2);
      
    • 凸包拟合

      std::vector<cv::Point> hull;
      
      cv::convexHull(points, hull);
      
      cv::polylines(image, hull, true, 0, 2);
      

    相关文章

      网友评论

          本文标题:轮廓检测

          本文链接:https://www.haomeiwen.com/subject/qjvinctx.html