9

画像の高さマップがあり、Z方向の各ピクセルのオフセットがわかります。私の目標は、高さマップのみを使用して、歪んだ画像を平坦化することです。

どうすればこれを行うことができますか?それが助けになるなら、私はカメラの位置を知っています。


これを行うには、各ピクセルが平面上の点であると想定し、高さマップとその変換から取得したZ値に従って、これらの各点を垂直方向に変換することを考えていました(あなたが見ていると想像してください)上からのポイントで;シフトにより、ポイントがあなたの視点から動き回ります)。

その投影されたシフトから、各ピクセルのXシフトとYシフトを抽出でき、これをにフィードできますcv.Remap()

しかし、OpenCVを使用してポイントの投影された3Dオフセットを取得する方法、ましてやそれからオフセットマップを作成する方法がわかりません。


これが私がしていることの私の参照画像です:

キャリブレーション画像 歪んだ画像

私はレーザーの角度(45度)を知っており、キャリブレーション画像から、本の高さを非常に簡単に計算できます。

h(x) = sin(theta) * abs(calibration(x) - actual(x))

私は両方のラインに対してこれを行い、このアプローチを使用して2つのラインを線形補間し、サーフェスを生成します(Pythonコード。ループ内にあります)。

height_grid[x][y] = heights_top[x] * (cv.GetSize(image)[1] - y) + heights_bottom[x] * y

これがお役に立てば幸いです;)


今、これは私が画像をデワープしなければならないものです。真ん中の奇妙なものはすべて、カメラの位置(およびカメラの位置、回転など)を指定して、3D座標をカメラ平面に投影します。

class Point:
  def __init__(self, x = 0, y = 0, z = 0):
    self.x = x
    self.y = y
    self.z = z

mapX = cv.CreateMat(cv.GetSize(image)[1], cv.GetSize(image)[0], cv.CV_32FC1)
mapY = cv.CreateMat(cv.GetSize(image)[1], cv.GetSize(image)[0], cv.CV_32FC1)

c = Point(CAMERA_POSITION[0], CAMERA_POSITION[1], CAMERA_POSITION[2])
theta = Point(CAMERA_ROTATION[0], CAMERA_ROTATION[1], CAMERA_ROTATION[2])
d = Point()
e = Point(0, 0, CAMERA_POSITION[2] + SENSOR_OFFSET)

costx = cos(theta.x)
costy = cos(theta.y)
costz = cos(theta.z)

sintx = sin(theta.x)
sinty = sin(theta.y)
sintz = sin(theta.z)


for x in xrange(cv.GetSize(image)[0]):
  for y in xrange(cv.GetSize(image)[1]):
    
    a = Point(x, y, heights_top[x / 2] * (cv.GetSize(image)[1] - y) + heights_bottom[x / 2] * y)
    b = Point()
    
    d.x = costy * (sintz * (a.y - c.y) + costz * (a.x - c.x)) - sinty * (a.z - c.z)
    d.y = sintx * (costy * (a.z - c.z) + sinty * (sintz * (a.y - c.y) + costz * (a.x - c.x))) + costx * (costz * (a.y - c.y) - sintz * (a.x - c.x))
    d.z = costx * (costy * (a.z - c.z) + sinty * (sintz * (a.y - c.y) + costz * (a.x - c.x))) - sintx * (costz * (a.y - c.y) - sintz * (a.x - c.x))
    
    mapX[y, x] = x + (d.x - e.x) * (e.z / d.z)
    mapY[y, x] = y + (d.y - e.y) * (e.z / d.z)
    

print
print 'Remapping original image using map...'

remapped = cv.CreateImage(cv.GetSize(image), 8, 3)
cv.Remap(image, remapped, mapX, mapY, cv.CV_INTER_LINEAR)

これは今、画像とコードの巨大なスレッドに変わりつつあります...とにかく、このコードチャンクは18MPカメラ画像で実行するのに7分かかります。これは長すぎます。最終的に、このアプローチは画像に何の影響も与えません(各ピクセルのオフセットはです<< 1

何か案は?

4

3 に答える 3

3

私は自分のソリューションを実装することになりました:

for x in xrange(cv.GetSize(image)[0]):
  for y in xrange(cv.GetSize(image)[1]):

    a = Point(x, y, heights_top[x / 2] * (cv.GetSize(image)[1] - y) + heights_bottom[x / 2] * y)
    b = Point()

    d.x = costy * (sintz * (a.y - c.y) + costz * (a.x - c.x)) - sinty * (a.z - c.z)
    d.y = sintx * (costy * (a.z - c.z) + sinty * (sintz * (a.y - c.y) + costz * (a.x - c.x))) + costx * (costz * (a.y - c.y) - sintz * (a.x - c.x))
    d.z = costx * (costy * (a.z - c.z) + sinty * (sintz * (a.y - c.y) + costz * (a.x - c.x))) - sintx * (costz * (a.y - c.y) - sintz * (a.x - c.x))

    mapX[y, x] = x + 100.0 * (d.x - e.x) * (e.z / d.z)
    mapY[y, x] = y + 100.0 * (d.y - e.y) * (e.z / d.z)


print
print 'Remapping original image using map...'

remapped = cv.CreateImage(cv.GetSize(image), 8, 3)
cv.Remap(image, remapped, mapX, mapY, cv.CV_INTER_LINEAR)

これは(ゆっくりと)cv.Remap関数を使用して各ピクセルを再マップします、そしてこれは一種の仕事のようです...

于 2011-03-07T21:11:15.307 に答える
0

次のようにシーンを分離します。

  • 不明なビットマップ画像がありますI(x、y)->(r、g、b)
  • 既知の高さフィールドH(x、y)-> h
  • シーンをスクリーン平面に投影するカメラ変換C(x、y、z)->(u、v)があります

カメラ変換は情報を破棄することに注意してください(各画面ピクセルの深度値は取得されません)。また、画面上でシーンの一部が重なっている場合もあります。その場合、最前面のみが表示され、残りは破棄されます。したがって、一般的に、これは完全に元に戻すことはできません。

  • Iのx、yのC(x、y、H(x、y))の結果であるスクリーンショットS(u、v)があります
  • Iのx、yのC(x、y、0)の結果であるスクリーンショットS'(u'、v')を生成したい

これにアプローチする2つの明白な方法があります。どちらも、カメラ変換の正確な値を持っているかどうかに依存します。

  1. レイキャスティング: Sのピクセルごとに、レイをシーンにキャストバックします。それが高さフィールドに当たる場所を見つけます。これにより、元の画像Iで(x、y)が得られ、画面のピクセルでその時点の色が得られます。回復できる限り多くのIを取得したら、それを再変換してS'を見つけます。

  2. ダブルレンダリング: Iのx、yごとに、(u、v)と(u'、v')を見つけるプロジェクト。S (u、v)からピクセルカラーを取得し、 S'(u'、v')にコピーします。

どちらの方法にも、スーパーサンプリングまたは補間によって支援されるサンプリングの問題があります。方法1は、画像の遮蔽された領域に空のスペースを残し、方法2は、最初のサーフェスから「投影」します。

編集:

Sの各ピクセルがS'の対応する位置の真上にあるCGスタイルの高さフィールドを意味していると思いました。しかし、これはページが表面にドレープする方法ではありません。ページは背表紙に固定されており、伸縮性はありません。ページの中央を持ち上げると、自由端が背表紙に向かって引っ張られます。

サンプル画像に基づいて、この累積的な引っ張りを逆にする必要があります-背表紙の中心線の位置と方向を検出し、左右に徐々に作業して、ページの各垂直ストリップの上下の高さの変化を見つけ、結果を計算しますアスペクトナローイングとスキュー、およびそれを逆にして元のフラットページを再作成します。

于 2011-03-02T21:15:14.153 に答える
0

カメラからの距離に基づく歪みは、透視投影でのみ発生します。ピクセルの(x、y、z)位置がある場合は、カメラの投影行列を使用して、ピクセルをワールドスペースに投影解除できます。その情報を使用して、正投影の方法でピクセルをレンダリングできます。ただし、元の透視投影が原因で、データが欠落している可能性があります。

于 2011-03-02T19:59:47.310 に答える