Jump to content
Compvision.ru
Sign in to follow this  
olkin

motion blur

Recommended Posts

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

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

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

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

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

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

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites

не-а :)

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;

}

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

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites

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

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

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

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

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

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

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

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

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

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

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

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

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

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

Share this post


Link to post
Share on other sites

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

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

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

Share this post


Link to post
Share on other sites

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

Для длины 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]

Share this post


Link to post
Share on other sites

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

Share this post


Link to post
Share on other sites

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

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

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

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

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×