Триангуляция с использованием прямого линейного преобразования, взятого непосредственно у Хартли и Циссермана - PullRequest
2 голосов
/ 20 февраля 2011

Ниже приведена функция Matlab, которая реализует метод триангуляции, как описано в Multiple View Geometry.Он берет 8 угловых точек куба (OriginalPoints) и проецирует их на два экрана.Точки экрана тогда находятся в CameraPoints и ProjectorPoints.Цель состоит в том, чтобы восстановить исходные точки из этих двух представлений, используя прямое линейное преобразование.К сожалению, результат - бред.

В SO есть еще одна тема , из которой взята нормализация строк A, но это не улучшило результат.

Три общих вопроса:

  • При нормализации данных перед SVD (origin = centroid и avg distance = sqrt (2)), вычислять ли среднее расстояние по (x, y) или (x, y, w)?Неоднородный или однородный?
  • После каждой операции, где это возможно, я масштабирую однородную координату w до 1,0, это правильно?
  • Поскольку матрицы камеры известны полностью (не только допроективное преобразование) результирующие точки должны отличаться не более чем от исходных точек, чем евклидово преобразование, верно?

    % Demos the triangulation method using the direct linear transform
    % algorithm
    function testTriangulation()
        close all;

    camWidth = 800;
    camHeight = 600;
    projectorWidth = 5080;
    projectorHeight = 760;

    % camera matrices
    CameraMatrix =    [
                    -1.81066 0.00000 0.00000 0.00000;
                    0.00000 2.41421 0.00000 0.00000;
                    0.00000 0.00000 1.00000 1.50000
                ];

    ProjectorMatrix =   [
                    -0.36118 0.00000 0.00000 0.00000
                    0.00000 2.00875 1.33916 0.00000
                    0.00000 -0.55470 0.83205 1.80278
                ];

    % generating original points and displaying them
    OriginalPoints =    [
                            -0.2 -0.2 -0.2 -0.2 0.2 0.2 0.2 0.2;
                            -0.2 -0.2 0.2 0.2 -0.2 -0.2 0.2 0.2;
                            -0.2 0.2 -0.2 0.2 -0.2 0.2 -0.2 0.2;
                            1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
                        ];    
    scatter3(OriginalPoints(1, :), OriginalPoints(2, :), OriginalPoints(3,:));
    title('Original Points');

    % projecting and normalizing camera points
    CameraPoints = CameraMatrix * OriginalPoints;
    for i = 1:3
        CameraPoints(i, :) = CameraPoints(i, :) ./ CameraPoints(3,:);
    end
    %     figure();
    %     scatter(CameraPoints(1,:), CameraPoints(2,:));
    %     title('Projected Camera Points');

    % transforming camera points to screen coordinates
    camXOffset = camWidth / 2;
    camYOffset = camHeight / 2; 
    CameraPoints(1,:) = CameraPoints(1,:) * camXOffset + camXOffset;
    CameraPoints(2,:) = CameraPoints(2,:) * camYOffset + camYOffset;
    figure();
    scatter(CameraPoints(1,:), CameraPoints(2,:));
    title('Projected Camera Points in Screen Coordinates');


    % projecting and normalizing projector points
    ProjectorPoints = ProjectorMatrix * OriginalPoints;
    for i = 1:3
        ProjectorPoints(i, :) = ProjectorPoints(i, :) ./ ProjectorPoints(3,:);
    end
    %     figure();
    %     scatter(ProjectorPoints(1,:), ProjectorPoints(2,:));
    %     title('Projected Projector Points');

    % transforming projector points to screen coordinates
    projectorXOffset = projectorWidth / 2;
    projectorYOffset = projectorHeight / 2; 
    ProjectorPoints(1,:) = ProjectorPoints(1,:) * projectorXOffset + projectorXOffset;
    ProjectorPoints(2,:) = ProjectorPoints(2,:) * projectorYOffset + projectorYOffset;
    figure();
    scatter(ProjectorPoints(1,:), ProjectorPoints(2,:));
    title('Projected Projector Points in Screen Coordinates');


    % normalizing camera points (i.e. origin is
    % the centroid and average distance is sqrt(2)).
    camCenter = mean(CameraPoints, 2);
    CameraPoints(1,:) =  CameraPoints(1,:) - camCenter(1);
    CameraPoints(2,:) = CameraPoints(2,:) - camCenter(2);
    avgDistance = 0.0;
    for i = 1:length(CameraPoints(1,:))
        avgDistance = avgDistance + norm(CameraPoints(:, i));
    end
    avgDistance = avgDistance / length(CameraPoints(1, :));
    scaleFactor = sqrt(2) / avgDistance;
    CameraPoints(1:2, :) = CameraPoints(1:2, :) * scaleFactor;

    % normalizing projector points (i.e. origin is
    % the centroid and average distance is sqrt(2)).
    projectorCenter = mean(ProjectorPoints, 2);
    ProjectorPoints(1,:) =  ProjectorPoints(1,:) - projectorCenter(1);
    ProjectorPoints(2,:) = ProjectorPoints(2,:) - projectorCenter(2);
    avgDistance = 0.0;
    for i = 1:length(ProjectorPoints(1,:))
        avgDistance = avgDistance + norm(ProjectorPoints(:, i));
    end
    avgDistance = avgDistance / length(ProjectorPoints(1, :));
    scaleFactor = sqrt(2) / avgDistance;
    ProjectorPoints(1:2, :) = ProjectorPoints(1:2, :) * scaleFactor;


    % triangulating points
    TriangulatedPoints = zeros(size(OriginalPoints));
    for i = 1:length(OriginalPoints(1, :))
        A = [
                CameraPoints(1, i) * CameraMatrix(3, :) - CameraMatrix(1, :);
                CameraPoints(2, i) * CameraMatrix(3, :) - CameraMatrix(2, :);
                ProjectorPoints(1, i) * ProjectorMatrix(3,:) - ProjectorMatrix(1,:);
                ProjectorPoints(2, i) * ProjectorMatrix(3,:) - ProjectorMatrix(2,:)
            ];

        % normalizing rows of A, as suggested in a topic on StackOverflow
        A(1,:) = A(1,:)/norm(A(1,:));
        A(2,:) = A(2,:)/norm(A(2,:));
        A(3,:) = A(3,:)/norm(A(3,:));
        A(4,:) = A(4,:)/norm(A(4,:));

        [U S V] = svd(A);
        TriangulatedPoints(:, i) = V(:, end);
    end
    for i = 1:4
        TriangulatedPoints(i, :) = TriangulatedPoints(i, :) ./ TriangulatedPoints(4, :);
    end
    figure()
    scatter3(TriangulatedPoints(1, :), TriangulatedPoints(2, :), TriangulatedPoints(3, :));
    title('Triangulated Points');

1 Ответ

1 голос
/ 08 марта 2011

Чего не хватало в приведенном выше коде, так это то, что матрицы камеры также необходимо преобразовать с помощью нормализующего преобразования.Ниже приведен пример, который работает.Отметим также разницу в структуре нормализующих преобразований.В примере вопроса коэффициент масштабирования помещается в последний элемент.Ниже он умножается на все элементы, так что последний элемент равен 1.


function testTriangulationDavid()
  close all
  clear all

  P = [
      -1.81066 0.00000 0.00000 0.00000;
      0.00000 2.41421 0.00000 0.00000;
      0.00000 0.00000 1.00000 1.50000
      ];

  Q =  [
      -0.36118 0.00000 0.00000 0.00000
      0.00000 2.00875 1.33916 0.00000
      0.00000 -0.55470 0.83205 1.80278
      ];


  % homogenous 3D coordinates
  Pts =  [
          -0.2 -0.2 -0.2 -0.2 0.2 0.2 0.2 0.2;
          -0.2 -0.2 0.2 0.2 -0.2 -0.2 0.2 0.2;
          -0.2 0.2 -0.2 0.2 -0.2 0.2 -0.2 0.2;
          1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
      ];    

  numPts = length(Pts(1,:));

  % project points
  PPtsHom = P*Pts;
  QPtsHom = Q*Pts;

  % normalize for homogenous scaling
  for i = 1:3
      PPtsHom(i, :) = PPtsHom(i, :) ./ PPtsHom(3, :);
      QPtsHom(i, :) = QPtsHom(i, :) ./ QPtsHom(3, :);
  end

  % 2D cartesian coordinates
  PPtsCart = PPtsHom(1:2,:);
  QPtsCart = QPtsHom(1:2,:);



  % compute normalizing transform

  % calc centroid
  centroidPPtsCart = mean(PPtsCart,2);
  centroidQPtsCart = mean(QPtsCart,2);

  % calc mean distance to centroid
  normsPPtsCart = zeros(1, numPts);
  normsQPtsCart = zeros(1, numPts);
  for i = 1:numPts
    normsPPtsCart(1,i) = norm(PPtsCart(:,i) - centroidPPtsCart);
    normsQPtsCart(1,i) = norm(QPtsCart(:,i) - centroidQPtsCart);
  end
  mdcPPtsCart = mean(normsPPtsCart);
  mdcQPtsCart = mean(normsQPtsCart);

  % setup transformation
  scaleP = sqrt(2)/mdcPPtsCart;
  scaleQ = sqrt(2)/mdcQPtsCart;

  tP = [ scaleP 0      -scaleP*centroidPPtsCart(1);
    0      scaleP -scaleP*centroidPPtsCart(2);
    0      0      1];
  tQ = [ scaleQ 0      -scaleQ*centroidQPtsCart(1);
    0      scaleQ -scaleQ*centroidQPtsCart(2);
    0      0      1];


  % transform points
  PPtsHom = tP * PPtsHom;
  QPtsHom = tQ * QPtsHom;

  % normalize for homogenous scaling
  for i = 1:3
      PPtsHom(i, :) = PPtsHom(i, :) ./ PPtsHom(3, :);
      QPtsHom(i, :) = QPtsHom(i, :) ./ QPtsHom(3, :);
  end
  % 2D cartesian coordinates
  PPtsCart = PPtsHom(1:2,:);
  QPtsCart = QPtsHom(1:2,:);

  % transform cameras
  P = tP * P;
  Q = tQ * Q;


  % triangulating points
  TriangulatedPoints = zeros(4,numPts);
  for i = 1:numPts
      A = [
          PPtsCart(1, i) * P(3, :) - P(1, :);
          PPtsCart(2, i) * P(3, :) - P(2, :);
          QPtsCart(1, i) * Q(3,:) - Q(1,:);
          QPtsCart(2, i) * Q(3,:) - Q(2,:)
      ]
      return;

      [U S V] = svd(A);
      TriangulatedPoints(:, i) = V(:, end);
  end
  for i = 1:4
      TriangulatedPoints(i, :) = TriangulatedPoints(i, :) ./ TriangulatedPoints(4, :);
  end
  figure()
  scatter3(TriangulatedPoints(1, :), TriangulatedPoints(2, :), TriangulatedPoints(3, :));
  title('Triangulated Points');
  axis equal;
...