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

motion blur

Recommended Posts

Здравствуйте. Моя задача состоит в том, чтоб реализовать эффект motion blur по любой заданной пользователем траектории. Вопрос следующий - как задавать ядро свёртки? Пока получается криво даже для вектора 45 градусов. Возможно, посоветуете какую-то литературу, как работать с коеффициентами ядра?

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


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

Там не ядро в классическом виде нужно. Там должна быть свертка по этой кривой (по кривой движения).

FieldBlur.cpp

Design.pdf

LIC.pdf

npr.pdf

В файлах блюр по векторному полю, это не совсем то что Вам нужно, но помогает понять смысл.

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

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

накладывается на текущее изображение с некоторым коэффициентом. И так идет наслоение.

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

Надеюсь не запутал еще больше :)

Картинка для такого набора сингулярностей:

	Singularity *S1=new Singularity(3,0.00001,Point2d(100,100),0.03);
Singularity *S2=new Singularity(2,0.00001,Point2d(200,100),0.03);[/code]

post-1-0-03203600-1344259338_thumb.jpg

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


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

Не запутал, спасибо:) По этой теме уже несколько дней много читаю, так что, все слова знакомые:) беда в том, что по запросу моушн блюр выдает в большинстве либо мануал по пользованию фотошопом, либо ре-блюринг - убрать этот эффект как оптическую ошибку. А так, чтоб доступно, но ближе к научному изложению, объяснить алгоритм свёртки в этом фильтре - очень очень мало. В статьях по работе с коэффициентами ядра глаза вообще в кучку сходятся, я функан люблю, конечно, но уже успешно подзабыла. Спасибо на этом, буду сейчас освежать свой английский:)

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


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

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

И определяют, насколько сильно данный пиксел влияет на результат (точка находящаяся под "якорем" фильтра).

Для размытия при движении я бы применил, для начала, линейное убывание коэффициентов при удалении от точки (на самом деле там, конечно, экспонента)

(сумма коэффициентов фильтра должна быть равна 1).

Да, исходное изображение и результат - это разные изображения (разные области памяти).

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


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

Уточню момент, поправьте, что не так поняла.

Пользователь рисует кривую, разбиваем её на вектора, для каждого пишем ядро свёртки, а потом все эти ядра помещаем в виде миноров в одну большую матрицу свёртки? Или это не в ту степь?

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


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

не-а :)

1) кодируем кривую, нарисованную пользователем в виде x=f(s); y=g(s) (можно при помощи рядов, сплайнов) или в виде кода Фримана (важно, чтобы мы могли посетить все точки этой кривой).

2) s=0,1..L; k=1/L; k - это ядро свертки.

3) начинаем с точки (X,Y), совпадающей с концом кривой (s=L).

Для каждой точки (X,Y)

{

sum=0;

s=L;

пока s>0

{

sum+=k*I(X-f(L-s),Y-g(L-s)); // здесь могу глючить, но вроде так.

//Смысл в том, чтобы двигаться от точки X,Y, при этом X,Y должна совпадать с конечной точкой нашей кривой (f(L),g(L))

s--;

}

I_dst(X,Y)=sum;

}

Что о в этом духе.

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


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

нет, не реализовано. Есть в примерах некоторое подобие рисования (inpaint.cpp например), но оно тоже примитивное.

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

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


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

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

При этом и скорость будет учитываться, частота точек при быстром движении мышью будет меньше.

В качестве криволинейной координаты s можно взять индекс массива точек.

Вот и вся математика :)

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


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

Вопрос про мышку снят - разрешили задавать ломаную кривую точками:)

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


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

На форуме я выкладывал функцию для расчета Bezier кривых (может после приспособите).

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

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


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

Я так смотрю, что реализованная функция свертки в OpenCV мне не особо и нужна, проще напрямую через пиксели?

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


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

Я думаю что так будет более естественно.

Можно и через матрицы, но матрицей (за разумное время) можно будет реализовать только малые движения.

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

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


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

Доброе утро:) Продолжая творческие поиски: докопалась как пройтись по всем пикселям, складывая канналы ргб с соседями. Пока сдвигаю по оси Х на некоторую величину, похоже на правду. Штука вот в чем: во первых, суммируя значение ргб, оно, похоже, береться по модулю 255, тоесть, если я к белому цвету что-то добавляю - он перепрыгивает в начало значений, и выходят все цвета радуги. Та же штука с остальными цветами - сдвиг картинки происходит, но цвета убиваются. И второе - проходка по пикселях работает только с иксом, сдвинуть по вертикали не удалось

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


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

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

Среднее значение (при k=1/L) не может превышать максимального.

Тип аккумулятора возьмите float а не int или unsigned char.

И вообще, для начальных экспериментов переведите изображение в тип CV_32FC1 (серое) или CV_32FC3 (цветное).

Еще это посмотрите: cvSampleLine

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


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

С цветами справилась, просто поставила ограничение, что если сумма больше 255, то присвоить 255. выглядит красиво:) и коэффициент ввела, всё ок. Остался вопрос про вертикаль, работаю

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


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

Если используете доступ через указатели, то адрес пикселя вычисляется так i*img.step+j (это если изображение типа Mat, для IplImage* шаг будет img->widthStep) а не через ширину изображения (i*img*width+j), там еще выравнивание есть, поэтому в конце каждой строки добавляются байты.

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


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

ну да, через IplImage* . Кстати, при спадающем коэффициенте интенсивность размытия не регулируется, точнее, увеличить не выходит - при очень малых значений коэффициента след просто не видно

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


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

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

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

Поэтому обычно сильное размытие есть много ресурсов (большое ядро, много нужно суммировать).

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


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

Да и так изображение строит секунд 10, сдвигая достаточно слабо. К тому же, съедает часть цветов, всё не могу добиться идентично к фотошоповскому эффекту

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


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

В фотошопе используются расчеты на графической карте, они раз в 20-50 быстрее.

А цвета, это у Вас нахимичено :) не должен он цвета искажать.

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


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

первый - мой текущий вариант, второй - через классический фильтр

post-5833-0-28226500-1344351259_thumb.jp

post-5833-0-35444300-1344351268_thumb.jp

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


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

Ну нэзнаю что у Вас долго считается, вот набросал у себя:

Для длины L=10

post-1-0-80093000-1344352211_thumb.jpg

Для длины L=50

post-1-0-67891200-1344352519_thumb.jpg

Причем считает мгновенно :)


#include <iostream>
#include <vector>
#include <stdio.h>
#include <functional>
#include <algorithm>
#include <numeric>
#include <cstddef>
#include "opencv2/core/core.hpp"
#include "opencv2/core/gpumat.hpp"
#include "opencv2/core/opengl_interop.hpp"
#include "opencv2/gpu/gpu.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/contrib/contrib.hpp"
#include "opencv2/video/tracking.hpp"
#include "opencv2/imgproc/imgproc.hpp"
using namespace std;
using namespace cv;

Vec3f ConvolvePoint(Mat& src,Point2f p,Vec2f v)
{
Vec3f sum=0;
float k=1.0/10.0; // По 10 точкам вектора
for(int i=0;i<10;i++)
{
if(p.y+(float)i*v[1]>0 && p.y+(float)i*v[1]<src.rows && p.x+(float)i*v[0]>0 && p.x+(float)i*v[0]<src.cols)
{
sum+=k*src.at<Vec3f>(p.y+(float)i*v[1],p.x+(float)i*v[0]);
}
}
return sum;
}
// ---------------------------------
//
// ---------------------------------
void Blur(Mat& src,Mat& dst)
{
for(int i=0;i<src.rows;i++)
{
for(int j=0;j<src.cols;j++)
{
dst.at<Vec3f>(i,j)=ConvolvePoint(src,Point2f(j,i),Vec2f(1,1)); // Vec2f(1,1) - вектор под 45 градусов
}

}
}
// ---------------------------------
//
// ---------------------------------
int main( int argc, char** argv )
{
namedWindow("Image");
namedWindow("Labels");

Mat Img=imread("C:\\ImagesForTest\\skull.jpg",1);
Img.convertTo(Img,CV_32FC1,1.0/255.0);
int width=Img.cols;
int height=Img.rows;
Mat resim(Img.size(),CV_32FC3);
Blur(Img,resim);
imshow("Labels",resim);
imshow("Image",Img);
cvWaitKey(0);

}[/code]

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


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

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

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


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

Шоколадку приму к сведению :)

Vec2f(1,1) я взял для упрощения.

На самом деле, там надо бы ставить Vec2f(cos(alpha),sin(alpha)); , где aplha - угол наклона.

В общем код надо еще допиливать.

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


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

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

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

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

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

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

Войти

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

Войти сейчас


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

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

×