Russian Qt Forum

Программирование => Алгоритмы => Тема начата: Igors от Ноябрь 27, 2009, 20:19



Название: Подогнать прямоугольник под картинку
Отправлено: Igors от Ноябрь 27, 2009, 20:19
Добрый вечер

Задачка совсем простая но почему-то не могу сообразить как сделать :)
Есть прямоугольник в 3D пространстве, он задается 4-мя точками (x, y, z) для каждой. Корректная геометрия гарантируется - все 4 точки лежат в одной плоскости и площадь прямоугольника не равна нулю. Каждая точка имеет также координаты пикселей  (u, v) картинки(имедж) которая должна быть нарисована на прямоугольнике.

Задача: имедж может иметь неиспользуемые (100% черные) края. Для имеджа это выглядит так

 --------------------------
|                                    |
|           --------              |
|          |           |            |
|          |           |            |
|           --------              |
|                                    |
|                                    |
---------------------------  

Вопрос: как теперь подсчитать 3D координаты каждой точки прямоугольника чтобы он вместил только "содержательную часть" имеджа?

Спасибо


Название: Re: Подогнать прямоугольник под картинку
Отправлено: Павел_F. от Ноябрь 27, 2009, 20:37
Читал раз 20... Ничего не понял.
Картинка это 2D... прямоугольник в 3D... Что с кем совместить надо? Нужно чтобы проекция 3D прямоугольника на плоскость с 2D картинкой совпадала со значащей частью 2D картинки?


Название: Re: Подогнать прямоугольник под картинку
Отправлено: Igors от Ноябрь 27, 2009, 20:43
Читал раз 20... Ничего не понял.
Картинка это 2D... прямоугольник в 3D... Что с кем совместить надо? Нужно чтобы проекция 3D прямоугольника на плоскость с 2D картинкой совпадала со значащей частью 2D картинки?
Представьте себе какую-нибудь пластиковую карточку. На ней что-то нарисовано но есть белые (неиспользуемые) края. Берем ножницы и обрезаем ненужные края. Какой теперь стала карточка?


Название: Re: Подогнать прямоугольник под картинку
Отправлено: Павел_F. от Ноябрь 27, 2009, 20:47
Представьте себе какую-нибудь пластиковую карточку. На ней что-то нарисовано но есть белые (неиспользуемые) края. Берем ножницы и обрезаем ненужные края. Какой теперь стала карточка?
1) Меньше чем была
2) В той же плоскости что и была раньше
3) Осталась прямоугольником( не может картинка овальной быть)
Причем тут 3D все равно не понятно.


Название: Re: Подогнать прямоугольник под картинку
Отправлено: Igors от Ноябрь 27, 2009, 20:57
1) Меньше чем была
2) В той же плоскости что и была раньше
3) Осталась прямоугольником( не может картинка овальной быть)
Причем тут 3D все равно не понятно.
Только при том, что карточка в 3D пространстве и каждый ее угол имеет (x, y, z). Как посчитать эти координаты после обрезки?


Название: Re: Подогнать прямоугольник под картинку
Отправлено: Павел_F. от Ноябрь 27, 2009, 21:31
  • Пишем уравнение плоскости "пластиковой карточки" в пространстве. Зная координаты углов "пластиковой карточки".
  • Преобразуем ( сдвиг и поворот, в исключительных ситуациях одно из них. В совсем исключительных ни одного) систему координат так чтобы эта плоскость стала одной из координатных. С уравнением плоскости посчитать угол и расстояние между плоскостями, нашей и одной из координатных, не проблема.
  • Задача стала 2D, считаем что хотели. Тоже вроде все ясно, с 2D все проще.
  • Обратное преобразование координат. Зная прямое преобразование, обратное не проблема.


Название: Re: Подогнать прямоугольник под картинку
Отправлено: Igors от Ноябрь 27, 2009, 21:39
  • Пишем уравнение плоскости "пластиковой карточки" в пространстве ( не проблема, так как три точки есть)
  • Преобразуем ( сдвиг и поворот, в исключительных ситуациях одно из них. В совсем исключительных ни одного) систему координат так чтобы эта плоскость стала одной из координатных ( с уравнением плоскости тоже не проблема)
  • Задача стала 2D, считаем что хотели ( границы значащих плоскостей) ( тоже вроде все ясно)
  • Обратное преобразование координат( зная прямое преобразование обратное не проблема)

Хорошо, предположим мы привели прямоугольник в плоскость XY. Но все равно координаты вершин (теперь x, y, 0) и координаты пикселей имеджа (для каждого угла) - разные вещи. Как посчитать что хотели?


Название: Re: Подогнать прямоугольник под картинку
Отправлено: Павел_F. от Ноябрь 27, 2009, 22:00
Но все равно координаты верщин (ткперь x. y, 0) и координаты пикселей имеджа (для каждого угла) - разные вещи. Как посчитать что хотели?
абстрагируясь от остального и рассматривая уже двумерную задачу:
  • Берем уравнение прямой, одной из границ прямоугольника, зная две точки не проблема( например левой)
  • Бежим по этой прямой( например сверху вниз, координаты верха и низа известны и не сложно)
  • Если встретили на прямой хоть одну значащую( не черную) точку то это и есть новая граница( левая :) если следовать примеру)
  • если не встретили двигаем прямую на единицу и снова бежим( если следовать примеру то двигаем в право)
Подобным образом проходим по всем четырем границам и получаем новый прямоугольник где внутри только значащее( не черное) содержимое.


Название: Re: Подогнать прямоугольник под картинку
Отправлено: Igors от Ноябрь 27, 2009, 22:05
Но все равно координаты верщин (ткперь x. y, 0) и координаты пикселей имеджа (для каждого угла) - разные вещи. Как посчитать что хотели?
абстрагируясь от остального и рассматривая уже двумерную задачу:
  • Берем уравнение прямой, одной из границ прямоугольника, зная две точки не проблема( например левой)
  • Бежим по этой прямой( например сверху вниз, координаты верха и низа известны и не сложно)
  • Если встретили на прямой хоть одну значащую( не черную) точку то это и есть новая граница( левая :) если следовать примеру)
  • если не встретили двигаем прямую на единицу и снова бежим( если следовать примеру то двигаем в право)
Подобным образом проходим по всем четырем границам и получаем новый прямоугольник где внутри только значащее( не черное) содержимое.
Ну как обрезать незначащие края имеджа - не вопрос. Сделано, допустим был имедж (0, 0)(100, 100). После обрезки стал, например (20, 10)(90, 90). Так ведь это все в пикселях имеджа. А прямоугольник-то как посчитать?


Название: Re: Подогнать прямоугольник под картинку
Отправлено: Павел_F. от Ноябрь 27, 2009, 22:26
Так подожди... Так надо миллиметры в пиксели пересчитать?


Название: Re: Подогнать прямоугольник под картинку
Отправлено: Igors от Ноябрь 27, 2009, 22:44
Так подожди... Так надо миллиметры в пиксели пересчитать?
Ну типа того :) Одну систему координат в другую. Конечно, есть соответствие для каждого угла


Название: Re: Подогнать прямоугольник под картинку
Отправлено: spectre71 от Ноябрь 27, 2009, 22:51
Добрый вечер

Задачка совсем простая но почему-то не могу сообразить как сделать :)
Есть прямоугольник в 3D пространстве, он задается 4-мя точками (x, y, z) для каждой. Корректная геометрия гарантируется - все 4 точки лежат в одной плоскости и площадь прямоугольника не равна нулю. Каждая точка имеет также координаты пикселей  (u, v) картинки(имедж) которая должна быть нарисована на прямоугольнике.

Задача: имедж может иметь неиспользуемые (100% черные) края. Для имеджа это выглядит так

 --------------------------
|                                    |
|           --------              |
|          |           |            |
|          |           |            |
|           --------              |
|                                    |
|                                    |
---------------------------  

Вопрос: как теперь подсчитать 3D координаты каждой точки прямоугольника чтобы он вместил только "содержательную часть" имеджа?

Спасибо

Вопросы:

1) Координаты целочиcлены(поскольку пикселы) ?
2) Правильно ли я понимаю задачу? - Переформулирую:
- Имеем прямоугольник A  с определенными валидными координатами в 3D
- Имеем проекцию A из 3D в 2D, т.е имеем координаты проекции A  в 2D
- Имеем прямоугольник B сторого внутри A (включая границы A)
- Имеем координаты B в плоскости прямоугольника A

Задача определить координаты прямоугольника B в 2D прекции прямоугольника A




Название: Re: Подогнать прямоугольник под картинку
Отправлено: Igors от Ноябрь 27, 2009, 23:30
Вопросы:

1) Координаты целочиcлены(поскольку пикселы) ?
2) Правильно ли я понимаю задачу? - Переформулирую:
- Имеем прямоугольник A  с определенными валидными координатами в 3D
- Имеем проекцию A из 3D в 2D, т.е имеем координаты проекции A  в 2D
- Имеем прямоугольник B сторого внутри A (включая границы A)
- Имеем координаты B в плоскости прямоугольника A

Задача определить координаты прямоугольника B в 2D прекции прямоугольника A
1) Нет, координаты числа с точкой

2) На все вопросы ответ "да" - просто давайте уточним термин "проекция". Под этим обычно понимается "проекция на одну из плоскостей координат" (в изометрии). Например

- front view (вид спереди). Отбрасываем z, видим только x, y
- тор view (вид сверху) Отбрасываем y, видим только x, z
- side view (вид сбоку) Отбрасываем x, видим только y, z

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


Название: Re: Подогнать прямоугольник под картинку
Отправлено: SimpleSunny от Ноябрь 28, 2009, 08:54
Если я правильно (хотя есть сомнения) понял, то:
1. Считаем количество мм в одном пикселе
k = sqrt(sqr(x2 - x1) + sqr(y2 - y1) + sqr(z2 - z1)) / sqrt (sqr(u2 - u1) + sqr(v2 - v1))
2. Считаем единичный вектор направления стороны m
{(x2 - x1) / |m|, (y2 - y1) / |m|, (z2 - z1) / |m|}
3. Узнаем координаты обрезанного изображения. К примеру одна из сторон (0, 0) (100, 0) -> (20, 0)(90, 0).
4. for (i = 20; i <= 90; ++i)
{
    in_mm = i * k;
    in_mm_x = mx * in_mm + x1;
    in_mm_y = my * in_mm + y1;
    in_mm_z = mz * in_mm + z1;
}
или (к 4му пункту)
можно узнать начальное смещение (из-за обрезания края картинки) и просто на каждом шаге прибавлять шаг (k).


Название: Re: Подогнать прямоугольник под картинку
Отправлено: spectre71 от Ноябрь 28, 2009, 19:00
Может проще получить матрицу преобразования(поворота) для точек (u,v) плоскости в точки (x,y,z) пространства:

Если ничего не путаю:
Код:
                           |a11 a12 a13|
Матрица преобразования A = |a21 a22 a23|
                           
         |a11 a12 a13|
|u v|  * |a21 a22 a23| = |x y z| = |u*a11+v*a21, u*a12+v*a22, u*a13+v*a2|

теперь имея две известные пары точек:
(u1,v1) -> (x1,y1,z1)
(u2,v2) -> (x2,y2,z2)

Получаем 3 системы уравнений:

u1*a11+v1*a21 = x1         
u2*a11+v2*a21 = x2         

u1*a12+v1*a22 = y1         
u2*a12+v2*a22 = y2         

u1*a13+v1*a23 = x1         
u2*a13+v2*a23 = x2         

===================
Решаем первую:

u1*a11+v1*a21 = x1         
u2*a11+v2*a21 = x2         

a11 = (x1-v1*a21)/u1 = (x2-v2*a21)/u2
a21 = (x1-u1*a11)/v1 = (x2-u2*a11)/v2

u2*x1-u2*v1*a21 = u1*x2-u1*v2*a21
u1*v2*a21-u2*v1*a21 = u1*x2-u2*x1
                               
Получаем:
a21 = (u1*x2-u2*x1)/(u1*v2-u2*v1)
a11 = (v1*x2-v2*x1)/(v1*u2-v2*u1)
Аналогично с двумя оставшимися системами

===================
Но это видимо без переноса и сдвига.
===================

Если 2D прямогольник в начале координат(3D естественно тоже), то упрощаем:
2D прямогольник задается {(u1,v1);(u2,v2)} -> {(0,h);(w,0)} - где: h-высота, w-ширина
a21 = (u1*x2-u2*x1)/(u1*v2-u2*v1)
a11 = (v1*x2-v2*x1)/(v1*u2-v2*u1)

a21 = (0*x2-w*x1)/(0*0-w*h)
a11 = (h*x2-0*x1)/(h*w-0*0)

a21 = x1/h
a11 = x2/w
         
    |x2/w y2/w z2/w|
A = |x1/h y1/h z1/h|         
         
===================

x = u*x2/w + v*x1/h;
y = u*y2/w + v*y1/h;
z = u*z2/w + v*z1/h;

   

Что-то слишком просто получилось. Наверное фигня.
Вот ссылочка на всякий случай
http://www.graphicon.ru/oldgr/grafor/gr_help/chapter_8_1_1.htm (http://www.graphicon.ru/oldgr/grafor/gr_help/chapter_8_1_1.htm)



Название: Re: Подогнать прямоугольник под картинку
Отправлено: Igors от Ноябрь 28, 2009, 21:51
Здравствуйте

Сегодня утром проснулся и за полчаса все сделал. Наверное вчера был неудачный день  :) Все просто.

1) Общая часть

Нужно определить 2 системы координат: одну для пикселей, другую для 3D точек.  Вычислить относительные координаты в пиксельной системе и использовать их в 3D. Например, был имедж (0, 0)(100, 100) а после обрезки стал (20, 20)(75, 80) - значит относительные координаты новых точек (0.2, 0.2)(0.75, 0.8 )

2) Данные

Нужно определить операторы и писать в векторах иначе (если каждый раз повторять вычисления для 2 или 3 координат) никакой головы не хватит

Код:
struct Vec3D {
  Vec3D & xyz( float _x, float _y, float _z ) { x = _x; y = _y; z = _z; return *this; }
  
  float length( void ) const { return sqrt(x * x + y * y + z * z); }   // длина вектора
  
// умножение и деление
  friend Vec3D operator * (  const Vec3D & v, float t ) {  Vec3D a; return a.xyz(v.x * t, v.y * t; v.z * t); }
  friend Vec3D operator / (  const Vec3D & v, float t ) {  Vec3D a; return a.xyz(v.x / t, v.y / t; v.z / t); }

// cложение и вычитание
  friend  Vec3D operator + ( const Vec3D &  a, const Vec3D & b ) { Vec3D t; return t.xyz(a.x + b.x, a.y + b.y,  a.z + b.z; }
  friend  Vec3D operator - ( const Vec3D &  a, const Vec3D & b ) { Vec3D t; return t.xyz(a.x - b.x, a.y - b.y,  a.z - b.z; }

// скалярное произведение - возвращает косинус угла между векторами помноженный на их длины
  friend  float operator *  ( const Vec3D &  a, const Vec3D & b ) { return a.x * b.x + a.y * b.y + a.z * b.z; }

// data
  float x, y, z;
};
Все то же самое для Vec2D, только без z  

3) Пусть точка задана так

Код:
struct CPoint {
  Vec3D mPosOld;    // исходная позиция в 3D
  Vec3D mPosNew;   // позиция в 3D после обрезки
  Vec2D mPixOld;     // пиксель имеджа до обрезки
  Vec2D mPixNew;     // пиксель имеджа после обрезки
};

Тогда
Код:
// mPixNew посчитано из имеджа для всех 4 точек теперь надо найти их mPosNew  
void CalcQuad( CPoint quad[4] )
{
// строим пиксельную систему координат  
   Vec2D pixCenter = quad[0].mPixOld;               // центр в точке 0
   Vec2D pixX = quad[1].mPixOld - pixCenter;      // первая ось 0->1 ("X")
   Vec2D pixY = quad[3].mPixOld - pixCenter;      // вторая ось 0->3 ("Y")
   float lenX = pixX.length();                            // длина первой оси
   float lenY = pixY.length();                            // длина второй оси

// строим 3D систему координат  
   Vec3D vecCenter = quad[0].mVecOld;             // центр в точке 0
   Vec3D vecX = quad[1].mVecOld - vecCenter;    // первая ось 0->1 ("X")
   Vec3D vecY = quad[3].mVecOld - vecCenter;    // вторая ось 0->3 ("Y")

   for (int i = 0; i < 4; ++i) {
     // находим относительные пиксельные координаты
     float relX = quad[i].mPixNew * pixX / (lenX * lenX);
     float relY = quad[i].mPixNew * pixY / (lenY * lenY);

     // переводим в 3D координаты
     quad[i].mPosNew = vecCenter + vecX * relX + vecY * relY;
   }
}