Определение ориентации 3D объекта по изображению (Determining the orientation of a 3D object from an image)

Автор: | 05.02.2018

Постановка задачи
Алгоритм восстановления параметров положения
Алгоритм смены системы координат
Пример решения задачи
Контрольные задания
Полезные ссылки

Постановка задачи

Во многих задачах, связанных с компьютерным зрением, важно не только определять взаимное положение объектов в 3D пространстве, но и знать их ориентацию. Например, по ориентации  ракеты (см. Имитация полета крылатой ракеты) можно быстро определить какую цель она преследует и предпринять упреждающие действия. По ориентации лица можно завершить его 3D-реконструкцию (см. Распознавание лиц. 3D- реконструкция ASM модели).

При фотофиксации (проецировании объекта на плоскость) теряется одно измерение.  Как известно,  его можно  восстановить по двум и более изображениям. А можно ли по одному? Можно, если известна его форма — по искажениям размеров каких-либо элементов объекта.

Поставим конкретное задание – разработать программную систему, которая определяет по фотографии, какой из объектов отслеживается пирамидальной рупорной антенной.

Для установления взаимосвязи между объектами и изображением  используем 2 системы координат – локальную xyz   и глобальную XYZ.

В локальной СК определяется форма антенны и пирамида сканирования.  В глобальной СК определяется текущее положение точечных объектов сканирования (см. табл.). Плоскость XY глобальной СК совпадает с фото.

Фотокамера направлена перпендикулярно плоскости экрана,  рассматривается модель ортогонального проецирования. На фото показаны единичные отрезки каждой из осей локальной СК с учетом их искажений. Также указана натуральная величина единичного отрезка.

Для решения поставленной задачи необходимо:

  1. Восстановить параметры положения антенны в пространстве;
  2. Определить, какие из заданных объектов, попадают в область сканирования.

Задача решается на основе математического аппарата аффинных преобразований и графического способа определения матрицы преобразований для аксонометрической проекции.

Алгоритм восстановления параметров положения

Положение антенны относительно глобальной СК задаются  5-ю параметрами  – тремя углами  и двумя линейными величинами (p и h). С помощью аффинных преобразований можно математически описать зависимость между глобальной и локальной СК от начального положения антенны

до конечного положения антенны

с помощью матриц элементарных преобразований:

Последовательно перемножаем матрицы (см. Правила умножения матриц):

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

Составляем систему уравнений, приравнивая соответствующие коэффициенты матриц:

Выбираем 5 уравнений, которые позволяют наиболее просто решить систему относительно 5 искомых параметров положения:

Алгоритм смены системы координат

Чтобы определить, какие из объектов (точек) находятся в области сканирования антенны, необходимо выразить (пересчитать) координаты точек из глобальной системы координат XYZ  в локальную систему координат xyz, связанную с антенной. Затем, по фронтальной и профильной проекциях области сканирования антенны можно определить, какая из точек находится в пределах области сканирования  Условием попадания объекта в область сканирования является нахождение проекций объекта в пределах обеих проекций области сканирования.

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

Пример решения задачи

Задача по разработке программной системы,  которая  определяет, какой из объектов отслеживается пирамидальной рупорной антенной, была представлена на международной олимпиаде по САПР, проводимой в Хмельницком национальном университете в 2011 году. Ниже вкратце описано решение  Радченко Вячеслава из Донецкого национального технического университета (более подробно решение описано здесь).

При запуске программы (exe-шник программы вместе с фотографиями антенны можно скачать) открывается окно, в котором отображаются объекты сцены, наблюдаемые с определенного ракурса в системе координат антенны.

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

Задание: Запустите программу, загрузите фото антенны  и определите, какие точки-цели (см.таблицу), отслеживаются рупорной антенной.

Используются 2 фото, чтобы исключить вероятность ошибочного суждения из-за случайного попадания цели в зону пирамиды сканирования. Каждое фото фиксирует положение антенны через определенный промежуток времени. Точки-цели за это время перемещаются.

Размеры пирамиды сканирования указаны на рисунке.

Контрольные задания

Проверьте работоспособность  Алгоритма восстановления параметров положения антенны. Для этого продолжите модификацию приложения из статьи 3D графика на основе WinApi C++:

  • В функции  окна WndProc (в  файле main.cpp)  создайте и инициализируйте переменные (параметры положения антенны):
 static Action *action;
 static Engine *engine;
 //static bool x = true;
 static double alpha, beta, gamma, p, h;
 switch (messg)
 {
 case WM_CREATE:
 alpha = 30.0, beta = -30.0, gamma = 30.0, p = 0.2, h = 1.0;
 alpha = (alpha*(PI / 180));
 beta = (beta*(PI / 180));
 gamma = (gamma* (PI / 180));
 engine = new Engine();
  • Модифицируйте обработчик событий нажатий на клавиши 1-5, а также  еще добавьте обработчик нажатия на клавиши 8 и 9:
case WM_KEYDOWN:
 int KeyPressed;
 KeyPressed = int(wParam);
 if (KeyPressed == int('0'))
 {
 action->Transform_0();
 }
 if (KeyPressed == int('1'))
 {
 action->Transform_1(h);
 }
 if (KeyPressed == int('2'))
 {
 action->Transform_2(gamma);
 }
 if (KeyPressed == int('3'))
 {
 action->Transform_3(beta);
 }
 if (KeyPressed == int('4'))
 {
 action->Transform_4(alpha);
 }
 if (KeyPressed == int('5'))
 {
 action->Transform_5(p);
 }
 // здесь еще может быть обработка клавиш 6 и 7
 if (KeyPressed == int('8'))
 { 
 action->Transform_8(alpha, beta, gamma, p, h);
 }
 if (KeyPressed == int('9'))
 {
 beta = asin(- engine->dyz);
 alpha = asin(engine->dxz/cos(beta));
 gamma = acos(engine->dyy/cos(beta));
 h = engine->dx /(cos(beta)*sin(alpha));
 p = engine->dy + h * sin(beta);
 }
 InvalidateRect(hWnd, NULL, FALSE);
 break;

В коде изменены вызовы функций action->Transform_…(…) — эта функция теперь используется с параметром. Для обеспечения работоспособности программы необходимо внести соответствующие изменения в объявления и определения этих функций. Также необходимо модифицировать входящие функции Tr.SetTranslationMatrix_…(….), которые определяют матрицы преобразований.

При нажатии на клавишу 8 обеспечивается комплексное преобразование рупорной антенны — вместо 5 матриц элементарных преобразований используется всего лишь одна матрица (композиция преобразований). Описание матрицы приводится в разделе  Алгоритм восстановления параметров положения. Ниже представлен программный код для определения этой матрицы (в файле matrix.cpp).

 void Matrix::SetTranslationMatrix_8
 (double alpha, double beta, double gamma, double p, double h) 
{
 SetUnit();
 
 data[0][0] = cos(gamma)*cos(alpha)+sin(gamma)*sin(beta)*sin(alpha); // a 
 data[0][1] = sin(gamma)*cos(beta); // c 
 data[0][2] = -cos(gamma)*sin(alpha)+sin(gamma)*sin(beta)*cos(alpha); // p 
 //data[0][3] = 0.0; // 0 // m n l 1 //
 data[1][0] = -sin(gamma)*cos(alpha)+cos(gamma)*sin(beta)*sin(alpha); // b 
 data[1][1] = cos(gamma)*cos(beta); // d
 data[1][2] = sin(gamma)*sin(alpha)+cos(gamma)*sin(beta)*cos(alpha); // q
 //data[1][3] = 0.1; // 0
 data[2][0] = cos(beta)*sin(alpha); // h       // a c p 0 //
 data[2][1] = -sin(beta); // f                 // b d q 0 //
 data[2][2] = cos(beta)*cos(alpha); // r       // h f r 0 //
 //data[2][3] = 0.0; // 0                      // m n l 1 //
 data[3][0] = h*cos(beta)*sin(alpha); // m
 data[3][1] = -h*sin(beta)+p; // n 
 data[3][2] = h*cos(beta)*cos(alpha); // l
 //data[3][3] = 1.0; // 1
}

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

  • После модификации приложения запустите его и выполните преобразования антенны последовательным нажатием на клавиши 1-5. Подвигайте антенну мышкой.
  • Запустите приложение еще раз и нажмите на клавишу 8.  Подвигайте антенну мышкой. Если результаты преобразований совпадают с предыдущими, то  матрицы перемножены  правильно (см. Алгоритм восстановления параметров положения).
  • Модифицируйте код в файле engine.cpp
void Engine::Draw(HDC hdc) {
 .....
 rupor[12].y = 0.05;
 rupor[12].z = z;
 z = 0.0; // оси координат антенны
 // центр
 rupor[13].x = 0.0;
 rupor[13].y = 0.0;
 rupor[13].z = z;
 // ось X
 rupor[14].x = 1.0; // размеры всех осей делаем единичными.
 rupor[14].y = 0.0;
 rupor[14].z = z;
 // ось Y
 rupor[15].x = 0.0;
 rupor[15].y = 1.0;
 rupor[15].z = z;
 // ось Z
 rupor[16].x = 0.0;
 rupor[16].y = 0.0;
 rupor[16].z = 1.0;
 z = 0.0; // глобальная система координат
 // центр
 rupor[17].x = 0.0;
 rupor[17].y = 0.0;
 //rupor[17].z = 0.0;
 rupor[18].x = 1.0;
 rupor[18].y = 0.0;
 rupor[18].z = 0.0;
 rupor[19].x = 0.0;
 rupor[19].y = 1.0;
 rupor[19].z = 0.0;
 for (int i = 1; i < 17; i++) {
 //Вращение и перемещение осуществляется в логических координатах
 action->CurrentMatrix.ApplyMatrixtoPoint(rupor[i]);
 // Переход из логических в оконные координаты.
 //rupor[i] = viewport.T(rupor[i]);  // рано еще преобразовывать
 }
  dx = rupor[13].x - rupor[17].x;
  dy = rupor[13].y - rupor[17].y;
  dyz = rupor[16].y - dy;
  dxz = rupor[16].x - dx;
  dyy = -(dy - rupor[15].y);

for (int i = 1; i < 20; i++) { //здесь все точки преобразуем совместно
 //Переход из логических в оконные координаты.
 rupor[i] = viewport.T(rupor[i]);
 }
......
  • Поменяйте знаки параметров на противоположные в событиях нажатия на клавиши 1-5
case WM_KEYDOWN:
 int KeyPressed;
 KeyPressed = int(wParam);
 if (KeyPressed == int('0'))
 {
 action->Transform_0();
 }
 if (KeyPressed == int('1'))
 {
 action->Transform_1(-h);
 }
 if (KeyPressed == int('2'))
 {
 action->Transform_2(-gamma);
 }
 if (KeyPressed == int('3'))
 {
 action->Transform_3(-beta);
 }
 if (KeyPressed == int('4'))
 {
 action->Transform_4(-alpha);
 }
 if (KeyPressed == int('5'))
 {
 action->Transform_5(-p);
 }
  • Запустите приложение. Нажмите клавишу 8. Антенна должна принять рабочее положение. А затем нажмите клавиши 5-1 в последовательности 5, 4, 3, 2, 1. Антенна должна принять исходное положение, поскольку было выполнено последовательное обратное преобразование.

  • Запустите приложение снова. Нажмите клавиши 8, а затем 9. При нажатии на клавишу 9 параметры переопределяются уже непосредственно по текущему изображению (см. Алгоритм восстановления параметров положения).  Теперь нажмите клавиши 5-1 в последовательности 5, 4, 3, 2, 1. Если антенна принимает исходное положение, то это подтверждает, что параметры положения антенны восстановлены по изображению правильно.

 

Полезные ссылки:

 

Автор: Николай Свирневский