LINUX.ORG.RU

Быстрое размытие.


0

2

Хайль всем.

Создаю маску для наложения тени, возникла проблема - все мои примитивы рисуются с четкой границей (just as planned). Чтобы не было такой границы света, делаю Blur для маски. Все работает. Но хочется ускорить blur раз в 10 (сейчас размытие картинки 800х600 на уровне размытия 2 занимает примерно секунду. Хочу ускорить процесс.

Как делаю размытие - Вначале создаю массив размером LEVEL * 2 + 1, который заполняю коэффициентами, потом используя данный массив заполняю копию текстуры, суммируя цвета по маске, затем деля на сумму ячеек. Потом замещаю исходное изображение измененной копией.

Есть что-то побыстрей? Снизить время надобно минимум раза в 4. Мой метод дает примерно (на изображение 800 * 600 и уровнем 2):

  • 480 000 операций деления.
  • ~ 4 320 000 операций сложения.
  • 480 000 операций копирования ячейки.
  • 9 эпических вычислений по особоизощренной негауссовой формуле.

Ответ для тех, кто спросит, зачем я работаю с копией, а потом её копирую: если работать все время с изображением, то при расчете Y+1,X ячейки она будет использовать не Y, X, а (Y,X)`, поскольку Y,X уже была изменена и перезаписана.

P.S. Если есть какой-нибудь интересный способ типа наложения битовой маски каким-нибудь изощрённым, но быстрым способом - welcome.

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

Ну или OpenGL - совсем просто.

Deleted
()
Ответ на: комментарий от vertexua

Всего лишь на 99% целевых машин

мы о линуксе говорим?

Всего лишь везде где есть

особенно на таких открытых свободных драйверах, как nouveau, да.

Bad_ptr ★★★★★
()
Ответ на: комментарий от Bad_ptr

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

vertexua ★★★★★
()
Ответ на: комментарий от Deleted

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

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

Deleted
()
Ответ на: комментарий от AlexCones

Я и различаю, иначе бы не спрашивал.

Кстати, ещё оптимизация:

 
For YIn := Y - Level To Y + Level Do 
	For XIn := X - Level To X + Level Do 
		If InRectangle(XIn, YIn, 
			RasterEditor.Select.Left, 
			RasterEditor.Select.Top, 
			RasterEditor.Select.Right, 
			RasterEditor.Select.Bottom) Then 

замени на

 For YIn := Max(Y - Level, RasterEditor.Select.Top) To Min(Y + Level, RasterEditor.Select.Bottom) Do 
	For XIn := Max(X - Level, RasterEditor.Select.Left) To Min(X + Level, RasterEditor.Select.Right) Do 

избавляет от тучи вызовов InRectangle

unC0Rr ★★★★★
()
Ответ на: комментарий от Bad_ptr

С картой размером 40 000 х 6 000 блоков 20 х 20 пикселей? No way. Тем паче, что освещение меняется от смены времени суток и при перемещении источников света или блоков, окружающих источник.

AlexCones ★★★
() автор топика
Ответ на: комментарий от Bad_ptr

Нет, либа обьективно в 200 раз медленнее чем могла бы быть. Она могла бы юзать железо, а нет - не юзает. Фоллбек на CPU - дело разработчика либы. Если у юзера есть железо, которое ускоряет, то оно должно ускорять

vertexua ★★★★★
()
Ответ на: комментарий от Deleted

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

НАМНОГО быстрее.


Если сжать к примеру в 2 раза - требуется обработать 400 х 300 пикселей. Затем разжимаем обратно - 800 х 600. В сумме - 600 000 операций. 4 320 000 операций у меня. На 87% быстрее. Да. Было бы неплохо. Не подбросите алгоритмов быстрого сжатия\расжатия?

AlexCones ★★★
() автор топика
Ответ на: комментарий от vertexua

>в чем проблема?

А обидно не будет? Пользуетесь софтом (например любимым плеером) и вдруг БАЦ! Обновление и выскакивает окно «ваша видеокарта более не поддерживается, приобретите более мощную видеокарту». Обидно не будет?

AlexCones ★★★
() автор топика
Ответ на: комментарий от AlexCones

Нужно переключаться на software mode если нет hardware

vertexua ★★★★★
()
Ответ на: комментарий от AlexCones

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

Deleted
()
Ответ на: комментарий от AlexCones

>как это не зависит?

Distance := Round(Sqrt(Sqr(XIn - <<X>>) + Sqr(YIn - <<Y>>)));

ну так? от XIn - не зависит, от <<X>> - не зависит, зависит от разности XIn и <<X>>

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

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

cool-e-bin
()
Ответ на: комментарий от Deleted

тупо найти среднее цветов всех пикселей, которые после сжатия попадут в данный

Ну это то понятно. Меня больше интересует расжатие.

AlexCones ★★★
() автор топика
Ответ на: комментарий от cool-e-bin

отделить края области от центральной части

А края считать отдельно? Или что? Лепить еще 4 двойных цикла для краев? Или ставить еще условие внутри этого главного на принадлежность к краям? Но тогда из огня да в полымя - это условие сожрет всю выгоду от вытаскивания InRectangle

AlexCones ★★★
() автор топика
Ответ на: комментарий от AlexCones

>Лепить еще 4 двойных цикла для краев? Или ставить еще условие внутри этого главного на принадлежность к краям? Но тогда из огня да в полымя - это условие сожрет всю выгоду от вытаскивания InRectangle

попробуй и так и разэдак, посмотри какой вариант быстрее

cool-e-bin
()

Хоть в нескольких потоках осиль сделать

vertexua ★★★★★
()

Ответ для тех, кто спросит, зачем я работаю с копией, а потом её копирую: если работать все время с изображением, то при расчете Y+1,X ячейки она будет использовать не Y, X, а (Y,X)`, поскольку Y,X уже была изменена и перезаписана.

Всё правильно, для КИХ так и нужно, а вот для БИХ не обязательно. можно попробовать

for level=1 to maxLevel
	for x=left to right
		for y=top to bottom
			p(x,y)=БИХ(p(x,y),p(x,y-1))
		for y=bottom to top
			p(x,y)=БИХ(p(x,y),p(x,y+1))
	for y=top to bottom
		for x=right to left
			p(x,y)=БИХ(p(x,y),p(x+1,y))
		for x=left to right
			p(x,y)=БИХ(p(x,y),p(x-1,y))

cool-e-bin
()

Это пиздец, простите мой французкий. Размытие 0.45 Мпикселя за секунду... Слушайте дальше, не читайте книг типа Graphics Gems, 1995-го бородатого года.

nikitos ★★★
()

сейчас размытие картинки 800х600 на уровне размытия 2 занимает примерно секунду

БПФ из fftw3 даст десяток (максимум - сотню) миллисекунд для такой малюсенькой картиночки

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Deleted

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

Таки да, тоже эта мысль посещала.

pevzi ★★★★★
()
Ответ на: комментарий от power

EBUG - наследство от простеньких однофайловых (чтобы можно было написать gcc -DEBUG). Кодировка - живее всех живых. На русском - т.к. все руки не доходят (у меня уже вторую неделю валяются файлы, ждут, пока я мелкие «косяки» исправлю, что уж о крупных говорить…)

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от AlexCones

Алгоритм сжатия : Если не заморачиваться и меньшать площадь картинки в 4 раза (линейные размеры в 2) Картинка представленна в виде 2мерного массива A. линейные размеры 800 на 600 Сжатое изображение пихаем в B.

for (int i=0;i<800;i+=2){
   for (int j=0;j<600;j+=2){
 
      b[i div 2][j div 2]=((a[i][j] + a[i+1][j] + a[i][j+1] + a[i+1][j+1]) / 4); //это типа мы вычислили среднее значение для 4 пикселей
  }
}
Естессно с поправкой на типы и структуры.

Алгоритм разжатия выглядит примерно так

for (int i=0;i<400;i++){
   for (int j=0;j<300;j++){
     A[i*2][j*2]=b[i][j];
     A[i*2+1][j*2]=b[i][j];
     A[i*2][j*2+1]=b[i][j];
     A[i*2+1][j*2+1]=b[i][j];
   }
}

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

anonymous
()
Ответ на: комментарий от anonymous

Твой хитры метод рассчета дистанции выкинуть нахрен из циклов производить его рассчет в самом начале процедурки. Тобиш сформировать готовую матрицу рассчетов:

итак для level =1 мы имеем массив размером 3 на 3 (x-level to x+ level; y-level to y + level) дистации соответственно считаются аналогично

этот кусок ставится сразу после бегина функции

distance_matrix[-level ..  + level][-level..+level] 
for (int i=-level;i<=level;i++){
   for (int j=-level;j<=level;j++){
     distance_matrix[i,j]= Round(Sqrt(Sqr(i) + Sqr(j)));
   }
}

затем вотэту хитрожопую конструкцию

 Distance := Round(Sqrt(Sqr(XIn - X) + Sqr(YIn - Y)));
заменяем на
 Distance:=distance_matrix[XIn - X][YIn - Y];

Если что можно поменять местами

 Distance:=distance_matrix[X - XIn][Y - YIn];

хотя должно работать и так.

Вся эта ахинея сократит расходы на вычисления.

anonymous
()
Ответ на: комментарий от AlexCones

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

Чтобы понять надо сделать самому. Некоторые неочевидные решения становятся очевидными когда сам их найдешь. И вообще в современные век 12-гигобайтных оперативок и 4-гигабайтных видеокарт люди забывают про оптимизацию. Пилите Шура пилите, командерос с вами, виваля куба. :)

И вообще я до сихпор считаю лучшей игрой элиту, потом идет XCom и там никаких изощренных опенглов не требовалось и работает почти ЛЮБОМ!!!! железе независимо от наличия отсутствия ускорения опегл и прочих костылей для неосиливших быстрые алгоритмы программеров.

Капча знаковая tystes Naturalists

anonymous
()
Ответ на: комментарий от Eddy_Em

Эт че это кривой. Самый примитивный, стандартный с вычислением среднего значения по 4-м соседним точкам.

Ну и разворачивание аналогично из 1-й точки делаем 4.

Потери данных конечно колоссальные (про интерполяцию тут даже речи не идет).

Of даже не поленюсь (если не поленюсь) накорябаю небольшую апликуху на qt которая таким макаром жмет и разворачивает.

anonymous
()
Ответ на: комментарий от anonymous

http://imageshack.us/photo/my-images/823/graphtest.png/

Вот как выглядит результат Слева на право 1 - оригинал 2 - сжатая хреновина 3 - разжатая хреновина

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

QT

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    
    QImage im = ui->label->pixmap()->toImage();
    
    int nheight = im.height()/2;
    int nwidth = im.width()/2;
    
    QImage nw(nwidth,nheight,QImage::Format_RGB32);
    for (int i=0;i<im.width();i+=2){
        for (int j=0;j<im.height();j+=2){
            int x=i/2, y=j/2;
            QRgb p1 = im.pixel(i,j);
            QRgb p2 = im.pixel(i+1,j);
            QRgb p3 = im.pixel(i,j+1);
            QRgb p4 = im.pixel(i+1,j+1);
            int red  = (qRed(p1)+qRed(p2)+qRed(p3)+qRed(p4))/4;
            int green  = (qGreen(p1)+qGreen(p2)+qGreen(p3)+qGreen(p4))/4;
            int blue  = (qBlue(p1)+qBlue(p2)+qBlue(p3)+qBlue(p4))/4;
            nw.setPixel(x,y,qRgb(red,green,blue));
        }
    }

    QPixmap pm = QPixmap::fromImage(nw);
    ui->label_2->setPixmap(pm);
    
    QImage nw2(nwidth*2,nheight*2,QImage::Format_RGB32);
    for (int i=0;i<nwidth;i++){
        for (int j=0;j<nheight;j++){
            QRgb p = nw.pixel(i,j);
            nw2.setPixel(i*2,j*2,p);
            nw2.setPixel(i*2+1,j*2,p);
            nw2.setPixel(i*2,j*2+1,p);
            nw2.setPixel(i*2+1,j*2+1,p);
        }
    }

    QPixmap pm2 = QPixmap::fromImage(nw2);
    ui->label_3->setPixmap(pm2);
}

anonymous
()
Ответ на: комментарий от Eddy_Em

Стыдно но на рабочей тачке токо оффтопик. Ибо корпоративная политика, анальный зонд и прочие подавители личности.

А насчет сжатия, так размер уменьшился же (площадь в 4 раза меньше), следовательно скукожилось, следовательно сжатие.

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

anonymous
()
Ответ на: комментарий от anonymous

А насчет сжатия, так размер уменьшился же (площадь в 4 раза меньше), следовательно скукожилось, следовательно сжатие.

Предлагаю инновационный метод сжатия. Гарантирует сжатие в миллионы-миллиарды раз. Берем картинку, вычисляем среднюю величину интенсивности по всей картинке и получившийся пиксель сохраняем на диск!

=)

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от Eddy_Em

Таки это будет сжатие с потерей информации в <Размер картинки> - 3 байта (если я правильно понимаю структуру которая сохранит последний пиксель).

И ЧСХ такимже образом можно жать даже звуки. 1) Берем песенку, 2) замеряем среднюю частоту 3) среднюю амплитуду ... n) Profit!!!

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

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.