Перейти к содержимому
Compvision.ru
mrgloom

старый IPL

Recommended Posts

http://www.comp.nus.edu.sg/~cs4243/doc/ipl.pdf

док на старый IPL

меня интересует функция


void iplRotate(IplImage* srcImage, IplImage* dstImage,double angle, double xShift, double yShift,int interpolate);
непонятно зачем нужен сдвиг после поворота?
The function iplRotate() rotates the source image srcImage by angle degrees around the origin (0,0) and shifts it by xShift and yShift along the x -and y -axis, respectively.
выполняет поворот вокруг (0,0) и зачем то потом сдвигает. вообще формула поворота вокруг произвольной точки такая
p'x = cos(theta) * (px-ox) - sin(theta) * (py-oy) + ox

p'y = sin(theta) * (px-ox) + cos(theta) * (py-oy) + oy

т.е. мы сдвигаемся в (0,0) поворачиваем и возвращаемся.

вот рецепт на поворот вокруг произвольной точки.

If you need to rotate the image around an arbitrary center (xCenter,yCenter) rather than the origin (0,0), you can compute xShift and yShift using the function iplGetRotateShift and then call iplRotate(). Alternatively, you can use the iplRotateCenter macro definition.

т.е. вроде как понятно что это будет работать, непонятно по какой формуле и как считается сам Shift в первой формуле.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

просто непонятно что за сдвиг, если делать сдвиг-поворот-сдвиг, то сдвиг собственно говоря и будет delta(x,y)= center(x,y) - (0,0) (т.е. мы берем точку вокруг которой поворачиваем и переносим систему координат в (0,0))

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

void iplRemap(IplImage* srcImage, IplImage* xMap,IplImage *yMap, IplImage* dstImage,int interpolate );

можно было бы просто посчитать непокрытые пиксели, но проблема в том, что xMap,yMap float и вроде как они там интерполируются, так что там не точное попадание в пиксель.

т.е. тут скорее вопрос как быть с краями и промежутками.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Может проще WarpAffine использовать?

http://www.compvision.ru/forum/index.php?showtopic=744

Есть еще вариант: взять черное изображение и на него нарисовать маску поворачиваемой области к которой применено то же преобразование что и к фрагменту изображения. Я так в проекте где менялись местами лица делал.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Может проще WarpAffine использовать?

а чем проще то? тем более что тащить еще файлы завязанные на новый opencv тут мне бы не хотелось, т.е. у меня есть 2 варианта либо через старый IPL либо руками.

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

так вот если можно будет залить фон каким либо цветом, а поверх варпнуть изображение, то это будет и так норм и даже сделать через тот же iplRotate, а не iplRemap.

либо надо писать самому пересчёт координат и интерполяцию.

Есть еще вариант: взять черное изображение и на него нарисовать маску поворачиваемой области к которой применено то же преобразование что и к фрагменту изображения.

не понял в чем тут суть.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

еще походу в IPL нету cvSet, а есть только iplSet который по всем каналам ставит одно и то же видимо.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

похоже что в старом IPL можно изменить пиксели изображения только через iplUserProcessPixel которая использует указатель на функцию IplUserFuncPixel

typedef void (__STDCALL *IplUserFuncPixel)(IplImage*

srcImage, void* srcPixel, IplImage* dstImage, void*

dstPixel);

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

вообщем вопрос решился просто изменением RGB по указателю в dst до поворота.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

всё таки так фоном заливать не получиться, мне надо знать где находяться эти фоновые пиксели, т.е. иметь пиксельную маску.

Как производиться интерполяция в общем виде?

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

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

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

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Может проще WarpAffine использовать?

или имелось ввиду представить всё изображение в виде регулярной сетки треугольников и потом варпнуть и интерполировать внутри каждого треугольника. + так и края получить легче.

попробовал почитать код remap из imgwarp.cpp но какой там метод используется я так и не понял.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

по идее должно быть что то такое

rgb-gouraud-triangle.gif

только у нас есть не только цвет на вершинах, но и в вообще с самом треугольнике.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
попробовал почитать код remap из imgwarp.cpp но какой там метод используется я так и не понял.

У меня http://www.compvision.ru/forum/index.php?showtopic=744 (пост №9) используются барицентрические координаты для вычисления карты соответствия.

Вот файлы maple с выводом формул: WarpAffine.zip

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

посмотрел код, по порядку:

DrawLabelsMask(Mat& imgLabel,vector<Point2d>& points,vector<vector<size_t>>& triangles)
- закрашивает наш список трианглов, которые хранятся они как список точек + индексы к ним.нужно потом для того чтобы иметь как раз попиксельную маску. Видимо в отсутсвии fillConvexPoly нужно то то типа растеризации треугольника делать
CalcCoeffs(vector<Point2d>& s_0,vector<Point2d>& s_1, vector<vector<size_t>>& triangles, Mat& Coeffs)

как я понял это все входные трианглы и выходные(s_0 и s_1) т.е. все точки сетки.

но что там за формула используется я не понял, видимо это как то связано с барицентрическими координатами?

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

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

у меня же как раз вопрос в том как сделать интерполяцию внутри варпнутого треугольника.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Используемый метод и начальные формулы из раздела "4.1.1 Piecewise Affine Warping" документа matthews_ijcv_2004.pdf

ЗЫ: дыр ведь нету, значит интерполяция есть :)

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

опять же по идее некоторые пиксели попадают в несколько треугольников сразу(те которые на границе)

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

есть такое понятие как Barycentric Interpolation но похоже это не в ту степь всё таки

http://classes.soe.ucsc.edu/cmps160/Fall10/resources/barycentricInterpolation.pdf

тут фигурируют другие названия polygon mesh deformations: picewise linear and piecewise bilinear

http://mesh.brown.edu/engn1610/assignment3.html

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

например поворот

rotate_no_interpolation.png

получились пустые точки внутри + неровный край

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

потом точки внутри можно заделать усреднением и т.д.

пиксели на границе наверно надо как то сглаживать методом что то типа растеризации линий.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Да, так и есть.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

не понял про формулу преобразования через матрицы

p'x = cos(theta) * (px-ox) - sin(theta) * (py-oy) + ox

p'y = sin(theta) * (px-ox) + cos(theta) * (py-oy) + oy

S= sin(theta)

C= cos(theta)

Rc-поворот вокруг произвольной точки

Ro-поворот вокруг точки (0,0)

Rc=T*Ro*T

по сути мы вычитаем из коодинаты точки смещение (С-О), поворачиваем вокруг (0,0) и потом прибавляем ранее вычтенное смещение.

через матрицы

post-701-0-18697900-1387799002_thumb.gif

непонятно то, что судя по матрицам получается, что сначала прибавляем координату, а потом вычитаем.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

как можно ускорить интреполяцию?

попробовал переписать в несколько тредов, но ускорения не получил, думаю что это связано с тем, что доступ к пикселям получается непоследовательным.(всмысле из src семплируется довольно рэндомными четвёрками).

примерный код

//проходимся по dst(заранее вычисленного размера n_h,n_w)

		for(int y=0;y<n_h;++y)

		{

			for(int x=0;x<n_w;++x)

			{

				//делаем обратное преобразование

				fPoint pt(Transform(Point(x+shift_x, y+shift_y))); //сдвиг чтобы помещалось в рект (0,0,n_w,n_h)


                                //это в координатах src

				int x1= (int)floor(pt.x); //округление вниз

				int y1= (int)floor(pt.y);

				int x2= x1+1; //округление вверх

				int y2= y1+1;


                                //смотрим не выходит ли за пределы src

				if((x1>=0&&x1<w&&y1>=0&&y1<h)&&(x2>=0&&x2<w&&y2>=0&&y2<h))

				{

					Mask[y][x]= 1; //показываем пиксель


					float dx1= pt.x-x1;

					float dx2= 1-dx1;

					float dy1= pt.y-y1;

					float dy2= 1-dy1;


					//bilinear

					pd[x].blue= (dy2*(ps[y1*w+x1].blue*dx2+ps[y1*w+x2].blue*dx1)+

						dy1*(ps[y2*w+x1].blue*dx2+ps[y2*w+x2].blue*dx1));

					pd[x].green= (dy2*(ps[y1*w+x1].green*dx2+ps[y1*w+x2].green*dx1)+

						dy1*(ps[y2*w+x1].green*dx2+ps[y2*w+x2].green*dx1));

					pd[x].red= (dy2*(ps[y1*w+x1].red*dx2+ps[y1*w+x2].red*dx1)+

						dy1*(ps[y2*w+x1].red*dx2+ps[y2*w+x2].red*dx1));


					//nearest neighbour

					//pd[y*n_w+x]= ps[((int)pt.y)*w+(int)pt.x]; //округление через приведение

				}

				else

					Mask[y][x]= 0; //прозрачный

			}

			pd+= n_w;

		}

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Можно SSE попробовать заюзать:

http://fastcpp.blogspot.ru/2011/06/bilinear-pixel-interpolation-using-sse.html

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте учётную запись или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×