2014-12-19 45 views
2

物流

的OpenCV 2.4和Python 2.7opencv的:在盒子中找到盒

我正在使用的圖像: enter image description here

的問題

我感興趣的是隔離圍繞9條垂直線和水平線形成框的輪廓。我只是不確定如何去做這件事。我已經看過各種教程,比如那些在Sudoku拼圖上完成的教程,那些簡單地假設最大的盒子是你正在尋找的盒子(因爲數獨拼圖在框中沒有框,減去實際網格) 。我嘗試過使用findContour函數並按大小過濾輪廓,但沒有運氣。我最終得出的結果不一致,有時會找到正確的輪廓,但其他時候發現完全錯誤的輪廓。任何人都可以將我指向正確的方向嗎?謝謝。

原始圖像: enter image description here

+1

Cound還你上傳的原始圖像?只能通過邊緣圖像獲取方框可能很困難。 – maxint 2014-12-19 01:19:23

+0

是。沒問題!謝謝! – user1243 2014-12-19 19:57:50

回答

2

這是更好地把原來的形象,但我想從你的輪廓圖像解釋

我做了以下步驟

  1. 你可能需要一些噪音去除(侵蝕)
  2. 從這些等高線計算水平和垂直投影
  3. 繪製圖像上的投影,以便能夠分析與檢查表相關的投影邊界。
  4. 請注意,垂直投影(綠色)是如何爲您提供左右邊界的指示,以及底部和頂部紙張的水平(藍色)如何。

您只需要平滑投影並精確搜索有關確切的輪廓。 enter image description here

enter image description here

,如果你認爲這是我可以共享OpenCV的C++(而不是Python)

編輯的實現代碼有用:

這是我用來使代碼水平和垂直投影,你可能需要優化它。

void HVprojection(Mat image) 
{ 
    // find the vertical projection 
    Mat smothedRes = image.clone(); 
    vector<double> v_vl_proj; // holds the column sum values 
    double max_vl_proj_h = 0,max_vl_proj_v=0; // holds the maximum value 
    double average_v=0; 
    for(int i=0;i<image.cols;++i) 
    { 
     Mat col; 
     Scalar col_sum; 
     // get individual columns 
     col= image.col(i); 
     col_sum = sum(col); // find the sum of ith column 
     v_vl_proj.push_back(col_sum.val[0]); // push back to vector 
     if(col_sum.val[0]>max_vl_proj_v) max_vl_proj_v = col_sum.val[0]; 
     average_v+= col_sum.val[0]; 
    } 
    average_v = average_v/image.cols; 

    // find the horizontal projection 
    vector<double> h_vl_proj; // holds the row sum values 

    double average_h=0; 
    for(int i=0;i<image.rows;++i) 
    { 
     Mat row; 
     Scalar row_sum; 
     // get individual columns 
     row= image.row(i); 
     row_sum = sum(row); // find the sum of ith row 
     h_vl_proj.push_back(row_sum.val[0]); // push back to vector 
     if(row_sum.val[0]>max_vl_proj_h) max_vl_proj_h = row_sum.val[0]; 
     average_h+= row_sum.val[0]; 
    } 
    average_h = average_h/image.rows; 


    //******************Plotting vertical projection******************* 
    for(int j =1;j<image.cols;j++) 
    { 
     int y1 = int(image.rows*v_vl_proj[j-1]/max_vl_proj_v); 
     int y2 = int(image.rows*v_vl_proj[j]/max_vl_proj_v); 
      line(image,Point(j-1,y1),Point(j,y2),Scalar(255,255,255),1,8); 
     } 
    int average_y = int(image.rows*average_v/max_vl_proj_v); // zero level 
    line(image,Point(0,average_y),Point(image.cols,average_y),Scalar(255,255,255),1,8); 




    //***************Plotting horizontal projection************** 
    for(int j =1;j<image.rows;j++) 
    { 
     int x1 = int(0.25*image.cols*h_vl_proj[j-1]/max_vl_proj_h); 
     int x2 = int(0.25*image.cols*h_vl_proj[j]/max_vl_proj_h); 
      line(image,Point(x1,j-1),Point(x2,j),Scalar(255,0,0),1,8); 
     } 
    int average_x = int(0.25*image.cols*average_h/max_vl_proj_h); 
    line(image,Point(average_x,0),Point(average_x,image.rows),Scalar(255,0,0),1,8); 

    imshow("horizontal_projection",image); 
    imwrite("h_p.jpg",image); 



// if you want to smooth the signal of projection in case of noisu signal 
    v_vl_proj = smoothing(v_vl_proj); 

    for(int j =1;j<image.cols;j++) 
     { 
      int y1 = int(image.rows*v_vl_proj[j-1]/max_vl_proj_v); 
      int y2 = int(image.rows*v_vl_proj[j]/max_vl_proj_v); 
       line(smothedRes,Point(j-1,y1),Point(j,y2),Scalar(0,255,0),1,8); 
      } 
     int average_y1 = int(smothedRes.rows*average_v/max_vl_proj_v); // zero level 
     line(smothedRes,Point(0,average_y1),Point(smothedRes.cols,average_y1),Scalar(0,255,0),1,8); 

     imshow("SMoothed",smothedRes); 
     imwrite("Vertical_projection.jpg",smothedRes); 
     waitKey(0); 
} 

爲了平穩投影信號:

vector<double> smoothing(vector<double> a) 
{ 
    //How many neighbors to smooth 
    int NO_OF_NEIGHBOURS=5; 
    vector<double> tmp=a; 
    vector<double> res=a; 

    for(int i=0;i<a.size();i++) 
    { 

     if(i+NO_OF_NEIGHBOURS+1<a.size()) 
     { 
      for(int j=1;j<NO_OF_NEIGHBOURS;j++) 
      { 
       res.at(i)+=res.at(i+j+1); 
      } 
      res.at(i)/=NO_OF_NEIGHBOURS; 
     } 
     else 
     { 
      for(int j=1;j<NO_OF_NEIGHBOURS;j++) 
      { 
       res.at(i)+=tmp.at(i-j); 
      } 
      res.at(i)/=NO_OF_NEIGHBOURS; 

     } 


    } 
    return res; 

} 
+0

是的。如果你不介意分享,那會很好。另外,您是否碰巧有我可以閱讀的鏈接,或者您是否介意進一步解釋這些預測?單線是否代表邊界? – user1243 2014-12-19 20:02:05

+0

還是我感興趣的點的相對極值?我也發佈了原始圖片。 – user1243 2014-12-19 20:20:09

+0

是的,我會盡快分享 – dervish 2014-12-22 09:47:15

3

通過@苦行僧的回答啓發,我有一些想法。

  1. 使用cv :: HoughLines()獲取軸方向。
  2. 估計透視變換矩陣(M)以對齊圖像w.r.t.軸方向。
  3. 使用CV :: warpPerspective()來扭曲圖像。
  4. 使用@ dervish的答案來獲取網格線candicates。
  5. 過濾由色彩信息(藍色和白色棋盤)和線路的距離線ca​​ndicates。
  6. 在最後一格做反向變換與M得到原始圖像的空間網格。

或者直接在步驟2中找到最終的網格位置以獲得第N個最長的線。和步驟4

HoughLine results

過濾結果的Python代碼:

import cv2 
import numpy as np 


def main(): 
    im = cv2.imread('image.png') 
    #edge = cv2.imread('edge.png', 0) 
    edge = cv2.Canny(im, 100, 200, apertureSize=3) 
    lines = cv2.HoughLines(edge, 1, np.pi/180, 140) 
    for rho, theta in lines[0]: 
     a = np.cos(theta) 
     b = np.sin(theta) 
     x0 = a*rho 
     y0 = b*rho 
     x1 = int(x0 + 1000*(-b)) 
     y1 = int(y0 + 1000*(a)) 
     x2 = int(x0 - 1000*(-b)) 
     y2 = int(y0 - 1000*(a)) 
     cv2.line(im, (x1, y1), (x2, y2), (0, 0, 255), 2) 
     # TODO: filter the lines by color and line distance 

    cv2.imshow('image', im) 
    cv2.imshow('edge', edge) 
    cv2.waitKey(0) 
    cv2.destroyAllWindows() 

if __name__ == '__main__': 
    main() 
+0

是的。我已經實現了hough線算法。我會仔細研究一下,看看它是否可行。謝謝。順便說一下,你使用何種版本的opencv作爲hough行? – user1243 2014-12-21 01:10:16

+0

霍夫線是一個正確的方向。我在Arch Linux官方存儲庫中使用OpenCV 2.4。 – maxint 2014-12-22 00:58:01