zoukankan      html  css  js  c++  java
  • 基于生长的棋盘格角点检测算法解读

    考文献:

    Geiger A, Moosmann F, Car Ö, et al. Automatic camera and range sensor calibration using a single shot[C]//Robotics and Automation (ICRA), 2012 IEEE International Conference on. IEEE, 2012: 3936-3943.

    代码网站:http://www.cvlibs.net/software/libcbdetect/

     棋盘格角点定位: 棋盘格角点有很明显的特征, 黑白交叉,常用的方案是使用角点检测算法, opencv有提供对应的算法, 但是这种算法对于模糊、噪点多的

    图像稳定太差, 虽然能够对角点进行检测,但是同时会引入其他不需要的点,需要配合筛查算法来进行过滤;

    文章开头给出的论文提供了一种角点检测算法, 它是基于生长的检测方案, 通过研究作者代码发现该算法的稳定性非常好, 能够定位亚像素级的角点;

    下面按照代码流程看看它是怎么实现的:

    1.  角点粗检测(滤波 + 非极大抑制);

     针对棋盘格角点的特征, 黑白交叉, 构建高斯滤波核(选取3个sigma, 两种布局);

                          

    上面是同一个sigma对应的四个滤波核, 分别为a1, a2, b1, b2;

     通过灰度图像与滤波核的卷积运算,得到四个处理后的图像imga1,imga2,imgb1, imgb2,显出角点位置, 抹平黑白平坦区;

     平均图像:   imgmu = (imga1  + imga2 + imgb1 + imgb2)/4;

     在平坦区域, 经过四个卷积运算后, 值基本没什么变化, 但是在角点、边缘地方由于不同的构造滤波核,将使得边缘不同

     方向的值不同,譬如a1核,将导致角点左上角边缘区明显大于其他核后的值,将该值减去平均图像, 就可以得到差值图;

     通过不同sigma尺寸滤波核处理后的差值图即可以得到粗略的角点位置, 当然当前的角点还是一个斑点;

    % template properties
    template_props = [0 pi/2 radius(1); pi/4 -pi/4 radius(1); 0 pi/2 radius(2); pi/4 -pi/4 radius(2); 0 pi/2 radius(3); pi/4 -pi/4 radius(3)];
    
    disp('Filtering ...');
    
    % filter image
    img_corners = zeros(size(img,1),size(img,2));
    for template_class=1:size(template_props,1)
      
      % create correlation template
      template = createCorrelationPatch(template_props(template_class,1),template_props(template_class,2),template_props(template_class,3));
      
      % filter image according with current template
      img_corners_a1 = conv2(img,template.a1,'same');
      img_corners_a2 = conv2(img,template.a2,'same');
      img_corners_b1 = conv2(img,template.b1,'same');
      img_corners_b2 = conv2(img,template.b2,'same');
      
      % compute mean
      img_corners_mu = (img_corners_a1+img_corners_a2+img_corners_b1+img_corners_b2)/4;
      
      % case 1: a=white, b=black
      img_corners_a = min(img_corners_a1-img_corners_mu,img_corners_a2-img_corners_mu);
      img_corners_b = min(img_corners_mu-img_corners_b1,img_corners_mu-img_corners_b2);
      img_corners_1 = min(img_corners_a,img_corners_b);
      
      % case 2: b=white, a=black
      img_corners_a = min(img_corners_mu-img_corners_a1,img_corners_mu-img_corners_a2);
      img_corners_b = min(img_corners_b1-img_corners_mu,img_corners_b2-img_corners_mu);
      img_corners_2 = min(img_corners_a,img_corners_b);
      
      % update corner map
      img_corners = max(img_corners,img_corners_1);
      img_corners = max(img_corners,img_corners_2);
    end

     通过非极大抑制(NMS),我们可以在斑点中找到准确的位置(像素级);NMS一般用于搜索局部极大值;

    2、亚像素级角点检测;

    经过1处理后可以找到像素级的角点位置, 但是棋盘格一般用来标定, 最好是采用亚像素精度更好;

    首先, 计算角点周围的边,得到边的方向v1, v2, 然后对3 * 3范围内的边缘点进行拟合计算求实际位置;

    % non maximum suppression
    for i=n+1+margin:n+1:width-n-margin
      for j=n+1+margin:n+1:height-n-margin
        
        maxi   = i;
        maxj   = j;
        maxval = img(j,i);
    
        for i2=i:i+n                        //先找到一个象限一定区域内的极大值;
          for j2=j:j+n
            currval = img(j2,i2);
            if currval>maxval
              maxi   = i2;
              maxj   = j2;
              maxval = currval;
            end
          end
        end
    
        failed = 0;
        for i2=maxi-n:min(maxi+n,width-margin)                     // 然后,在这个极大值的邻域内找到比该极大值更大的;
          for j2=maxj-n:min(maxj+n,height-margin)
            currval = img(j2,i2);
            if currval>maxval && (i2<i || i2>i+n || j2<j || j2>j+n)
              failed = 1;
              break;
            end
          end
          if failed
            break;
          end
        end
        if maxval>=tau && ~failed
          maxima = [maxima; maxi maxj];
        end
      end
    end

    3、基于生长的检测;

    经过1,2处理后, 角点的位置已经明确了, 下面就需要对所有的角点进行排布, 这就有问题了: 可能存在角点检测遗漏的情况。

    首先, 通过一个焦点找到一个3 * 3的邻居角点阵列, 然后在通过外推(距离、方向),得到四个方向的理论位置,将该理论位置在剩下的

    角点中找最近的点,同时计算当前的能量(判定函数)。理论上, 随着点的增多, 能  % for all seed corners do

    for i=1:size(corners.p,1)
      
      % output
      if mod(i-1,100)==0
        fprintf('%d/%d
    ',i,size(corners.p,1));
      end
      
      % init 3x3 chessboard from seed i
      chessboard = initChessboard(corners,i);                        // 找到3 * 3 的邻居;
      
      % check if this is a useful initial guess
      if isempty(chessboard) || chessboardEnergy(chessboard,corners)>0
        continue;
      end
        
      % try growing chessboard
      while 1
        
        % compute current energy
        energy = chessboardEnergy(chessboard,corners);                  // 计算目前的能量;
        
        % compute proposals and energies
        for j=1:4                                        // 四个方向扩展;
          proposal{j} = growChessboard(chessboard,corners,j);              //扩展, 生长;
          p_energy(j) = chessboardEnergy(proposal{j},corners);                      // 扩展后的能量;
        end
        
        % find best proposal
        [min_val,min_idx] = min(p_energy);
        
        % accept best proposal, if energy is reduced
        if p_energy(min_idx)<energy
          chessboard = proposal{min_idx};
          
          if 0
            figure, hold on, axis equal;
            chessboards{1} = chessboard;
            plotChessboards(chessboards,corners);
            keyboard;
          end
          
        % otherwise exit loop
        else
          break;
        end
      end
        
      % if chessboard has low energy (corresponding to high quality)
      if chessboardEnergy(chessboard,corners)<-10                  //当能量小于-10; 因为最大-9 ( 3 * 3)
      
        % check if new chessboard proposal overlaps with existing chessboards
        overlap = zeros(length(chessboards),2);
        for j=1:length(chessboards)                          // 判断当前找的阵列是否与先前找的阵列有重叠区;         
          for k=1:length(chessboards{j}(:))
            if any(chessboards{j}(k)==chessboard(:))
              overlap(j,1) = 1;
              overlap(j,2) = chessboardEnergy(chessboards{j},corners);
              break;
            end
          end
        end
    
        % add chessboard (and replace overlapping if neccessary)
        if ~any(overlap(:,1))
          chessboards{end+1} = chessboard;
        else
          idx = find(overlap(:,1)==1);
          if ~any(overlap(idx,2)<=chessboardEnergy(chessboard,corners))        // 如果重叠区的能量比现有的阵列小, 那么久置换先前的;
            chessboards(idx) = [];
            chessboards{end+1} = chessboard;
          end
        end
      end
    end
  • 相关阅读:
    RGB888转RGB666
    bmp文件格式详细解析
    Qt 5简介
    IntelliJ IDEA 快捷键
    猫猫学iOS之小知识之_xcode插件的删除方法_自己主动提示图片插件KSImageNamed有时不灵_分类或宏之类不能自己主动提示,
    sql server 2008出现远程过程调用失败
    Oracle-31-对视图DML操作
    uva 11127(暴力)
    各种排序算法的分析与实现
    我的Android进阶之旅------&gt;怎样解决Android 5.0中出现的警告: Service Intent must be explicit:
  • 原文地址:https://www.cnblogs.com/yinwei-space/p/12831621.html
Copyright © 2011-2022 走看看