Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2017.01.29;
Скачать: CL | DM;

Вниз

Blur, реализация   Найти похожие ветки 

 
Илья_666   (2015-05-29 22:04) [0]

Доброго времени суток, товарищи!
Мне необходимо сделать размытие изображения. Маленького, 100х100 максимум. Но необходимо делать это программно (т.е. в Фотошопе не сделать).
Вообщем, полистал описания алгоритмов попробовал реализовать, но ничего не получилось. На басурманском сайте нашел один любопытный код (правда, не знаю, на каком языке):
   
   function Blur (source, dest, radius) {
       for (y = 0; y < height; ++y) {
           for (x = 0; x < width; ++x) {
               total = 0
               for (ky = -radius; ky <= radius; ++ky)
                   for (kx = -radius; kx <= radius; ++kx)
                       total += source(x + kx, y + ky)
               dest(x, y) = total / (radius * 2 + 1) ^ 2  
           }
       }
   }

Автор утверждает, что данный код:
This function blurs a source image and places the result in the destination image.

Я попробовал переписать его в делфи, но либо напутал чего-то, либо код изначально не рабочий:

procedure Blur(source, dest: TBitmap; radius: integer);
var
 x, y, kx, ky: integer;
 total: integer;
begin
 source.PixelFormat := pf24Bit;
 dest.PixelFormat := pf24Bit;
 for y:=0 to source.height do begin
   for x:=0 to source.width do begin
     total := 0;
       for ky:=-radius to radius do
         for kx:=-radius to radius do
           total := source.canvas.Pixels[x + kx, y + ky];
           dest.canvas.Pixels[x, y] := Round(Sqr(total / (radius * 2 + 1)));
   end;
 end;
end;


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

Заранее спасибо за дельные советы.

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


 
MBo ©   (2015-05-29 22:23) [1]

1. C-образный псевдокод
2. Циклы по x,y неправильные. Во-первых, лишняя единица в конце, во-вторых, как и в исходном коде, не учтены краевые эффекты - что, будешь из минус пятого пиксела строки читать? Возможный вариант:
for y:= radius to source.height - radius - 1
Pixels - это цвет. Как представляешь себе сложение цветов, представленных rgb составляющими? Проще всего работать с монохромными изображениями, с яркостью.

Приведенный код выполняет свертку с квадратным окном, заменяя значение в точке на среднее по указанной окрестности


 
Dimka Maslov ©   (2015-05-30 09:09) [2]

На "непонятном" языке ^ не возведение в степень, а xor.


 
Илья_666   (2015-05-30 20:44) [3]


> Pixels - это цвет. Как представляешь себе сложение цветов,
>  представленных rgb составляющими? Проще всего работать
> с монохромными изображениями, с яркостью.

Действительно? (Интонацию не передать, но это не издевка)
На одном форуме видел такое:


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

Я ж и думал, что с цветами надо работать. Ну, не с только с цветом, сколько с его составляющими.


> Приведенный код выполняет свертку с квадратным окном, заменяя
> значение в точке на среднее по указанной окрестности

Да, этого мне вполне хватило бы.


> На "непонятном" языке ^ не возведение в степень, а xor.

Спасибо, но с xor та же история. Хотя, не в xor дело, видимо.

З.Ы.
Хотел уже было отправить ответ, но решил еще поэкспериментировать.
В общем, сотворил такое:

procedure MakeBlur(ABitmap: TBitmap);
var
 A, B, C: PRGBArray;
 x, y: integer;
begin
 ABitmap.PixelFormat := pf24bit;
 for y:=2 to ABitmap.Height - 2 do
   begin
     A := ABitmap.ScanLine[y-1];
     B := ABitmap.ScanLine[y];
     C := ABitmap.ScanLine[y+1];
     for x:=2 to ABitmap.Width - 2 do
       begin
         B[x].Red := Trunc(C[x+1].Red + A[x-1].Red + B[x].Red) div 3;
         B[x].Green := Trunc(C[x].Green + A[x].Green + B[x].Green) div 3;
         B[x].Blue := Trunc(C[x+1].Blue + A[x-1].Blue + B[x].Blue) div 3;
       end;
   end;
end;


Работает))
Только теперь есть проблема: изображение размывается по вертикали, а хотелось и по горизонтали тоже. В чем может быть проблема?


 
MBo ©   (2015-05-30 21:47) [4]

>Я ж и думал, что с цветами надо работать. Ну, не с только с цветом, сколько с его составляющими.
Тогда нужно применять фильтрацию к каждой составляющей отдельно.

> В чем может быть проблема?
В логике. Сколько точек должно участвовать в формировании значения, например, B[x].Red ?


 
Илья_666   (2015-05-31 11:18) [5]


> В логике. Сколько точек должно участвовать в формировании
> значения, например, B[x].Red ?

Думаю, что 3 точки. R,G,B или не прав?


 
brother ©   (2015-05-31 11:48) [6]

если блур кубический, то не менее 4х близлежащих... а у Вас 3и...


 
brother ©   (2015-05-31 11:50) [7]

rgb это не 3 точки, а цветовая составляющая (красный, зеленый, синий) 1й точки...


 
MBo ©   (2015-05-31 11:55) [8]

>Думаю, что 3 точки
Для radius = 1 исходный код получает среднее по квадрату из 9 точек (3x3)


 
Илья_666   (2015-05-31 13:33) [9]


> если блур кубический, то не менее 4х близлежащих... а у
> Вас 3и...

Ну да, квадрат же.


> Для radius = 1 исходный код получает среднее по квадрату
> из 9 точек (3x3)

Что это значит? Если radius = 2, то будет 6х6 и 36 точек соответственно?

Если я правильно все понял, то вот переделанный вариант:

procedure MakeBlur(ABitmap: TBitmap);
var
 A, B, C, D: PRGBArray;
 x, y: integer;
begin
 ABitmap.PixelFormat := pf24bit;
 for y:=2 to ABitmap.Height - 2 do
   begin
     A := ABitmap.ScanLine[y-1];
     B := ABitmap.ScanLine[y];
     C := ABitmap.ScanLine[y+1];
    D := ABitmap.ScanLine[y];
     for x:=1 to ABitmap.Width - 2 do
       begin
         B[x].Red   := Trunc(C[x].Red   + A[x].Red   + B[x-1].Red   + D[x+1].Red)   div 4;
         B[x].Green := Trunc(C[x].Green + A[x].Green + B[x-1].Green + D[x+1].Green) div 4;
         B[x].Blue  := Trunc(C[x].Blue  + A[x].Blue  + B[x-1].Blue  + D[x+1].Blue)  div 4;
       end;
   end;
end;


Теперь ничего не сдвигается (относительно примера в [0]), на глаз - все корректно.
Или это не самое правильное решение?


 
Inovet ©   (2015-05-31 14:09) [10]

> [9] Илья_666   (31.05.15 13:33)
> Что это значит? Если radius = 2, то будет 6х6 и 36 точек
> соответственно?

5*5=25



Страницы: 1 вся ветка

Текущий архив: 2017.01.29;
Скачать: CL | DM;

Наверх




Память: 0.5 MB
Время: 0.004 c
2-1433181587
e5431
2015-06-01 20:59
2017.01.29
ComboBox: кнопки для удаления на элементах выпадающего списка


2-1432211338
Сергей
2015-05-21 15:28
2017.01.29
SQL запрос


4-1281220286
trw
2010-08-08 02:31
2017.01.29
зная pid вывести все хэндлы этого приложения


2-1432926299
Илья_666
2015-05-29 22:04
2017.01.29
Blur, реализация


15-1457459219
Eraser
2016-03-08 20:46
2017.01.29
Тест выключения монитора