基於生長的棋盤格角點檢測算法解讀


考文獻:

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\n',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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM