Форум: "Начинающим";
Текущий архив: 2017.01.29;
Скачать: [xml.tar.bz2];
Вниз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;
Скачать: [xml.tar.bz2];
Память: 0.48 MB
Время: 0.001 c