Размытие изображения фильтром Kuwahara

    Фильтр Kuwahara выполняет нелинейную фильтрацию изображений с сохранением резких краев. После фильтрации изображение похоже на грубо нарисованную красками, картину.
    image

    Алгоритм


    1. В окрестности каждого пикселя применить маску размером (2r+1)*(2r+1)
    2. Окрестность разделить на 4 области, указанные цифрами I, II, III, IV, размером r*r
    3. Вычислить среднюю интенсивность и дисперсию в каждой из областей I, II, III, IV
    4. Присвоить центральному пикселю X среднее значение интенсивности той области, дисперсия которой наименьшая

    Маска фильтра


    Применение


    Сегментация однородных по цвету областей

    Допустим у нас стоит задача поиска водоемов на космоснимке. На этапе предварительной обработке необходимо очистить изображение от шумов и сделать его более гладким и однородным. Причем должна быть сохранена информация о границах объектов в изображении. Применяем к исходному изображению фильтр kuwahara.
    Исходное изображение
    image
    Kuwahara 21x21

    После фильтрации границы стали более четкими, и к изображению можно применить какой-нибудь контурный фильтр, например детектор Канни.
    Детектор Канни, примененный после фильтрации kuwahara
    image
    Для сравнения, если бы мы в качестве предварительной обработке использовали бы фильтр Гаусса, получили бы следующие изображения:
    Фильтр Гаусса 21x21
    image

    image

    Применение фильтра для создания эффекта нарисованной картины

    Хоть это и не самый лучший фильтр для создания эффекта акварели или гуаши, но во многих случаях, на мой взгляд, получается очень даже красивый эффект.
    Исходное изображение
    image
    Kuwahara 21x21
    image

    Ссылки


    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 37

      +20
      Оригинальный кот намного лучше
        0
        Как я понимаю это размытие создано для создания такого эффекта некой краски. А вообще можно в редакторе сделать как бы нарисованный фон с человеком без размытия.
        +2
        Очень жаль что вся статья по сути состоит из 6 картинок. Т.е. сама тема интересна, но статья уж больно маленькая :-(
          0
          Как-то мало информации, чем он лучше фильтра того же Гаусса? где целесообразно применять данный фильтр?
            +3
            фильтр Гаусса Размывает изображение не сохраняя информации о краев. Применять можно в сегментации. Например, стоит задача обнаружение водоемов на космоснимках. Если применять фильтр Гаусса, границы будет определить сложнее
            Исходное изображение:
            image
            Размытие Гауссом
            image
            Размытие Кувахара
            image
              +1
              Хм… да действительно, нужно попробовать сделать данное размытие перед детектором Канни.
                0
                Детектор Канни, примененный к изображениям выше соответственно




                  +2
                  Гхм. А если правильно параметры детектора границ настроить — он их везде выделит хоть какие-то. Некорректно сравнить детектор с одинаковыми параметрами.
                    0
                    Не корректно само понятие «детектор Канни». В своих работах Kanny обозначил сам подход, и сделал это на столько остроумно, что программисты наплодили из него большое число «алгоритмов» :-) в то время как для большинства частных случаев выделения края, можно обойтись вообще ОДНОЙ свёрткой, без какой-либо предварительной фильтрации.
            +40
            Странно что нет этой картинки :)
              –1
              а цэ откель?
              0
              спасибо, ты сделал мой день )))))
                0
                Черт, не выходит! Надо кривые подкрутить.

                0
                Для понимания алгоритма не хватает картинки после шага 1, когда маска наложена, но последний фильтр не применён
                  0
                  чёрт, кажется туплю. на первом шаге не фильтр, а просто разметка картинки
                  +1
                  Вот с сегментации и надо было начинать, а то эти эффекты красок уже надоели…
                    0
                    Алгоритм дан для серых изображений. Как он расширяется на цветные? (для каждого RGB канала?)
                      0
                      Да, алгоритм применяется к каждому каналу
                        +1
                        Только, наверное, интенсивность для дисперсии нужно общую брать (max(r, g, b)). Иначе, представим, что в по красной компоненте наибольшая дисперсия в левом верхнем квадранте, по зелёной — в правом верхнем, по синей — где нибудь ещё. В итоге будут взяты средние значения компонент из разных квадрантов и получатся абсолютно новые цвета.

                        Или вообще считать не по RGB, а HSL (не уверен про расчёт среднего hue).
                          0
                          В оригинале Кувахара применяется к каждому каналу отдельно. Хотя ваша модификация фильтра тоже интересна. Интересно будет сравнить имеющиеся результаты с вашей модификацией.
                            +2
                            К сожалению, в статье все изображения уменьшены и повреждены jpeg-ом. Вот что получилось у меня (21x21):

                            Выбор по отдельным интенсивностям: при сильном увеличении видны мусорные пиксели из компонент разных квадрантов.


                            Выбор квадранта по значению (максимальной интенсивности): всё чисто.
                              0
                              По небольшой части изображения сложно судить результат, выложите изображение полностью.
                                +2
                                Оригинал:
                                habrastorage.org/storage2/530/b03/638/530b036382e0a669cb1fbeb719f24220.jpg

                                Отдельные каналы, цветущие края:
                                habrastorage.org/storage2/d59/1c2/55b/d591c255bb7f9a5c6cfdb81789165aa4.png

                                Максимальный канал:
                                habrastorage.org/storage2/0c9/b65/62d/0c9b6562df0c87f15d0bb3f5f21de405.png

                                void KuwaharaOperation::getMeanAndVariance(int x0, int y0, int x1, int y1, float output[3], float variance[3])
                                {
                                	float color[3], mean[3];
                                	float var[3] = {0.0f};
                                	int count = (y1 - y0 + 1) * (x1 - x0 + 1);
                                	
                                	for (int y = y0; y <= y1; y++) {
                                		for (int x = x0; x <= x1; x++) {
                                			this->m_inputOperation->read(color, x, y, NULL);
                                			add_v3_v3(mean, color);
                                		}
                                	}
                                	 
                                	mul_v3_fl(mean, 1.0f / count);
                                	
                                	for (int y = y0; y <= y1; y++) {
                                		for (int x = x0; x <= x1; x++) {
                                			this->m_inputOperation->read(color, x, y, NULL);
                                			sub_v3_v3(color, mean);
                                			mul_v3_v3(color, color);
                                			add_v3_v3(var, color);
                                		}
                                	}
                                	
                                    // Код для отдельных каналов
                                //	if (variance[0] > var[0]) {
                                //		output[0] = mean[0];
                                //		variance[0] = var[0];
                                //	}
                                //	if (variance[1] > var[1]) {
                                //		output[1] = mean[1];
                                //		variance[1] = var[1];
                                //	}
                                //	if (variance[2] > var[2]) {
                                //		output[2] = mean[2];
                                //		variance[2] = var[2];
                                //	}
                                	
                                	// Код для общей интенсивности
                                	if (MAX3(variance[0], variance[1], variance[2]) > MAX3(var[0], var[1], var[2])) {
                                		copy_v3_v3(output, mean);
                                		copy_v3_v3(variance, var);
                                	}
                                }
                                
                                void KuwaharaOperation::executePixel(float output[4], int x, int y, void *data)
                                {
                                	float color_org[4];
                                	float variance[4] = {FLT_MAX, FLT_MAX, FLT_MAX, FLT_MAX};
                                	int size = this->m_size;
                                	int x1 = x - size, x2 = x, x3 = x + size;
                                	int y1 = y - size, y2 = y, y3 = y + size;
                                	
                                	CLAMP(x1, 0, getWidth() - 1);
                                	CLAMP(x2, 0, getWidth() - 1);
                                	CLAMP(x3, 0, getWidth() - 1);
                                	CLAMP(y1, 0, getHeight() - 1);
                                	CLAMP(y2, 0, getHeight() - 1);
                                	CLAMP(y3, 0, getHeight() - 1);
                                
                                	this->m_inputOperation->read(color_org, x, y, NULL);
                                	
                                	this->getMeanAndVariance(x1, y1, x2, y2, output, variance);
                                	this->getMeanAndVariance(x1, y2, x2, y3, output, variance);
                                	this->getMeanAndVariance(x2, y1, x3, y2, output, variance);
                                	this->getMeanAndVariance(x2, y2, x3, y3, output, variance);
                                	output[3] = color_org[3];
                                }
                                  0
                                  А с первого взгляда потеря цвета не заметна. Замечание очень даже хорошее, спасибо.
                      0
                      результат отличия от surface blur минимален.

                      и surface blur для поиска водоёмов, больше подошел бы. хотя при любом варианте использование в таких целях — полный бред.
                      +1
                      Да, интересный эффект.
                      Дополнительно в GIPM есть плагин G'MIC с этим эффектом и в плагине gluas есть исходник этого эффекта.
                      pippin.gimp.org/plug-ins/gluas/index.html
                        –1
                        вторая картинка кота плющит
                          +1
                          Умиляют меня такие посты, с обилием картинок, сравнением чего-то с чем-то, без каких-либо попыток осмысления происходящего, вообще… Но за-то с умными словами и фамилиями людей в работы которых не разу не заглядывали.
                            0
                            Неплохо бы привести сравнение с медианным фильтром, т.к. результаты схожие. Более того, мне обработка медианным фильтром нравится больше, т.к. не вносит больших искажений в форму объектов.
                            Обратите внимание на то, как овальные объекты (сверху и ближе к центру левее) разделились на несколько фрагментов:

                            Это уже недопустимо для последующей обработки краев.
                              0
                              эти фильтры схожи тем, что они сохраняют информацию о краях и хорошо удаляют импульсный шум, но в отличие от фильтра кувахары, в медианном фильтре области изображения не становится однородными, поэтому результаты не совсем схожи.
                              исходное изображение
                              image
                              кувахара 21х21
                              image
                              медианный фильтр 9х9
                              image

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

                              >Обратите внимание на то, как овальные объекты (сверху и ближе к центру левее) разделились на несколько фрагментов
                              >Это уже недопустимо для последующей обработки краев.
                              Замечание хорошее. Из-за большого радиуса размытия небольшие объекты делятся на несколько (такова особенность фильтра). Но это не критично т.к. чаще всего маленькие объекты принимаются за шум.
                              В случае, если необходимо сохранить небольшие объекты, то необходимо уменьшить радиус размытия
                              кувахара 9х9
                              image
                              0
                              Сказать по правде это плохо походит на работу написанную красками. Как минимум именно потому, что края остаются слишком резкими для картины написанной красками, да ещё и как следует из описания — «грубо». Было бы грубо, края были бы ещё сильнее оборваны.
                              Точно так же и цветовые переходы внутри объекта — слишком резко меняются для такой техники.
                                0
                                Здесь есть некие сходства с картинами в стиле экспрессионизма
                                image
                                  0
                                  Совсем небольшое. если сравнивать с конкретной картиной то тут мазки по другому ложатся, да и края в той или иной степени очерчены.

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

                                Only users with full accounts can post comments. Log in, please.