Неправильный расчет внешнего вида камеры - PullRequest
3 голосов
/ 22 сентября 2011

Я пытаюсь найти изображение камеры из 2 изображений.У меня есть встроенные функции CameraCalibration, и сцена имеет известные размеры (созданные с помощью 3DSMAX).

Шахматная доска - 1000 * 1000, каждый квадрат 125, 125.Камера в (0,0,3000) смотрит прямо на шахматную доску, которая находится в центре в начале координат.На втором изображении камера переводится (-1500, 0, -402) и поворачивается на 30 ° по оси Y, чтобы снова указывать на центр шахматной доски: camera setup

GoodFeaturesToTrack правильно определяет 81углы: chessboards

Я создаю трехмерные точки углов шахматной доски, cvFindExtrinsicCameraParams2 для вычисления внутренних и 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°

Кто-нибудь может понять, что яделать неправильно?Спасибо!

Ответы [ 2 ]

1 голос
/ 24 февраля 2014

Пожалуйста, посмотрите на уравнение камеры с точечным отверстием:

[u, v, 1]' ~ A * R|T * [x, y, z, 1]', где внешняя матрица R | T имеет размеры 3х4. Обратите внимание, что умножение его на «идеальную» или исчезающую точку на бесконечности, такое как [1,0,0,0], даст вам соответствующий столбец R | T. Это просто означает, что для поиска всех столбцов R | T вам нужно иметь как минимум три точек схода, которые можно легко найти по вашим шахматным фигурам.

Пока у вас есть только 1, так что вам просто повезло, если ваши результаты выглядят разумно. Попробуйте еще раз и выберите минимум 10-20 различных наклонов, расстояний и наклонов калибровочной установки.

1 голос
/ 22 сентября 2011

Нашел это.Коэффициенты искажения

k1, k2, p1, p2, k3

, а не

k1, k2, k3, k4, k5

, как я кодировал.Когда я устанавливаю их на

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

, ответ (примерно) правильный

...