Преобразование изображения с использованием углов Roll-Pitch-Yaw (исправление изображения)

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

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

Я пытался сделать это с помощью OpenCV (С++) и Matlab, но, похоже, мне не хватает чего-то фундаментального в том, как это делается.

В Matlab я пробовал следующее:

%% Transform perspective
img = imread('my_favourite_image.jpg');
R = R_z(yaw_angle)*R_y(pitch_angle)*R_x(roll_angle);
tform = projective2d(R);   
outputImage = imwarp(img,tform);
figure(1), imshow(outputImage);

Где R_z/y/x — стандартные матрицы вращения (реализованные в градусах).

Для некоторого вращения по рысканию все работает просто отлично:

R = R_z(10)*R_y(0)*R_x(0);

Что дает результат:

Изображение повернуто на 10 градусов относительно оси Z-изображения

Если я попытаюсь повернуть изображение на одинаковую величину по осям X или Y, я получу такие результаты:

R = R_z(10)*R_y(0)*R_x(10);

Изображение повернуто на 10 градусов относительно оси X-изображения

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

R = R_z(10)*R_y(0)*R_x(10/1000);

Изображение повернуто на 10/1000 градусов относительно оси X-изображения

Может кто-нибудь, пожалуйста, помогите мне понять, почему вращение вокруг осей X или Y приводит к тому, что трансформация сходит с ума? Есть ли способ решить это без деления на какое-то случайное число и других фокусов? Может быть, это то, что можно решить, используя какие-то параметры Эйлера? Любая помощь будет высоко оценена!

Обновление: полная настройка и измерения

Для полноты добавлен полный тестовый код и исходное изображение, а также углы Эйлера платформ:

Код:

%% Transform perspective
function [] = main()
    img = imread('some_image.jpg');
    R = R_z(0)*R_y(0)*R_x(10);
    tform = projective2d(R);   
    outputImage = imwarp(img,tform);
    figure(1), imshow(outputImage);
end

%% Matrix for Yaw-rotation about the Z-axis
function [R] = R_z(psi)
    R = [cosd(psi) -sind(psi) 0;
         sind(psi)  cosd(psi) 0;
         0          0         1];
end

%% Matrix for Pitch-rotation about the Y-axis
function [R] = R_y(theta)
    R = [cosd(theta)    0   sind(theta);
         0              1   0          ;
         -sind(theta)   0   cosd(theta)     ];
end

%% Matrix for Roll-rotation about the X-axis
function [R] = R_x(phi)
    R = [1  0           0;
         0  cosd(phi)   -sind(phi);
         0  sind(phi)   cosd(phi)];
end

Исходное изображение:

введите здесь описание изображения

Размеры платформы камеры в системе координат BODY:

Roll:     -10
Pitch:    -30
Yaw:      166 (angular deviation from north)

Насколько я понимаю, угол рыскания не имеет прямого отношения к трансформации. Впрочем, я могу ошибаться в этом.

Дополнительная информация:

Я хотел бы уточнить, что среда, в которой будет использоваться установка, не содержит линий (фотографии океана), которые можно надежно использовать в качестве ориентира (горизонта обычно не будет на снимке). Кроме того, квадрат в исходном изображении просто используется как мера, чтобы увидеть, правильно ли преобразование, и его не будет в реальном сценарии.


person Tormod Haugene    schedule 07.12.2013    source источник
comment
Не могли бы вы загрузить исходное изображение и свою реализацию матрицы вращения?   -  person scap3y    schedule 08.12.2013
comment
Привет, Scap3y! Я добавил полный набор информации и код для проблемы в сообщение выше.   -  person Tormod Haugene    schedule 08.12.2013
comment
Хорошо, я думаю, вы пропустили важный шаг: нахождение омографии по отношению к горизонтальным проекциям линий на изображении. Перейдите по этой ссылке, чтобы понять, как заставить ее работать. После того, как вы рассчитали гомографию, вы можете вставить ее вместо вашей матрицы R, и это должно помочь.   -  person scap3y    schedule 08.12.2013
comment
Спасибо, сэр, за этот прекрасный совет. У меня нет линий (на самом деле вообще) на изображениях, которые я буду анализировать. Однако я думаю, что мог бы создать эти векторы коррекции непосредственно из углов RPY. Матрица коррекции выглядит разумной, так как затрагивает элементы в третьей строке матрицы преобразования. Именно эти элементы на самом деле сводят текущее преобразование с ума, если только они не умножаются на какое-то случайное небольшое число; Я считаю, что это могут быть те/те числа. Я вернусь к вам с результатом.   -  person Tormod Haugene    schedule 08.12.2013
comment
На изображении есть линии (стороны листа бумаги и линии вдоль дверной коробки должно быть достаточно, чтобы оценить горизонтальный вектор).   -  person scap3y    schedule 08.12.2013
comment
Я знаю эти строки. Однако в окружающей среде будет использоваться камера, нет четких линий (изображения океана с точки зрения птиц), поэтому мне придется найти другой способ решения. На самом деле, на самом деле никакого квадрата тоже нет, он просто используется как мера, чтобы увидеть, правильно ли я понимаю. :)   -  person Tormod Haugene    schedule 08.12.2013
comment
Ах хорошо. Это было бы хлопотно. Возможно, вы сможете получить 1 линию на изображении океана (горизонт), но этого определенно будет недостаточно, чтобы получить вектор (или, по крайней мере, не точную оценку того же самого). Всего наилучшего, и дайте мне знать, как оказывается.!   -  person scap3y    schedule 08.12.2013


Ответы (4)


Итак, вот что я в итоге сделал: я понял, что если вы на самом деле не имеете дело с 3D-изображениями, исправление перспективы фотографии — это 2D-операция. Имея это в виду, я заменил значения матрицы преобразования по оси Z нулями и единицами и применил к изображению двухмерное аффинное преобразование.

Вращение исходного изображения (см. исходный пост) с измеренным значением Roll = -10 и Pitch = -30 было выполнено следующим образом:

R_rotation = R_y(-60)*R_x(10); 
R_2d       = [   R_rot(1,1)  R_rot(1,2) 0; 
                 R_rot(2,1)  R_rot(2,2) 0;
                 0           0          1    ] 

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

Кроме того, при вращении изображения так, чтобы оно совпадало с заголовком платформы, может быть добавлен поворот вокруг оси Z, что дает:

R_rotation = R_y(-60)*R_x(10)*R_z(some_heading); 
R_2d       = [   R_rot(1,1)  R_rot(1,2) 0; 
                 R_rot(2,1)  R_rot(2,2) 0;
                 0           0          1    ] 

Обратите внимание, что это не меняет фактическое изображение, а только поворачивает его.

В результате исходное изображение, повернутое вокруг осей Y и X, выглядит так:

введите здесь описание изображения

Полный код для выполнения этого преобразования, показанный выше, был таким:

% Load image
img = imread('initial_image.jpg'); 

% Full rotation matrix. Z-axis included, but not used.
R_rot = R_y(-60)*R_x(10)*R_z(0); 

% Strip the values related to the Z-axis from R_rot
R_2d  = [   R_rot(1,1)  R_rot(1,2) 0; 
            R_rot(2,1)  R_rot(2,2) 0;
            0           0          1    ]; 

% Generate transformation matrix, and warp (matlab syntax)
tform = affine2d(R_2d);
outputImage = imwarp(img,tform);

% Display image
figure(1), imshow(outputImage);



%*** Rotation Matrix Functions ***%

%% Matrix for Yaw-rotation about the Z-axis
function [R] = R_z(psi)
    R = [cosd(psi) -sind(psi) 0;
         sind(psi)  cosd(psi) 0;
         0          0         1];
end

%% Matrix for Pitch-rotation about the Y-axis
function [R] = R_y(theta)
    R = [cosd(theta)    0   sind(theta);
         0              1   0          ;
         -sind(theta)   0   cosd(theta)     ];
end

%% Matrix for Roll-rotation about the X-axis
function [R] = R_x(phi)
    R = [1  0           0;
         0  cosd(phi)   -sind(phi);
         0  sind(phi)   cosd(phi)];
end

Спасибо за поддержку, надеюсь, кому-то это поможет!

person Tormod Haugene    schedule 09.12.2013
comment
Хорошо, я вижу, что вы сделали +10, потому что крен был -10 (-10 + 10 = 0), и -60, потому что шаг был -30 (-30-60 = -90). Но зачем вам вращать the remainder of (90-pitch) degrees in the counter-clockwise direction of the y-axis, and the positive roll angle clockwise of the x-axis? Почему бы вам не попытаться свести крен и тангаж обратно к 0? Почему установка Pitch на -90 градусов вместо 0 решает эту проблему? - person fariadantes; 30.03.2020

Я думаю, вы можете получить преобразование следующим образом:

1) Пусть у вас есть четыре 3d-точки A(-1,-1,0), B(1,-1,0), C(1,1,0) и D(-1,1,0). Вы можете взять любые 4 неколлинеарные точки. Они не связаны с изображением.

2) У вас есть матрица преобразования, поэтому вы можете настроить камеру, умножив координаты точек на матрицу преобразования. И вы получите 3D-координаты относительно положения/направления камеры.

3) Вам нужно получить проекцию ваших точек на плоскость экрана. Самый простой способ - использовать ортографическую проекцию (просто игнорируя координату глубины). На этом этапе у вас есть 2D-проекции преобразованных точек.

4) Когда у вас есть 2 набора координат 2D точек (набор из шага 1 без 3-й координаты и набор из шага 3), вы можете вычислить матрицу гомографии стандартным способом.

5) Примените обратное гомографическое преобразование к вашему изображению.

person Andrey Smorodov    schedule 09.12.2013
comment
Вы, безусловно, правы, что это 2D-преобразование. Спасибо! :) - person Tormod Haugene; 09.12.2013

Вам нужно оценить гомографию. Готовое решение Matlab см. в функции vgg_H_from_x_lin.m на сайте http://www.robots.ox.ac.uk/~vgg/hzbook/code/ .

Для теории покопайтесь в учебнике Computer Vision, таком как тот, который доступен бесплатно по адресу http://szeliski.org/Book/ или в главе 3 http://programmingcomputervision.com/downloads/ProgrammingComputerVision_CCdraft.pdf

person YXD    schedule 09.12.2013

Возможно, мой ответ неверен из-за неправильного понимания параметров камеры, но мне было интересно, связаны ли рысканье/тангаж/крен с положением вашего объекта. Я использовал формулу общего вращения, и мой код приведен ниже (функции вращения R_x , R_y и R_z скопированы из ваших, я их сюда не вставляла)

close all
file='http://i.stack.imgur.com/m5e01.jpg'; % original image
I=imread(file);

R_rot = R_x(-10)*R_y(-30)*R_z(166);
R_rot = inv(R_rot);

R_2d  = [   R_rot(1,1)  R_rot(1,2) 0; 
            R_rot(2,1)  R_rot(2,2) 0;
            0           0          1    ]; 


T = maketform('affine',R_2d);

transformedI = imtransform(I,T);
        figure, imshow(I), figure, imshow(transformedI)

Результат:

введите здесь описание изображения

Это указывает на то, что вам все еще нужна некоторая операция вращения, чтобы получить «правильное» выравнивание в уме (но, вероятно, не обязательно правильное положение в уме камеры). Поэтому я меняю R_rot = inv(R_rot); на R_rot = inv(R_rot)*R_x(-5)*R_y(25)*R_z(180);, и теперь это дало мне:

введите здесь описание изображения

Выглядит лучше, как то, что вы хотите. Спасибо.

person lennon310    schedule 09.12.2013
comment
Спасибо за ваш ответ! Я более или менее пришел к такому же выводу буквально минуту назад (см. третий пост в этой теме). Значения вращения имеют смысл, если вы поместите повороты в порядке YXZ и учтете, каково фактическое целевое состояние кадра камеры (камера направлена ​​прямо вниз сверху сцены). Для этого вам нужно повернуть рамку камеры на оставшуюся часть (90 шагов) градусов против часовой стрелки по оси Y и на положительный угол поворота по часовой стрелке по оси X. Вращение по рысканию не является обязательным и имеет значение только в том случае, если у вас есть платформа, ориентированная на север. :-) - person Tormod Haugene; 09.12.2013