2009-02-09 8 views
6

У меня есть приложение, которое определяет прямоугольник реального мира поверх изображения/фотографии, конечно, в 2D это может быть не прямоугольник, потому что вы смотрите на него под углом ,Как нарисовать перспективно-правильную сетку в 2D

Проблема заключается в том, что прямоугольник должен иметь нарисованные на нем линии сетки, например, если это 3x5, поэтому мне нужно нарисовать две линии со стороны 1 на сторону 3 и 4 линии со стороны 2 на сторону 4

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

Кто-нибудь знает имя алгоритма, который я должен искать?

Да, я знаю, что вы можете сделать это в 3D, однако я ограничен 2D для этого конкретного приложения.

+0

Так пример, возможно, пытается нарисовать прямоугольник на окне в картине? – MSN

+0

да, это был бы пример –

+0

вам повезло с этим проектом? Мне нужно что-то очень похожее! спасибо – PyWebDesign

ответ

14

Вот решение: http://freespace.virgin.net/hugo.elias/graphics/x_persp.htm

Основная идея вы можете найти в перспективе правильный «центр» вашего прямоугольника, подключив углы по диагонали. Пересечение двух результирующих линий - ваш правильный правильный центр. Оттуда вы разделите свой прямоугольник на четыре меньших прямоугольника, и вы повторите этот процесс. Количество раз зависит от того, насколько вы точны. Вы можете подразделить чуть ниже размера пикселя для эффективной идеальной перспективы.

Затем в ваших подэлеантах вы просто применяете свои стандартные нескорректированные «текстурированные» треугольники или прямоугольники или что угодно.

Вы можете выполнить этот алгоритм, не перейдя к сложной проблеме построения «реального» 3D-мира. это также хорошо, если у вас есть do, но у вас есть реальный 3D-мир, но ваши текстовые диаграммы не скорректированы на аппаратном уровне, или вам нужен эффективный способ получить перспективные правильные плоскости без обмана.

+0

Будет ли это решение работать только для сетей с мощностью 2? – Ipsquiggle

+1

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

-1

Проблема в том, что это преобразование из 3D в 2D, которое вас доставит.

Here учебник о том, как это делается.

+0

Это striclty 2D, от 3D-данных нет данных. –

4

Хотя мой google-fu не смог создать какое-либо твердое математическое решение, возможно, этот чертеж, который я нашел, может немного помочь.

http://studiochalkboard.evansville.edu/lp-diminish.html

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

+0

Спасибо, что на самом деле очень ценно. ваши навыки Google определенно опережают меня. –

-1

Что вам нужно сделать, это представить его в 3D (мир), а затем проецировать его на 2D (экран).

Для этого потребуется использовать матрицу преобразования 4D, которая выполняет проекцию на 4D, однородную до трехмерного однородного вектора, которую вы затем можете преобразовать в вектор 2D пространственного пространства.

Я тоже не мог найти его в Google, но в хороших книгах по компьютерной графике будут подробные сведения.

Ключевые слова являются матрицу проекции, преобразование проекции, преобразование аффинным, однородны вектор, мировое пространство, пространство экрана, преобразование перспективы, 3D преобразование

И, кстати, это обычно занимает несколько лекций, чтобы объяснить все это. Удачи.

+2

Использование 3D-математики для достижения этого - массивный перебор, чрезвычайно сложный вычислительный процесс, чем требуется. – Sparr

+1

Его просто куча математики, которая не требует ввода-вывода. Так было бы очень быстро. – Pyrolistical

+2

«супер быстрый» относительный. Не использование 3D-математики было бы «супер быстрым» ER. Бросание миллионов процессорных циклов на проблему, которая должна занять тысячи, просто требует неприятностей. Что происходит, когда он решает использовать сетку 1024x1024 вместо 5x5? – Sparr

3

Используя метод подразделения Бретона (который связан с методом расширения Монго), вы получите точную произвольную силу двух дивизий. Чтобы разделить на не-два-два подразделения с помощью этих методов, вам придется подразделить на подпиксельные интервалы, которые могут быть дорогостоящими.

Однако, я считаю, что вы можете применить вариацию Haga's Theorem (которая используется в оригами для разделения стороны на Nths, учитывая сторону, разделенную на (N-1) ths) на квадраты с перспективой, чтобы произвести произвольные деления от ближайшей силы 2 без продолжения разделения.

+0

Теорема Хаги была очень интересной, но она применима только к квадратам. С переменным отношением h/w к моим прямоугольникам я не могу найти способ применить эту теорему. –

+1

Вместо того, чтобы перейти к субпиксельной точности, я думаю, что я собираюсь выполнить «двоичный поиск» для каждого подразделения. Поэтому, если мне нужно разделить мой прямоугольник на трети, я бы в основном выполнял двоичный поиск с определенной точностью до 33,33% и 66,66%, затем выполнял взвешенное деление пополам с использованием каждой «части» (а по части я имею в виду, если Я делясь пополам 4 раза, это будет соответствовать правильной перспективе 16) –

0

В специальном случае, когда вы смотрите перпендикулярно сторонам 1 и 3, вы можете разделить эти стороны на равные части. Затем нарисуйте диагональ и проведите параллели со стороной 1 через каждое пересечение диагонали и разделительных линий, проведенных ранее.

1

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

С достойной матричной библиотекой это не должно быть трудной задачей, если вы знаете свою математику.

Ключевые слова: коллинеацию, гомография, прямая линейная трансформация

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

6

image description Изображение: Пример билинейной & перспективного преобразование (Примечание: Высота верхних & нижних горизонтальных линий сетки фактически половина высоты остальных линий, на обоих чертежах)

======= =================================

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

Я начинаю на самом деле с аналогичной проблемой: нарисовать 2D-перспективную сетку, а затем трансформировать подчеркивание для восстановления перспективы.

Я начал читать здесь: http://www.imagemagick.org/Usage/distorts/#bilinear_forward

, а затем здесь (Leptonica Library): http://www.leptonica.com/affine.html

были я нашел это:

Когда вы смотрите на объект в плоскости с произвольного направления на на конечном расстоянии, вы получите дополнительное «искажение трапецеидального искажения» в изображении .Это проективное преобразование, которое прячет прямые линии , но не сохраняет углы между линиями. Эта деформация не может быть описана линейным аффинным преобразованием, и на самом деле отличается в знаменателе х- и y-зависимыми членами.

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

Чтобы избежать включения всей библиотеки Leptonica в моем проекте, я взял некоторые куски кода из него, я удалил все специальное Leptonica типов данных & макросов, я исправлены некоторые утечки памяти, и я преобразовал его в C++ класса (в основном для причины инкапсуляции), что делает только одно: Он сопоставляет координату QPointF float (x, y) с соответствующей Перспективной координатой.

Если вы хотите адаптировать код к другой библиотеке C++, единственное, что нужно переопределить/заменить, это класс координат QPointF.

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

А. Пример того, как использовать genImageProjective C++ класс нарисовать 2D Сетка перспективы

B. genImageProjective.h файл

C. genImageProjective. cpp file

//============================================================ 
// C++ Code Example on how to use the 
//  genImageProjective class to draw a perspective 2D Grid 
//============================================================ 

#include "genImageProjective.h" 

// Input: 4 Perspective-Tranformed points: 
//  perspPoints[0] = top-left 
//  perspPoints[1] = top-right 
//  perspPoints[2] = bottom-right 
//  perspPoints[3] = bottom-left 
void drawGrid(QPointF *perspPoints) 
{ 
(...) 
     // Setup a non-transformed area rectangle 
     // I use a simple square rectangle here because in this case we are not interested in the source-rectangle, 
     // (we want to just draw a grid on the perspPoints[] area) 
     // but you can use any arbitrary rectangle to perform a real mapping to the perspPoints[] area 
     QPointF topLeft = QPointF(0,0); 
     QPointF topRight = QPointF(1000,0); 
     QPointF bottomRight = QPointF(1000,1000); 
     QPointF bottomLeft = QPointF(0,1000); 
     float width = topRight.x() - topLeft.x(); 
     float height = bottomLeft.y() - topLeft.y(); 

     // Setup Projective trasform object 
     genImageProjective imageProjective; 
     imageProjective.sourceArea[0] = topLeft; 
     imageProjective.sourceArea[1] = topRight; 
     imageProjective.sourceArea[2] = bottomRight; 
     imageProjective.sourceArea[3] = bottomLeft; 
     imageProjective.destArea[0] = perspPoints[0]; 
     imageProjective.destArea[1] = perspPoints[1]; 
     imageProjective.destArea[2] = perspPoints[2]; 
     imageProjective.destArea[3] = perspPoints[3]; 
     // Compute projective transform coefficients 
     if (imageProjective.computeCoeefficients() != 0) 
      return; // This can actually fail if any 3 points of Source or Dest are colinear 

     // Initialize Grid parameters (without transform) 
     float gridFirstLine = 0.1f; // The normalized position of first Grid Line (0.0 to 1.0) 
     float gridStep = 0.1f;  // The normalized Grd size (=distance between grid lines: 0.0 to 1.0) 

     // Draw Horizonal Grid lines 
     QPointF lineStart, lineEnd, tempPnt; 
     for (float pos = gridFirstLine; pos <= 1.0f; pos += gridStep) 
     { 
      // Compute Grid Line Start 
      tempPnt = QPointF(topLeft.x(), topLeft.y() + pos*width); 
      imageProjective.mapSourceToDestPoint(tempPnt, lineStart); 
      // Compute Grid Line End 
      tempPnt = QPointF(topRight.x(), topLeft.y() + pos*width); 
      imageProjective.mapSourceToDestPoint(tempPnt, lineEnd); 

      // Draw Horizontal Line (use your prefered method to draw the line) 
      (...) 
     } 
     // Draw Vertical Grid lines 
     for (float pos = gridFirstLine; pos <= 1.0f; pos += gridStep) 
     { 
      // Compute Grid Line Start 
      tempPnt = QPointF(topLeft.x() + pos*height, topLeft.y()); 
      imageProjective.mapSourceToDestPoint(tempPnt, lineStart); 
      // Compute Grid Line End 
      tempPnt = QPointF(topLeft.x() + pos*height, bottomLeft.y()); 
      imageProjective.mapSourceToDestPoint(tempPnt, lineEnd); 

      // Draw Vertical Line (use your prefered method to draw the line) 
      (...) 
     } 
(...) 
} 

========================================== 



//======================================== 
//C++ Header File: genImageProjective.h 
//======================================== 

#ifndef GENIMAGE_H 
#define GENIMAGE_H 

#include <QPointF> 

// Class to transform an Image Point using Perspective transformation 
class genImageProjective 
{ 
public: 
    genImageProjective(); 

    int computeCoeefficients(void); 
    int mapSourceToDestPoint(QPointF& sourcePoint, QPointF& destPoint); 

public: 
    QPointF sourceArea[4]; // Source Image area limits (Rectangular) 
    QPointF destArea[4]; // Destination Image area limits (Perspectivelly Transformed) 

private: 
    static int gaussjordan(float **a, float *b, int n); 

    bool coefficientsComputed; 
    float vc[8];   // Vector of Transform Coefficients 
}; 

#endif // GENIMAGE_H 
//======================================== 


//======================================== 
//C++ CPP File: genImageProjective.cpp 
//======================================== 

#include <math.h> 
#include "genImageProjective.h" 

// ---------------------------------------------------- 
// class genImageProjective 
// ---------------------------------------------------- 
genImageProjective::genImageProjective() 
{ 
    sourceArea[0] = sourceArea[1] = sourceArea[2] = sourceArea[3] = QPointF(0,0); 
    destArea[0] = destArea[1] = destArea[2] = destArea[3] = QPointF(0,0); 
    coefficientsComputed = false; 
} 


// -------------------------------------------------------------- 
// Compute projective transform coeeeficients 
// RetValue: 0: Success, !=0: Error 
/*-------------------------------------------------------------* 
*    Projective coordinate transformation   * 
*-------------------------------------------------------------*/ 
/*! 
* computeCoeefficients() 
* 
*  Input: this->sourceArea[4]: (source 4 points; unprimed) 
*    this->destArea[4]: (transformed 4 points; primed) 
*    this->vc (computed vector of transform coefficients) 
*  Return: 0 if OK; <0 on error 
* 
* We have a set of 8 equations, describing the projective 
* transformation that takes 4 points (sourceArea) into 4 other 
* points (destArea). These equations are: 
* 
*   x1' = (c[0]*x1 + c[1]*y1 + c[2])/(c[6]*x1 + c[7]*y1 + 1) 
*   y1' = (c[3]*x1 + c[4]*y1 + c[5])/(c[6]*x1 + c[7]*y1 + 1) 
*   x2' = (c[0]*x2 + c[1]*y2 + c[2])/(c[6]*x2 + c[7]*y2 + 1) 
*   y2' = (c[3]*x2 + c[4]*y2 + c[5])/(c[6]*x2 + c[7]*y2 + 1) 
*   x3' = (c[0]*x3 + c[1]*y3 + c[2])/(c[6]*x3 + c[7]*y3 + 1) 
*   y3' = (c[3]*x3 + c[4]*y3 + c[5])/(c[6]*x3 + c[7]*y3 + 1) 
*   x4' = (c[0]*x4 + c[1]*y4 + c[2])/(c[6]*x4 + c[7]*y4 + 1) 
*   y4' = (c[3]*x4 + c[4]*y4 + c[5])/(c[6]*x4 + c[7]*y4 + 1) 
* 
* Multiplying both sides of each eqn by the denominator, we get 
* 
*   AC = B 
* 
* where B and C are column vectors 
* 
*   B = [ x1' y1' x2' y2' x3' y3' x4' y4' ] 
*   C = [ c[0] c[1] c[2] c[3] c[4] c[5] c[6] c[7] ] 
* 
* and A is the 8x8 matrix 
* 
*    x1 y1  1  0 0 0 -x1*x1' -y1*x1' 
*    0 0  0 x1 y1 1 -x1*y1' -y1*y1' 
*    x2 y2  1  0 0 0 -x2*x2' -y2*x2' 
*    0 0  0 x2 y2 1 -x2*y2' -y2*y2' 
*    x3 y3  1  0 0 0 -x3*x3' -y3*x3' 
*    0 0  0 x3 y3 1 -x3*y3' -y3*y3' 
*    x4 y4  1  0 0 0 -x4*x4' -y4*x4' 
*    0 0  0 x4 y4 1 -x4*y4' -y4*y4' 
* 
* These eight equations are solved here for the coefficients C. 
* 
* These eight coefficients can then be used to find the mapping 
* (x,y) --> (x',y'): 
* 
*   x' = (c[0]x + c[1]y + c[2])/(c[6]x + c[7]y + 1) 
*   y' = (c[3]x + c[4]y + c[5])/(c[6]x + c[7]y + 1) 
* 
*/ 
int genImageProjective::computeCoeefficients(void) 
{ 
    int retValue = 0; 
    int  i; 
    float *a[8]; /* 8x8 matrix A */ 
    float *b = this->vc; /* rhs vector of primed coords X'; coeffs returned in vc[] */ 

    b[0] = destArea[0].x(); 
    b[1] = destArea[0].y(); 
    b[2] = destArea[1].x(); 
    b[3] = destArea[1].y(); 
    b[4] = destArea[2].x(); 
    b[5] = destArea[2].y(); 
    b[6] = destArea[3].x(); 
    b[7] = destArea[3].y(); 

    for (i = 0; i < 8; i++) 
     a[i] = NULL; 
    for (i = 0; i < 8; i++) 
    { 
     if ((a[i] = (float *)calloc(8, sizeof(float))) == NULL) 
     { 
      retValue = -100; // ERROR_INT("a[i] not made", procName, 1); 
      goto Terminate; 
     } 
    } 

    a[0][0] = sourceArea[0].x(); 
    a[0][1] = sourceArea[0].y(); 
    a[0][2] = 1.; 
    a[0][6] = -sourceArea[0].x() * b[0]; 
    a[0][7] = -sourceArea[0].y() * b[0]; 
    a[1][3] = sourceArea[0].x(); 
    a[1][4] = sourceArea[0].y(); 
    a[1][5] = 1; 
    a[1][6] = -sourceArea[0].x() * b[1]; 
    a[1][7] = -sourceArea[0].y() * b[1]; 
    a[2][0] = sourceArea[1].x(); 
    a[2][1] = sourceArea[1].y(); 
    a[2][2] = 1.; 
    a[2][6] = -sourceArea[1].x() * b[2]; 
    a[2][7] = -sourceArea[1].y() * b[2]; 
    a[3][3] = sourceArea[1].x(); 
    a[3][4] = sourceArea[1].y(); 
    a[3][5] = 1; 
    a[3][6] = -sourceArea[1].x() * b[3]; 
    a[3][7] = -sourceArea[1].y() * b[3]; 
    a[4][0] = sourceArea[2].x(); 
    a[4][1] = sourceArea[2].y(); 
    a[4][2] = 1.; 
    a[4][6] = -sourceArea[2].x() * b[4]; 
    a[4][7] = -sourceArea[2].y() * b[4]; 
    a[5][3] = sourceArea[2].x(); 
    a[5][4] = sourceArea[2].y(); 
    a[5][5] = 1; 
    a[5][6] = -sourceArea[2].x() * b[5]; 
    a[5][7] = -sourceArea[2].y() * b[5]; 
    a[6][0] = sourceArea[3].x(); 
    a[6][1] = sourceArea[3].y(); 
    a[6][2] = 1.; 
    a[6][6] = -sourceArea[3].x() * b[6]; 
    a[6][7] = -sourceArea[3].y() * b[6]; 
    a[7][3] = sourceArea[3].x(); 
    a[7][4] = sourceArea[3].y(); 
    a[7][5] = 1; 
    a[7][6] = -sourceArea[3].x() * b[7]; 
    a[7][7] = -sourceArea[3].y() * b[7]; 

    retValue = gaussjordan(a, b, 8); 

Terminate: 
    // Clean up 
    for (i = 0; i < 8; i++) 
    { 
     if (a[i]) 
      free(a[i]); 
    } 

    this->coefficientsComputed = (retValue == 0); 
    return retValue; 
} 


/*-------------------------------------------------------------* 
*    Gauss-jordan linear equation solver   * 
*-------------------------------------------------------------*/ 
/* 
* gaussjordan() 
* 
*  Input: a (n x n matrix) 
*    b (rhs column vector) 
*    n (dimension) 
*  Return: 0 if ok, 1 on error 
* 
*  Note side effects: 
*   (1) the matrix a is transformed to its inverse 
*   (2) the vector b is transformed to the solution X to the 
*    linear equation AX = B 
* 
*  Adapted from "Numerical Recipes in C, Second Edition", 1992 
*  pp. 36-41 (gauss-jordan elimination) 
*/ 
#define SWAP(a,b) {temp = (a); (a) = (b); (b) = temp;} 
int genImageProjective::gaussjordan(float **a, float *b, int n) 
{ 
    int retValue = 0; 
    int i, icol=0, irow=0, j, k, l, ll; 
    int *indexc = NULL, *indexr = NULL, *ipiv = NULL; 
    float big, dum, pivinv, temp; 

    if (!a) 
    { 
     retValue = -1; // ERROR_INT("a not defined", procName, 1); 
     goto Terminate; 
    } 
    if (!b) 
    { 
     retValue = -2; // ERROR_INT("b not defined", procName, 1); 
     goto Terminate; 
    } 

    if ((indexc = (int *)calloc(n, sizeof(int))) == NULL) 
    { 
     retValue = -3; // ERROR_INT("indexc not made", procName, 1); 
     goto Terminate; 
    } 
    if ((indexr = (int *)calloc(n, sizeof(int))) == NULL) 
    { 
     retValue = -4; // ERROR_INT("indexr not made", procName, 1); 
     goto Terminate; 
    } 
    if ((ipiv = (int *)calloc(n, sizeof(int))) == NULL) 
    { 
     retValue = -5; // ERROR_INT("ipiv not made", procName, 1); 
     goto Terminate; 
    } 

    for (i = 0; i < n; i++) 
    { 
     big = 0.0; 
     for (j = 0; j < n; j++) 
     { 
      if (ipiv[j] != 1) 
      { 
       for (k = 0; k < n; k++) 
       { 
        if (ipiv[k] == 0) 
        { 
         if (fabs(a[j][k]) >= big) 
         { 
          big = fabs(a[j][k]); 
          irow = j; 
          icol = k; 
         } 
        } 
        else if (ipiv[k] > 1) 
        { 
         retValue = -6; // ERROR_INT("singular matrix", procName, 1); 
         goto Terminate; 
        } 
       } 
      } 
     } 
     ++(ipiv[icol]); 

     if (irow != icol) 
     { 
      for (l = 0; l < n; l++) 
       SWAP(a[irow][l], a[icol][l]); 
      SWAP(b[irow], b[icol]); 
     } 

     indexr[i] = irow; 
     indexc[i] = icol; 
     if (a[icol][icol] == 0.0) 
     { 
      retValue = -7; // ERROR_INT("singular matrix", procName, 1); 
      goto Terminate; 
     } 
     pivinv = 1.0/a[icol][icol]; 
     a[icol][icol] = 1.0; 
     for (l = 0; l < n; l++) 
      a[icol][l] *= pivinv; 
     b[icol] *= pivinv; 

     for (ll = 0; ll < n; ll++) 
     { 
      if (ll != icol) 
      { 
       dum = a[ll][icol]; 
       a[ll][icol] = 0.0; 
       for (l = 0; l < n; l++) 
        a[ll][l] -= a[icol][l] * dum; 
       b[ll] -= b[icol] * dum; 
      } 
     } 
    } 

    for (l = n - 1; l >= 0; l--) 
    { 
     if (indexr[l] != indexc[l]) 
     { 
      for (k = 0; k < n; k++) 
       SWAP(a[k][indexr[l]], a[k][indexc[l]]); 
     } 
    } 

Terminate: 
    if (indexr) 
     free(indexr); 
    if (indexc) 
     free(indexc); 
    if (ipiv) 
     free(ipiv); 
    return retValue; 
} 


// -------------------------------------------------------------- 
// Map a source point to destination using projective transform 
// -------------------------------------------------------------- 
// Params: 
// sourcePoint: initial point 
// destPoint: transformed point 
// RetValue: 0: Success, !=0: Error 
// -------------------------------------------------------------- 
// Notes: 
// 1. You must call once computeCoeefficients() to compute 
//  the this->vc[] vector of 8 coefficients, before you call 
//  mapSourceToDestPoint(). 
// 2. If there was an error or the 8 coefficients were not computed, 
//  a -1 is returned and destPoint is just set to sourcePoint value. 
// -------------------------------------------------------------- 
int genImageProjective::mapSourceToDestPoint(QPointF& sourcePoint, QPointF& destPoint) 
{ 
    if (coefficientsComputed) 
    { 
     float factor = 1.0f/(vc[6] * sourcePoint.x() + vc[7] * sourcePoint.y() + 1.); 
     destPoint.setX(factor * (vc[0] * sourcePoint.x() + vc[1] * sourcePoint.y() + vc[2])); 
     destPoint.setY(factor * (vc[3] * sourcePoint.x() + vc[4] * sourcePoint.y() + vc[5])); 
     return 0; 
    } 
    else // There was an error while computing coefficients 
    { 
     destPoint = sourcePoint; // just copy the source to destination... 
     return -1;    // ...and return an error 
    } 
} 
//======================================== 
+0

Вы, кажется, описываете проективные преобразования или гомологии. Например, библиотека OpenCV (C++, Java, Python) имеет функции для оценки этих преобразований и их применения. –

+1

@Rui: Спасибо за информацию. Я действительно думал использовать и экспериментировать с OpenCV когда-нибудь в будущем, так что это дополнительный мотив для этого. –

+0

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

0

Это геометрическое решение, которое я продумал. Я не знаю, имеет ли «алгоритм» имя.

Скажите, что вы хотите начать с деления «прямоугольника» на n частей с вертикальными линиями в первую очередь.

Цель состоит в том, чтобы поместить точки P1..Pn-1 в верхнюю строку, которые мы можем использовать, чтобы нарисовать их через линии, где левая и правая линии встречаются или параллельны им, когда такая точка не существует.

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

Else место n точек Q1..Qn на левой линии, так что те и верхний левый угол являются эквидистантными, а i < j => Qi ближе к верхнему левому корню, чем Qj. Чтобы отобразить Q-точки в верхней строке, найдите пересечение S линии из Qn через верхний правый угол и параллельную левую линию через пересечение верхней и нижней линий. Теперь соедините S с Q1..Qn-1. Пересечение новых линий с верхней линией - это требуемые P-точки.

Сделайте этот аналог для горизонтальных линий.

0

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

0

Я думаю, что выбранный ответ не является лучшим решением. Лучшим решением является применение перспективного (проективного) преобразования прямоугольника в простую сетку в виде следующего сценария Matlab и изображения. Вы можете реализовать этот алгоритм и с C++ и OpenCV.

function drawpersgrid 
sz  = [ 24, 16 ]; % [x y] 
srcpt = [ 0 0; sz(1) 0; 0 sz(2); sz(1) sz(2)]; 
destpt = [ 20 50; 100 60; 0 150; 200 200;]; 

% make rectangular grid 
[X,Y] = meshgrid(0:sz(1),0:sz(2)); 

% find projective transform matching corner points 
tform = maketform('projective',srcpt,destpt); 

% apply the projective transform to the grid 
[X1,Y1] = tformfwd(tform,X,Y); 

hold on; 

%% find grid 

for i=1:sz(2) 
    for j=1:sz(1) 
     x = [ X1(i,j);X1(i,j+1);X1(i+1,j+1);X1(i+1,j);X1(i,j)]; 
     y = [ Y1(i,j);Y1(i,j+1);Y1(i+1,j+1);Y1(i+1,j);Y1(i,j)]; 
     plot(x,y,'b'); 
    end 
end 
hold off; 

Projective grid