Почему нормали вершин переворачиваются после вращения трехмерных точечных облаков? - PullRequest
2 голосов
/ 29 апреля 2019

У меня есть два образца трехмерного облака точек человеческого лица.Синее облако точек обозначает целевую грань, а красное облако точек обозначает шаблон.На рисунке ниже показано, что цель и грань шаблона выровнены в разных направлениях (грань цели примерно вдоль оси x, грань шаблона примерно вдоль оси y).

Рисунок 1: enter image description here Область вокруг носа показана на рисунке 1.

Я хочу повернуть целевое лицо (синее лицо) кончиком носа, какцентр вращения (я перевел цель на шаблон до рисунка 1, так что кончик носа, то есть centerpt, для обеих граней накладывается), чтобы он выровнялся с гранью шаблона (красная грань).Я повернул целевую грань следующим кодом MATLAB:

% PCA for the target face
targetFaceptfmt = pointCloud(targetFace); % Convert to point cloud format
point = [templateFace(3522, 1), templateFace(3522, 2), templateFace(3522, 3)]; % The 3522th point in the templateFace is the nasal tip point used as center of rotation later on
radius = 20; % 20mm
[NNTarIndex, NNTarDist] = findNeighborsInRadius(Locationptfmt, point, radius); % Find all vertices within 20 of the nasal tip point on the target face
NNTar = select(Locationptfmt, NNTarIndex); % Select the identified points for PCA
[TarVec,TarSCORE,TarVal] = pca(NNTar.Location); % Do PCA for target face using vertices close to the nasal tip

% PCA for the template face
templateFaceptfmt = pointCloud(templateFace); % Convert to point cloud format
[NNTemIndex, NNTemDist] = findNeighborsInRadius( templateFaceptfmt, point, radius); % Find all vertices within 20 of the nasal tip point on the template
NNTem = select(templateFaceptfmt, NNTemIndex); % Select the identified points for PCA
[TemVec,TemSCORE,TemVal] = pca(NNTem.Location); % Do PCA for template face using vertices close to the nasal tip

% Rotate target face with nasal tip point as the center of rotation
targetFace_r = R * (targetFace-cenertpt)' + centerpt';
targetFace_new = targetFace_r';

, где targetFace и templateFace содержат координаты для необращенной целевой грани и грани шаблона соответственно.targetFace_r содержит координаты для целевой грани после поворота вокруг кончика носа, R - матрица вращения, рассчитанная с помощью PCA (см. здесь для определения формулы вращения), а centerpt - носовойнаконечник, который используется в качестве центра вращения.Затем я построил транспонированную targetFace_r, то есть targetFace_new, с нормалями, добавленными к каждой вершине:

Рисунок 2: enter image description here

Перед вращением,нормали для целевой грани и грани шаблона обычно указывают в одинаковых направлениях (рисунок 1).После поворота цель и грань шаблона выровнены вдоль оси y (что я и хочу), однако нормали для целевой грани и грани шаблона указывают в противоположные стороны.Принимая во внимание, что не было никаких изменений в грани шаблона, я понял, что нормалей целевой грани, вычисленных после вращения, перевернуты.Но я не знаю почему. Я использовал функцию checkFaceOrientation пакета Rvcg в R, чтобы проверить, увеличивает ли расширение по нормали размер центроида.Мне вернули значение ИСТИНА для грани шаблона, но ЛОЖЬ для целевой грани, которая подтверждает, что нормали вершин для целевой грани были перевернуты.

Нормы вершин были вычислены в MATLAB следующим образом:

TR = triangulation(Faces, Vertices); % Triangulation based on face and vertex information
VN = vertexNormal(TR); % Calculate vertext normal

где Faces содержит информацию о лице, т. е. список связности, а Vertices содержит координаты для вершин.Для целевой грани перед вращением, целевой грани после вращения и грани шаблона нормали вершин вычислялись отдельно.Я использовал те же самые данные Faces для вычисления нормали вершины до и после вращения целевой грани.

Перевернутые нормали вершины привели к ошибкам для дальнейшего анализа.В результате я должен вручную перевернуть нормали, чтобы они указывали аналогично нормали на лицевой стороне шаблона.

Рисунок 3: enter image description here На рисунке 3 показано, что после переворачивания нормалей вручнуюнормали целевого лица и грани шаблона обычно указывают одинаково в направлении.

Мой вопрос: почему нормали целевого лица, вычисленные после поворота, перевернулись?В каком случае вращение трехмерного облака точек приводит к перевороту нормалей вершин?

Дополнительная информация, которая может оказаться полезной: полученная мной матрица вращения R выглядит следующим образом:

0.0473096146726546  0.867593376108813   -0.495018720950670
0.987013081649028   0.0355601323276586  0.156654567895508
-0.153515396665006  0.496001220483328   0.854643675613313

С trace(R) = 1 + 2cos(alpha) я вычислил альфа через acos((trace(R)-1)/2)*180/pi, что дало угол поворота 91,7904 относительно точки кончика носа.

Ответы [ 2 ]

3 голосов
/ 30 апреля 2019

Если я все правильно понимаю, похоже, ваша матрица вращения фактически кодирует вращение плюс отражение.Если ваша матрица приблизительно равна:

 0.04  0.86  -0.49
 0.98  0.03   0.15
-0.15  0.49   0.85

, то изображение каждого единичного вектора, указывающего вдоль положительных осей, будет:

x = [ 0.04 0.98 -0.15]
y = [ 0.86 0.03  0.49]
z = [-0.49 0.15  0.85]

Однако, если вы берете перекрестное произведение x и y (cross(x, y)), вы получите примерно [0.49 -0.15 -0.85], что является отрицанием z, что означает, что матрица кодирует как поворот, так и отражение.Естественно, умножение вершин меша на матрицу отражения приведет к изменению порядка намотки его многоугольников и получению инвертированных нормалей.

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

2 голосов
/ 30 апреля 2019

Как указано в комментариях к , направление нормали к вершине будет зависеть от того, как вы упорядочили треугольные грани в матрице Faces.Это будет следовать правилу для правой руки , где ваши пальцы следуют порядку вершин вокруг треугольника, а большой палец указывает на нормальное направление поверхности.Вот простой пример, чтобы проиллюстрировать это:

Vertices = [0 0; 0 1; 1 1; 1 0];  % Points clockwise around a unit square in x-y plane
Faces = [1 2 3; 1 3 4];           % Two triangular facets, clockwise vertex ordering
TR = triangulation(Faces, Vertices);
VN = vertexNormal(TR)

VN =

     0     0    -1
     0     0    -1
     0     0    -1
     0     0    -1

В этом примере Vertices содержит 4 вершины единичного квадрата в плоскости xy, упорядоченные по часовой стрелке, если вы смотрите вниз с положительного z.Две треугольные грани определены в Faces, и порядок индексов в каждой строке также проходит по вершинам по часовой стрелке.В результате получается поверхность , нормальная для каждой грани, которая указывает в отрицательном направлении z.Когда вычисляются нормали vertex , они также указывают в отрицательном направлении z.

Что происходит, когда мы переворачиваем порядок одного треугольника так, чтобы его точки были против часовой стрелки ?...

Faces = [1 2 3; 1 4 3];  % Second facet is 1 4 3 instead of 1 3 4
TR = triangulation(Faces, Vertices);
VN = vertexNormal(TR)

VN =

     0     0     0
     0     0    -1
     0     0     0
     0     0     1

Поверхность нормали второго треугольника теперь будет указывать в положительном направлении z.Вершины, которые используются только одним треугольником (строки 2 и 4), будут иметь нормали вершин, которые соответствуют нормалям поверхности, в то время как вершины, общие для каждой (строки 1 и 3), будут иметь нормали вершин 0 (две нормали поверхности отменяются).

Как это поможет вам в вашей проблеме?Ну, трудно сказать, так как я не знаю точно, как вы определяете Faces и Vertices.Однако, если вы точно знаете, что каждая нормаль вершины в вашей сетке указывает в неправильном направлении, вы можете легко перевернуть их все, поменяв двумя столбцами в матрице Faces перед вычислением нормалей:

Faces = [1 2 3; 1 3 4];  % Clockwise-ordered vertices
TR = triangulation(Faces(:, [1 3 2]), Vertices);  % Change to counter-clockwise
VN = vertexNormal(TR)

VN =

     0     0     1  % Normals are now pointing in positive z
     0     0     1
     0     0     1
     0     0     1
...