2016-11-15 50 views
0

我一直在使用Hough變換的Rosetta Code Java implementation,它也很好地生成了累加器的可視化。在原始圖像中顯示與Rosetta Code Hough變換髮現的行

通過在輸入圖像是這樣的:

enter image description here

累加器是這樣的:

Accumulator Space

鑑於我cpompile並調用類是這樣的:

$ javac HoughTransform.java && java HoughTransform pentagram.png out.png 640 480 100 

這是有道理的。現在我想用我發現的線條覆蓋原始圖像,但這給我帶來了嚴重的麻煩。

我只能找到一個例子我想要做什麼用C++編寫:

... 
int x1, y1, x2, y2; 
x1 = y1 = x2 = y2 = 0; 

if(t >= 45 && t <= 135) 
{ 
    //y = (r - x cos(t))/sin(t) 
    x1 = 0; 
    y1 = ((double)(r-(_accu_h/2)) - ((x1 - (_img_w/2)) * cos(t * DEG2RAD)))/sin(t * DEG2RAD) + (_img_h/2); 
    x2 = _img_w - 0; 
    y2 = ((double)(r-(_accu_h/2)) - ((x2 - (_img_w/2)) * cos(t * DEG2RAD)))/sin(t * DEG2RAD) + (_img_h/2); 
} 
else 
{ 
    //x = (r - y sin(t))/cos(t); 
    y1 = 0; 
    x1 = ((double)(r-(_accu_h/2)) - ((y1 - (_img_h/2)) * sin(t * DEG2RAD)))/cos(t * DEG2RAD) + (_img_w/2); 
    y2 = _img_h - 0; 
    x2 = ((double)(r-(_accu_h/2)) - ((y2 - (_img_h/2)) * sin(t * DEG2RAD)))/cos(t * DEG2RAD) + (_img_w/2); 
} 
... 

https://github.com/brunokeymolen/hough/blob/master/hough.cpp#L125

我試圖適應的代碼至少要看到,如果我能得到一般想法,但C++版本和Rosetta代碼版本的實現看起來有些不同。

我實現:

public static void getLines(String filename, int thetaAxisSize, ArrayData arrayData) throws IOException 
{ 
    BufferedImage inputImage = ImageIO.read(new File(filename)); 

    double[] sinTable = new double[thetaAxisSize]; 
    double[] cosTable = new double[thetaAxisSize]; 
    for (int theta = thetaAxisSize - 1; theta >= 0; theta--) 
    { 
    double thetaRadians = theta * Math.PI/thetaAxisSize; 
    sinTable[theta] = Math.sin(thetaRadians); 
    cosTable[theta] = Math.cos(thetaRadians); 
    } 


    java.awt.Color color = new java.awt.Color(255, 0, 0); 

    int max = arrayData.getMax(); 
    System.out.println("Max value: " + max); 

    for (int r = 0; r < arrayData.height; r++) 
    { 
    for (int theta = 0; theta < arrayData.width; theta++) 
    { 
     int val = arrayData.get(theta, r); 

     if (val < max - 1) { 
     continue; 
     } 

     System.out.println("Found val: " + val + ", r: " + r + ", theta: " + theta); 

     int x = (int)(r * cosTable[theta]); 
     int y = (int)(r * sinTable[theta]); 

     System.out.println("Found val: " + val + ", r: " + r + ", theta: " + theta + ", x/y: " + x + "/" + y); 
    } 
    } 

    ImageIO.write(inputImage, "PNG", new File("/tmp/hough-overlay.png")); 
} 

但隨後就卡住,因爲結果已經是無意義的對我說:

Max value: 217 (this one still makes sense) 
Found val: 216, r: 275, theta: 342 
Found val: 216, r: 275, theta: 342, x/y: -29/273 
Found val: 216, r: 276, theta: 340 
Found val: 216, r: 276, theta: 340, x/y: -27/274 
Found val: 217, r: 277, theta: 337 
Found val: 217, r: 277, theta: 337, x/y: -23/276 
Found val: 217, r: 277, theta: 339 
Found val: 217, r: 277, theta: 339, x/y: -25/275 
Found val: 217, r: 278, theta: 336 
Found val: 217, r: 278, theta: 336, x/y: -21/277 
Found val: 216, r: 279, theta: 334 
Found val: 216, r: 279, theta: 334, x/y: -19/278 

我的數學不夠好,找出我如何改變rtheta回到圖像空間,給出一條線被發現。我閱讀了很多有關霍夫變換的白皮書和文章,但我仍然不明白。我發現的幾個實現,如C++版本,似乎都與我的Java版本有點不同。

所以我想知道,有沒有人用過Hough變換的Rosetta Code Java實現,並設法將線條從極座標變換回原圖像?

+0

你是否有五個簇的近r/theta對圍繞這個pentagon的最大值? – MBo

+0

@MBo Hm你是什麼意思?根據霍夫空間圖像,線條被正確檢測。 – Max

+0

是的,你的問題是要獲得這些明亮地方的位置,不是嗎? – MBo

回答

1

你有參數RHO,「正常」的直線方程的THETA,並希望得到兩個點定義在同一行

x * Cos(Theta) + y * sin(Theta) - Rho = 0 

特殊情況:檢查的Rho = 0或θ是90 * K(水平或垂直)。

  1. Rho = 0 - 通過座標原點的直線。所以第一點是(0,0)。如果THETA = 0,取(0, 1)作爲第二點,否則取(1, Cotangent(Theta))

  2. 如果THETA = 0或180(垂直) - 只是使垂直線X=Rho(例如,點(Rho, 0) and (Rho,1)

  3. 如果THETA = 90/270(水平) - 只是使水平線Y=Rho(例如,點(0, Rho) and (1, Rho)

否則 - 我們選擇與座標軸作爲基準線的點交叉點。在方程代入x = 0和y = 0,並獲得座標:

0 * Cos(Theta) + y * sin(Theta) - Rho = 0 
y = Rho/Sin(Theta) 

x * Cos(Theta) + 0 * sin(Theta) - Rho = 0  
x = Rho/Cos(Theta) 

那麼點(0, Rho/Sin(Theta))(Rho/Cos(Theta), 0)

Theta = 45, Rho = 0.7071快速檢查: (0, 1)(1, 0) - OK

+0

謝謝您的回答,我將需要詳細檢查。 「替代方程式中的x = 0和y = 0並得到座標」是什麼意思?和「Theta是90 * K」,「K」是什麼?謝謝! – Max

+0

我表現出替代。 K是整數:90 * K = 0,90,180,270 – MBo

+0

您能給我一個這方面所需計算的例子:https://upload.wikimedia.org/wikipedia/commons/3/39/Hough_transform_diagram .png?所以基本上累加器中的每個單元格代表一條線。我現在需要找到該線上的一個x/y點。在這幅圖像中,30度的綠線 - 我可以說綠線的交點是x/y,然後用它反轉到正常形式? – Max

0

你有什麼圓上的切線。如果您閱讀了關於霍夫的所有文章,您將會知道它會計算可能通過一個點並在極地空間投票的線(最多投票贏得該線):

要解決轉換問題,轉型:

public static void data(ArrayData outputData, int theta, int r, int maxR) { 
    int w=outputData.width, h=outputData.height; 
    int halfRAxisSize = r >>> 1; 
    int max=0, maxr=0, maxth=0, maxi=0, maxj=0; 
    for (int i=0; i<outputData.width; i++) 
     for (int j=0; j<outputData.height; j++) 
     if (outputData.dataArray[i+j*outputData.width]>max) { 
      max=outputData.dataArray[i+j*outputData.width]; maxi=i; maxj=j; 
     }  
    double R=(maxj-halfRAxisSize)*maxR/halfRAxisSize; 
    double th=1.0*maxi/theta, tha=(1.0*maxi/theta)*180; 
    System.out.println("max "+R+" "+th+" "+tha+" "+max+" w h "+w+" "+h); 
    } 

,你這樣稱呼它

public static void m() { 
    ArrayData inputData = getArrayDataFromImage("../h-5.png"); 
    ArrayData outputData = houghTransform(inputData, 640, 480, 100); 

    int width = inputData.width; 
    int height = inputData.height; 
    int maxRadius = (int)Math.ceil(Math.hypot(width, height));  
    data(outputData, 640, 480, maxRadius);  
} 

我做了幾個實驗,以單個線,似乎工作 - 不包括舍入誤差(我與整數工作)似乎遵守(最後一個你不會的) ee值,因爲它進入負RHO):

1

2

3

4

5

所以,你必須弄清楚垂直線(黑色)從紅線。

在多行情況下,您必須刪除最大值附近的區域,因爲很多值都與最大值相似,然後才能轉到下一個最大區域。

-

要畫線我用下面的代碼。由於在計算霍夫期間y方向被翻轉,因此座標中心在圖像中爲0,即h-1,即正常座標系。

g2.setStroke(new BasicStroke(2f)); 
// g2.drawLine(100, 100, 200, 150); 
// g2.drawLine(100, 100, 200, 200); 
// g2.drawLine(100, 200, 200, 50); 
    g2.drawLine(100, 100, 100, 200); 
// g2.drawLine(100, 100, 200, 100); 


    g2.setColor(Color.red); 
// int r=170, th=63, rr=r; // 170 63, 168 45, -63 147, 98 0, 138 90 
// int r=168, th=45, rr=r; 
// int r=-63, th=147, rr=(int)Math.abs(r); 
    int r=98, th=0, rr=(int)Math.abs(r); 
// int r=138, th=90, rr=(int)Math.abs(r); 
    g2.drawOval(-rr, h-1-rr, 2*rr, 2*rr); 
    g2.drawLine(0, h-1, (int)(rr*Math.cos(Math.toRadians(th))), h-1-(int)(rr*Math.sin(Math.toRadians(th))));