Pull to refresh

Comments 63

Если интересно, то в java присутствует стандартный класс — ColorTransform, который позволяет обработать данное изображение указываемой матрицей.

И как-то вы с оригинальным определением завернули сложно. Применительно к обработке изображений это определение заставляет мозг сделать лоботомию изнутри, особенно сейчас, после работы :) Хорошо, что расшифровали потом :)
Вы не путаете случайно с другим типом матричного преобразования? В том же .NET есть такая вещь как ColorMatrix — матрица 4x4, которая преобразует цвета — аналог того, что в Фотошопе называется Channel Mixer кажется. Так это немного другое.
Вроде бы нет. ColorMatrix в .NET оперирует в цветовом пространстве, а не в пространстве координат изображения. Хотя насчет названия ColorTransform я уже не уверен :)
А можно где-нибудь посмотреть какие еще бывают ядра и понять почему то или иное ядро работает именно так?
Хороший вопрос.
Посоветовать ресурс, где есть все и сразу, не смогу, так как сам искал и не нашел.
Если постараться ответить кратко, то понять, почему ядро работает именно так, можно прочитав алгоритм и посмотрев на матрицу ядра. Например Box Blur — это вычисление среднего арифметического цветов пикселей, окружающих данный пиксель (берем их все с коэффициентом 1). Gaussian blur — среднее арифметическое с коэффициентами, поэтому размытие получается более мягким.
Нахождение краев и повышение резкости — по сути дифференцирование.
Хотя конечно вот так быстро и на пальцах не все объяснишь, да и нет смысла. Постараюсь в ближайшее время написать более подробно отдельный топик про это.
И тем не менее, вашего ответа вполне достаточно для понятия сути :) По крайней мере я понял.

Спасибо :)
Есть хорошая книга «Р. Гонсалес, Р. Вудс, Цифровая Обработка Изображений».

Все ядра получены чисто из эвристических соображений. И если понять как работает алгоритм «применения ядра свертки», то становится понятно почему само ядро имеет такой вид. Для простоты можно рассмотреть черно-белое изображение где каждый пиксель имеет один параметр — яркость(от 0 до 255). Взяв, например, черный квадрат на белом фоне, можно применить к нему ядро выделения вертикальных границ(как в топике). Тогда понятно, что белый фон(яркость 255) это ядро перекрасит в черный(яркость станет 0), потому что 1*255+1*255+1*255+0*255+0*255+0*255 -1*255 -1*255 -1*255 = 0. Тоже самое будет и с черным фоном -останется яркость 0. А вот на границе черного и белого(вертикальные стороны) будет 1*255+1*255+1*255+0*255+0*255+0*255 -1*0 -1*0 -1*0= 255 * 3 =253 (mod 256) то есть примерно белый. Что и требовалось. :)
О, у меня же эта книжка на работе стоит. Я про нее и забыл совсем :)
Смотрите любой курс по цифровой обработке сигналов (например, книжку Гонсалес, Вудс). Ядро свертки — это коэффициенты фильтра с конечным временем отклика (FIR-фильтр), применяемого к изображению. Коэффициенты свертки получаются путем применения обратного преобразования Фурье к передаточной функции фильтра. (Для изображений, передаточная функция фильтра — это матрица, в которой задаются коэффициенты усиления для разных частот сигналов, составляющих изображение).
При этом высокие частоты соответствуют границам объектов, а низкие частоты — фону и плавным переходам.
Сглаживание — это фильтр, который убирает высокие частоты из изображения. Выделение границ — это фильтр, который убирает низкие частоты из изображения. Повышение резкости — это фильтр, который усиливает высокие частоты, а низкие частоты оставляет без изменений.
на самом деле это частный случай. есть ещё нелинейная фильтрация используемая для обработки изображений
на самом деле это частный случай. есть ещё нелинейная фильтрация используемая для обработки изображений
Не могли бы вы более ясно продемонстрировать сходство между свёрткой по ссылке в Википедии (которая для функций — интеграл) и той, что применяется к изображениям? Скажем, такой вопрос: где в Википедийных свёртках ядро?
Ядро — одна из функций в свертках на википедии. Она необязательно должна быть дискретной как в примере с обработкой изображений.
Двухуровневый цикл — это фактически и есть интеграл, который считается для дискретных переменных x и y. В дискретном пространстве интеграл становится суммой.
А Вы специально для сверки в .NET использовали изображения ПИНГВИНОВ?
Сначала я взял изображение из стандартных картинок в винде и лишь потом понял весь глубинный смысл =)
судя по всему, у автора есть подсознательное желание переписать программу на Mono )))
Такой фильтр также есть в фотошопе Filter>Other>Custom…
Что-то он немного не так работает: попробовал примеры из статьи.
видимо дело в том по какому значению нормируются значения
У кого-нибудь есть реализация консольного варианта для увеличения резкости? Или php?
Модифицировать предоставленный пример до консольного — дело нескольких минут.
В институте свертку называли аппертурой, blur низкочастотным фильтром, а повышение резкости высокочастотной фильтрацией :)
а у нас в универе свертку светкой называли )
Я думаю, топику самое место в «Алгоритмах». Тем более там уже есть один по машинной графике и обработки изображений, опять-таки с исходником на шарпе. А вообще странно разделять алгоритмы по языку реализации ;)
Еще одно такое же мнение… и топик отправляется в Алгоритмы :)
> if (kSum <= 0) kSum = 1;

в исходнике есть, в описании — нет. У многих по описанию и примерам возникнут вопросы о делении на 0…
Статья хорошая. Но надо бы более формально раскрыть связть свертки из статьи со сверткой как понятия мат. анализа. А так же показать связь между сверкой и фурье-разложением изображения — это сразу подсказывает как выбирать хорошие ядра для задач.
Только сегодня защитил диплом связанный с обработкой изображений. Тема топика прям родная xD
Поздравляю, коллега! =)
У меня грядет защита диплома по facial recognition & identification в сентябре
Там было описано лишь как пользоваться. Без описания алгоритма.
у меня есть реализация линейных методов фильтрации (– низькочастотна фільтрація;
– полосова фільтрація;– режекторна фільтрація) реализовано на SciLab(типа Matlab). Кому интересно могу навоять статью.
Есть такая книжка «Д. Форсайт, Ж. Понс. Компьютерное зрение. Современный подход». Отличное пособие по практически всем областям, связанным с компьютерным представлением изображений. Очень рекомендую всем, кто хочет познакомиться с программной обработкой картинок и видеопотока поближе.
Я бы в свою очередь посоветовал
Гонсалес Р., Вудс Р. Цифровая обработка изображений
В последние годы математики полюбили показывать возможности вейвлетов (всплесков) на примерах, аналогичных вашим.
о ужОс, кто ж так пишет(особенно алгориты которые не должны работать долго), куча повторяющихся вычислений, создание переменных в циклах…

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

что сложного в том чтобы понять такую вещь как
a = 3 * (width * y + x);
и последующее использование

>это умышленно, иначе алгоритм стал бы нечитаем для непосвященных

приводишь довод достойный первоклассника.

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

если приводишь алгоритм, сделай его хорошо, потому что многие просто скопируют без оптимизации!

ЗЫ. и в шарпе надо это делать в unsafe. (:
да алгоритм как раз привели как положено.
А реализация/оптимизация алгоритма — это уже отдельная статья.
По-моему должно быть очевидно, что реализация алгоритма в лоб (как в данном примере) далеко не самая эффективная.
>А реализация/оптимизация алгоритма — это уже отдельная статья.

если реализация отдельная статья, зачем код?

> что реализация алгоритма в лоб (как в данном примере) далеко не самая эффективная

зачем нужна неэффективная реализация алгоритма?! (в стопяцотпервый раз — на плодят же дофига, не обязательно этот, но наплодят)
Алгоритм нормально приведён! Пример нормальный!!!
Кто просто копипастит, тот и будет пкопипастить! Он не будет вникать в оптимизацию, поэтому оно того не стоит. А чтобы объяснить само действие алгоритма самое то!
А вот те, кому правда интересно, те алгоритм поймут и уже перепишут как им надо! Так что не в пирожках мясо!
>Кто просто копипастит, тот и будет пкопипастить! Он не будет вникать в оптимизацию, поэтому оно того не
>стоит. А чтобы объяснить само действие алгоритма самое то!

дык и будут в том то и дело, не лучше ли чтоб копипастили что то хорошее?!

> Так что не в пирожках мясо!

а жаль, щас бы пирожок… (:
соглашусь с вами только в том, что данный алгоритм можно было бы привести в некоем псевокоде. Но автор выбрал конкретный язык, чтобы не было недопонимания.
Копипастить будут максимум школьники-студенты для курсовых — пусть делают это наздоровье, оценку им поставят, т.к. специалистами они видимо стать при этом не хотят.
афтор, покури на досуге более православный вариант: FFT( FFT(изображение) * FFT(раздутая маска_оператор_ядро)) = профит в скорости.

FFT — естественно быстрое преобразование фурье
Писал курсовую по этой тема на C++ с интерфейсом на Qt4…
Конечно да. Решил таки написать на питончике этот скрипт просто по описанному вами алгоритму — не получилось до конца, пришлось таки текст программы читать. Чего именно не хватало:

1. Что делать на границе? Первый же пиксель (0, 0) и я в ступоре. Оказалось что пиксели изображения недостающие надо пропускать (это еще очевидно), но неочевидным оказалось то, что сумму сетки тоже надо брать только ту, что на пиксели наложена (тоесть не учитывать некоторое на границе как и в случае с изображением).
2. Деление на ноль (а как по коду оказалось — если меньше нуля то тоже надо единицу ставить)
if (kSum <= 0) kSum = 1;

А в целом — спасибо огромное, куча позитива и все такое). Вот, собственно, программка: dpaste.com/hold/59566/ (привентил прогресс-бар на всякий случай, брать его здесь code.google.com/p/python-progressbar/)
Рад что вам понравилось =)

Насчет граничных случаев в большинстве описаний алгоритма ничего не сказано. Каждый реализует это так, как считает нужным. В инете находил достаточно много решений, таких как «заворачивание» изображений (если координата пикселя отрицательная, то берется пиксель с другого края картинки), игнорирование несуществующих пикселей с делением на полную сумму ядра и прочие методы. Однако приведенный мной метод показался мне наиболее логичным и дающим самый приличный результат на краях.
Насчет деления на ноль ситуация такая же. Я посчитал что в случае отрицательной или нулевой суммы делить на 1 — самое безобидное.
в коде эти пиксели пропускаются, тоесть центр рамки начинает с координат 1,1 и доходит до предпоследнего.

if ((pixelPosX < 0) || (pixelPosX >= width) || (pixelPosY < 0) || (pixelPosY >= height)) continue;
не, центр рамки начинает с координаты 0,0. Вы не правильно поняли), pixelPosX и pixelPosY- это не центр рамки а координата текущего пикселя изображения относительно наложенной рамки (тоесть пропускаются, к примеру, пять пикселей (левые и верхние — 0,0, 0,1, 0,2, 1,0, 2,0) рамки при наложении к пикселю 0,0, так как они указывают на отрицательные координаты).
Лет десять назад я писал дипломную программу по этой теме, ничего не зная о фильтрах.
У меня была только методичка и желание заработать :)
UFO landed and left these words here
Sign up to leave a comment.

Articles