2011-09-21 108 views
3

我想從2張圖像中找到相機extrinsics。我擁有CameraCalibration的內部函數,並且場景已知尺寸(使用3DSMAX創建)。相機extrinsics計算錯誤

棋盤是1000 * 1000,每個正方形125 * 125。相機處於(0,0,3000)處,直直看向以原點爲中心的棋盤。在第二圖像時,相機被轉換(-1500,0,-402)並旋轉30°在Y軸上再次指向棋盤的中心: camera setup

GoodFeaturesToTrack正確地識別81角: chessboards

我創建棋盤角的3d點,cvFindExtrinsicCameraParams2來計算intrinsics和cvRodrigues2來獲得旋轉矩陣。下面的代碼

Imports Emgu.CV 
Imports Emgu.CV.Structure 
Imports Emgu.CV.CvInvoke 
Imports Emgu.CV.CvEnum 
Imports Emgu.CV.UI 
Imports System.Drawing 
Imports System.IO 
Imports System.Diagnostics 
Imports System.Math 
Module main_ 

    Sub Main() 

     Const MAXFEATURES As Integer = 100 
     Dim featuresA(0)() As PointF 
     Dim featuresB(0)() As PointF 
     Dim features As Integer = 0 
     Dim imgA As Emgu.CV.Image(Of Emgu.CV.Structure.Bgr, Byte) 
     Dim imgB As Emgu.CV.Image(Of Emgu.CV.Structure.Bgr, Byte) 
     Dim grayA As Emgu.CV.Image(Of Emgu.CV.Structure.Gray, Byte) 
     Dim grayB As Emgu.CV.Image(Of Emgu.CV.Structure.Gray, Byte) 
     Dim pyrBufferA As Emgu.CV.Image(Of Emgu.CV.Structure.Gray, Byte) 
     Dim pyrBufferB As Emgu.CV.Image(Of Emgu.CV.Structure.Gray, Byte) 
     Dim pointsA As Matrix(Of Single) 
     Dim pointsB As Matrix(Of Single) 
     Dim flags As Emgu.CV.CvEnum.LKFLOW_TYPE = Emgu.CV.CvEnum.LKFLOW_TYPE.DEFAULT 
     Dim imagesize As Size 
     Dim termcrit As New Emgu.CV.Structure.MCvTermCriteria(20, 0.03D) 
     Dim status As Byte() = Nothing 
     Dim errors As Single() = Nothing 
     Dim red As Bgr = New Bgr(Color.Red) 

     ' Load chessboards 
     imgA = New Image(Of [Structure].Bgr, Byte)("chessboard centre.jpg") 
     imgB = New Image(Of [Structure].Bgr, Byte)("chessboard left.jpg") 
     grayA = imgA.Convert(Of Gray, Byte)() 
     grayB = imgB.Convert(Of Gray, Byte)() 

     ' setup for feature detection 
     imagesize = cvGetSize(grayA) 
     pyrBufferA = New Emgu.CV.Image(Of Emgu.CV.Structure.Gray, Byte)(imagesize.Width + 8, imagesize.Height/3) 
     pyrBufferB = New Emgu.CV.Image(Of Emgu.CV.Structure.Gray, Byte)(imagesize.Width + 8, imagesize.Height/3) 
     features = MAXFEATURES 

     ' Find features 
     featuresA = grayA.GoodFeaturesToTrack(features, 0.01, 25, 3) 
     grayA.FindCornerSubPix(featuresA, New System.Drawing.Size(10, 10), New System.Drawing.Size(-1, -1), termcrit) 
     features = featuresA(0).Length 

     ' Compute optical flow. Not necessary here but good to remember 
     Emgu.CV.OpticalFlow.PyrLK(grayA, grayB, pyrBufferA, pyrBufferB, featuresA(0), New Size(25, 25), 3, termcrit, flags, featuresB(0), status, errors) 
     Debug.Assert(featuresA(0).GetUpperBound(0) = featuresB(0).GetUpperBound(0)) 

     ' Copy features to an easier-to-use matrix and get min/max to create 3d points 
     Dim minx As Double = Double.MaxValue 
     Dim miny As Double = Double.MaxValue 
     Dim maxx As Double = Double.MinValue 
     Dim maxy As Double = Double.MinValue 
     pointsA = New Matrix(Of Single)(features, 2) 
     pointsB = New Matrix(Of Single)(features, 2) 
     For i As Integer = 0 To features - 1 
      pointsA(i, 0) = featuresA(0)(i).X 
      pointsA(i, 1) = featuresA(0)(i).Y 
      pointsB(i, 0) = featuresB(0)(i).X 
      pointsB(i, 1) = featuresB(0)(i).Y 
      If pointsA(i, 0) < minx Then 
       minx = pointsA(i, 0) 
      End If 
      If pointsA(i, 1) < miny Then 
       miny = pointsA(i, 1) 
      End If 
      If pointsA(i, 0) > maxx Then 
       maxx = pointsA(i, 0) 
      End If 
      If pointsA(i, 1) > maxy Then 
       maxy = pointsA(i, 1) 
      End If 
     Next 

     ' Create 3D object points that correspond to chessboard corners 
     ' (The chessboard is 1000*1000, squares are 125*125) 
     Dim corners As Integer = Sqrt(features) 
     Dim obj As New Matrix(Of Double)(features, 3) 
     Dim squaresize2dx As Double = (maxx - minx)/8 ' pixel width of a chessboard square 
     Dim squaresize2dy As Double = (maxy - miny)/8 ' pixel height of a chessboard square 
     For i As Integer = 0 To features - 1 
      obj(i, 0) = Math.Round((pointsA(i, 0) - minx)/squaresize2dx) * 125 ' X=0, 125, 250, 375 ... 1000 
      obj(i, 1) = Math.Round((pointsA(i, 1) - miny)/squaresize2dy) * 125 ' idem in Y 
      obj(i, 2) = 0 
      ' Debug.WriteLine(pointsA(i, 0) & " " & pointsA(i, 1) & " " & obj(i, 0) & " " & obj(i, 1) & " " & obj(i, 2)) ' Just to verify 
     Next 

     ' These were calculated with CalibrateCamera using the same images 
     Dim intrinsics As New Matrix(Of Double)({{889.1647, 0.0, 318.3721}, 
               {0.0, 888.5134, 238.4254}, 
               {0.0, 0.0, 1.0}}) 
     ' Find extrinsics 
     Dim distortion As New Matrix(Of Double)({-0.036302, 2.008797, -29.674306, -29.674306}) 
     Dim translation As New Matrix(Of Double)(3, 1) 
     Dim rotation As New Matrix(Of Double)(3, 1) 
     cvFindExtrinsicCameraParams2(obj, pointsA, intrinsics, distortion, rotation, translation, False) 

     ' Convert rotation vector to rotation matrix 
     Dim rotmat As New Matrix(Of Double)(3, 3) 
     Dim jacobian As New Matrix(Of Double)(9, 3) 
     cvRodrigues2(rotation, rotmat, jacobian) 

     ' From http://en.wikipedia.org/wiki/Rotation_representation paragraph "Conversion formulae between representations" 
     Dim yr As Double = Asin(-rotmat(2, 0)) 
     Dim xr As Double = Asin(rotmat(2, 1)/Cos(yr)) 
     Dim zr As Double = Asin(rotmat(1, 0)/Cos(yr)) 

    End Sub 
End Module 

的結果似乎不正確的,我期待的平移/旋轉,但我得到這個:

translation 
208.394425348956 
-169.447506344527 
-654.273807995629 
rotation 
-0.0224937226554797 
-2.13660350939653 
-1.10542281290682 
rotmat 
-0.741100224945266 0.322885083546921 -0.588655824237707 
-0.293966101915684 0.632206237134128 0.716867633983572 
0.603617749499279 0.704315622822328 -0.373610915174894 
xr=1.08307908108382 yr=-0.648031006135158 zr=-0.377625254910525 
xr=62.0558602250101° yr=-37.1294416451609° zr=-21.636333343925° 

會有人有一個想法,我做錯了嗎?謝謝!

+0

+1向我介紹cvRodrigues2()。乾杯! – coder9

回答

1

找到它。失真係數

k1, k2, p1, p2, k3 

,而不是

k1, k2, k3, k4, k5 

,因爲我曾編碼。當我將它們設置爲

-0.05716, 2.519006, -0.001674, -0.001021, -33.372798 

答案爲(大約)正確

1

請看針孔相機公式:

[u, v, 1]' ~ A * R|T * [x, y, z, 1]',其中外在矩陣 [R | T的尺寸爲3x4的。請注意,將它與無限遠處的'理想'或消失點相乘,例如[1,0,0,0]將給出R | T的對應列。這僅僅意味着要找到R | T的所有列,必須至少有三個可從棋盤圖案中找到的消失點。

現在你只有1個,所以如果你的結果看起來合理的話,你就很幸運。再試一次,並選擇最少10-20種不同的斜面,距離和校準裝置的傾斜度。