2016-11-15 3 views
0

私はHough TransformのRosetta Code Java implementationを使用していて、アキュムレータの視覚化もうまく行っています。Rosetta Codeで見つかった行を表示するHough Transformを元画像

enter image description here

アキュムレータは、次のようになります:私はcpompileと、このようなクラスを呼び出すことを考えると

Accumulator Space

$ javac HoughTransform.java && java HoughTransform pentagram.png out.png 640 480 100 
このような入力画像が与えられ

どちらが理にかなっている。今私が見つけた線で元の画像をオーバーレイしたいのですが、これは私に深刻な問題をもたらします。

私は、私はC++で書かれて欲しいものない例見つけることができる:https://github.com/brunokeymolen/hough/blob/master/hough.cpp#L125

から

... 
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); 
} 
... 

私は私ができるならば、少なくとも参照するコードを適応しようとしたが一般的な考えを得るが、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 

私の数学は、私が変えることができる方法を見つけるために十分ではありませんrおよびthetaがイメージスペースに戻ってきて、行が見つかった場合。私はHough Transformに関する多くのホワイトペーパーと記事を読んでいますが、私はまだ理解していません。私が見つけたいくつかの実装は、C++バージョンのように、すべて私が持っているJavaバージョンと少し違っているようです。

誰かがHough TransformのRosetta Code Java実装を使用し、極座標から元の画像に線を戻すことができたのでしょうか?

+0

この五角形の最大値の近くに5つのクラスタがありますか? – MBo

+0

@MBoどういう意味ですか?ハフ空間画像によれば、線は正しく検出される。 – Max

+0

はい、あなたの問題は、これらの明るい場所の位置を取得することですか? – MBo

答えて

1

あなたはパラメータのロー、「ノーマル」のライン方程式のシータを持っているし、同じ行に

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

特別な場合を規定している2つのポイントを取得したい:Rhoの= 0またはシータがあるかどうかをチェック90 *横K(または垂直)。

  1. Rho = 0 - 直線通過座標起点。したがって、最初のポイントは(0,0)です。シータは90 =場合だけ垂直線X=Rho(例えば、(Rho, 0) and (Rho,1)ポイント)

  2. を作る - シータ= 0の場合、そうでなければシータが0または180(垂直)をIF = (1, Cotangent(Theta))

  3. を取り、第二の点として(0, 1)を取ります/ 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) 

だから、ポイントがTheta = 45, Rho = 0.7071ため(0, Rho/Sin(Theta))(Rho/Cos(Theta), 0)

クイックチェックです: (0, 1)(1, 0) - OK

+0

あなたの答えをありがとう、私は詳細を確認する必要があります。 「方程式のx = 0とy = 0を置き換えて座標を取得する」とは何を意味していますか? "Theta is 90 * K"とは何ですか?ありがとう! – Max

+0

私は置換を示しました。 Kは整数です:90 * K = 0,90,180,270 – MBo

+0

この文脈で必要とされる計算の例を教えてください:https://upload.wikimedia.org/wikipedia/commons/3/39/Hough_transform_diagram .png?したがって、基本的に、アキュムレータの各セルはラインを表します。私は今、その行に1つのx/y点を見つける必要があります。その画像では、30度の緑の線 - 私はその緑の線の交差点がx/yであり、それを通常の形に戻すために使用すると言うことができますか? – Max

0

は、あなたが持っているものです円の接線。 Houghについてのすべての記事を読むと、潜在的にポイントを通過したラインを計算し、極座標で投票します(多くの投票が勝ちます)。

変換を実行するには、変換:

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);  
} 

ようにそれを呼び出す - それが思わエラーオフラウンドを除く(Iは整数で動作)あなたがいない最後のものEE)、それは負のローに入るので:だからあなたは垂直線(黒)を把握する必要があり

1

2

3

4

5

赤い線から。

複数行の場合、次の最大領域に行く前に、値の多くがmaxの周りで似ているので、maxの周りの領域を削除する必要があります。

-

私は次のコードを使用しました。ハフの計算中にy方向が反転されるので、座標の中心は画像内の0、h-1、すなわち、nornal座標系にある。

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)))); 
関連する問題