2012-09-27 15 views
5

私は魚眼レンズで撮影した写真を大量に撮影しています。写真上でいくつかの画像処理(エッジ検出など)を行いたいので、結果を大きく左右するバレル歪みを取り除きたい。 FishEyeレンズを補正するためのバレル歪み補正アルゴリズム - Javaでの実装に失敗しました

は、いくつかの研究と読み取りの記事の多くの後、私はこの pageを見つけました:彼らはこの問題を解決するためのアルゴリズム(およびいくつかの式)を記述します。

Mは、*のrcorr^3 + B * rcorr^2 + C * rcorr + D
RSRC =(*のrcorr^3 + B * rcorr^2 + C * rcorr + D)* rcorrを=

RSRC =ソース画像の中心からの画素の距離
rcorr =補正画像
画像の、B、画像 DのC =歪み=線形スケーリング中心からの画素の距離私はこれらを使用

Javaアプリケーションでこれを実装しようとしました。残念ながら、それは動作しません、私はそれを動作させるために失敗しました。 「修正された」画像は元の写真のようには見えず、真ん中にいくつかの不思議な円を表示します。ここを見て:ここで

http://imageshack.us/f/844/barreldistortioncorrect.jpg/ (これは前の白牛の写真青い壁にするために使用)

は私のコードです:

protected int[] correction(int[] pixels) { 

    // 
    int[] pixelsCopy = pixels.clone(); 

    // parameters for correction 
    double paramA = 0.0; // affects only the outermost pixels of the image 
    double paramB = -0.02; // most cases only require b optimization 
    double paramC = 0.0; // most uniform correction 
    double paramD = 1.0 - paramA - paramB - paramC; // describes the linear scaling of the image 

    // 
    for(int x = 0; x < dstView.getImgWidth(); x++) { 
     for(int y = 0; y < dstView.getImgHeight(); y++) { 

      int dstX = x; 
      int dstY = y; 

      // center of dst image 
      double centerX = (dstView.getImgWidth() - 1)/2.0; 
      double centerY = (dstView.getImgHeight() - 1)/2.0; 

      // difference between center and point 
      double diffX = centerX - dstX; 
      double diffY = centerY - dstY; 
      // distance or radius of dst image 
      double dstR = Math.sqrt(diffX * diffX + diffY * diffY); 

      // distance or radius of src image (with formula) 
      double srcR = (paramA * dstR * dstR * dstR + paramB * dstR * dstR + paramC * dstR + paramD) * dstR; 

      // comparing old and new distance to get factor 
      double factor = Math.abs(dstR/srcR); 
      // coordinates in source image 
      double srcXd = centerX + (diffX * factor); 
      double srcYd = centerY + (diffX * factor); 

      // no interpolation yet (just nearest point) 
      int srcX = (int)srcXd; 
      int srcY = (int)srcYd; 

      if(srcX >= 0 && srcY >= 0 && srcX < dstView.getImgWidth() && srcY < dstView.getImgHeight()) { 

       int dstPos = dstY * dstView.getImgWidth() + dstX; 
       pixels[dstPos] = pixelsCopy[srcY * dstView.getImgWidth() + srcX]; 
      } 
     } 
    } 

    return pixels; 
} 

私の質問は以下のとおりです。)この式は正しいですか?
2)私はその数式をソフトウェアに変えて間違いを犯しましたか?
3)他にもアルゴリズムがあります(例えば、How to simulate fisheye lens effect by openCV?またはwiki/Distortion_(光学))。

ありがとうございました!

+0

エッジ付近のピクセルの正方形のグリッドは、問題の可能性についてたくさん言います。あなたのアルゴリズムがどんな写真にもかかわらず、私は分かりません。それがうまくいかない理由の1つは、歪みが過剰補正されている可能性があるということです。 – AJMansfield

+0

私が下で述べたように、私は無限小の値にbを設定しようとしました。結果は異なりますが(球面補正はありません)、同じ画像は表示されません。ここをクリックしてください:http://imageshack.us/f/191/barreldistortioncorrect.jpg/ – Lucas

+0

_other_方向では、極端に小さいb値が過補正されることがありますか? – AJMansfield

答えて

7

あなたが持っている主なバグがアルゴリズムがそのr_corrとr_srcを指定していることですmin((xDim-1)/ 2、(yDim-1)/ 2)の単位である。これは、パラメータ値がソース画像のサイズに依存しないように計算を正規化するために行う必要があります。コードをそのまま使用すると、paramBの値をもっと小さくする必要があります。 paramB = 0.00000002(2272 x 1704の画像の場合)でうまくいきました。

また、中心からの差異を計算する際にバグがあり、結果のイメージが元のイメージと180度回転します。 (あなたは、各パラメータの符号を反転させる必要がありますが)あなたはLensFunのような既存のレンズデータベースからパラメータ値を使用することができます。このバージョンでは

protected static int[] correction2(int[] pixels, int width, int height) { 
    int[] pixelsCopy = pixels.clone(); 

    // parameters for correction 
    double paramA = -0.007715; // affects only the outermost pixels of the image 
    double paramB = 0.026731; // most cases only require b optimization 
    double paramC = 0.0; // most uniform correction 
    double paramD = 1.0 - paramA - paramB - paramC; // describes the linear scaling of the image 

    for (int x = 0; x < width; x++) { 
     for (int y = 0; y < height; y++) { 
      int d = Math.min(width, height)/2; // radius of the circle 

      // center of dst image 
      double centerX = (width - 1)/2.0; 
      double centerY = (height - 1)/2.0; 

      // cartesian coordinates of the destination point (relative to the centre of the image) 
      double deltaX = (x - centerX)/d; 
      double deltaY = (y - centerY)/d; 

      // distance or radius of dst image 
      double dstR = Math.sqrt(deltaX * deltaX + deltaY * deltaY); 

      // distance or radius of src image (with formula) 
      double srcR = (paramA * dstR * dstR * dstR + paramB * dstR * dstR + paramC * dstR + paramD) * dstR; 

      // comparing old and new distance to get factor 
      double factor = Math.abs(dstR/srcR); 

      // coordinates in source image 
      double srcXd = centerX + (deltaX * factor * d); 
      double srcYd = centerY + (deltaY * factor * d); 

      // no interpolation yet (just nearest point) 
      int srcX = (int) srcXd; 
      int srcY = (int) srcYd; 

      if (srcX >= 0 && srcY >= 0 && srcX < width && srcY < height) { 
       int dstPos = y * width + x; 
       pixels[dstPos] = pixelsCopy[srcY * width + srcX]; 
      } 
     } 
    } 

    return pixels; 
} 

固定の両方のこれらのバグはあなたにこのような何かを与える必要があります。アルゴリズムを説明するページは、http://mipav.cit.nih.gov/pubwiki/index.php/Barrel_Distortion_Correctionにあります。

+0

ご協力ありがとうございます! – Lucas

+0

私は魚眼レンズを使って360のパノラマ撮影をしています。私はイメージの歪みとステッチングのための参照としてptiGuiを使用しました。しかし、問題は、ptguiがあなたのコードに歪みを与えないa b cパラメータを置くと、結果が非​​常に異なることです。実際のところ、Ptguiではコードとは逆の効果があります。あなたは何が問題になると思いますか? –

0

おそらく、あなたの放射状の歪みパラメータが大きすぎ、画像が球体に詰め込まれた可能性があります。 a,b,cおよびdに小さい値を入力してください。

+0

無限小の値を設定するbについては(そしてa = c = 0のままにして)、球はもう存在しないが、依然として画像内のすべてのピクセルが混ざっているように見える。ここをクリックしてください:http://imageshack.us/f/191/barreldistortioncorrect.jpg/アルゴリズムではなく私のコードに問題がなければならないと思います。 a = b = c = 0、d = 1に設定すると、すべて正常に動作し、画像は変更されません。 – Lucas

0

値が極端であるため、極端な結果が表示されます。

a = 0、b = 0、c = 1を試してください。あなたのプログラムが正しければ、元の画像が見えるはずです。その後徐々にcとbを変更します。 0.1単位で変更するのが良いスタートです。

2

私はサークルは、この行によって引き起こされると思う:私は推測している

double srcYd = centerY + (diffX * factor); 

は次のようになります。

double srcYd = centerY + (diffY * factor); 
+0

ありがとう、これが助けになった! – Lucas

関連する問題