Galaxy2D Tutorials Галактика 2D
Фильтры.

 

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

 

Так же важно, что мы будем делать "взвешенную" фильтрацию. (в противоположность "одинаковой" фильтрации). Это значит, что различные пиксели имеют разный вес при вычислении изображения. Когда я выясняю, как делать другие типы фильтров, я добавлю информацию об этом в эту статью.

 

Режимы фильтрации

 

В этой статье я буду ссылаться на два разных типа фильтрации:

 

- Цветовая

- Высотная

 

Высотная фильтрация работает только с палитровыми изображениями. Например, с 256-цветными изображениями. Каждый цвет имеет индекс 0-255, и мы можем обрабатывать этот индекс как "высоту", как будто на карте.

 

Цветная фильтрация игнорирует индекс цвета и использует значения красной / зеленной / синей составляющих компонент цвета для вычислений. Это работает на 256-цветных изображениях также хорошо, как и на полноцветных изображениях. Обратите внимание, что наиболее хорошие графические программы имеют много хороших фильтров для полноцветных изображений, но в них мало фильтров для палитровых изображений.

 

Эффективность - быстродействие

 

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

 

Как это работает

 

Процесс довольно прост:

o       Сделайте копию изображения в памяти. Мы используем это как приемник для нашего фильтра (делает работу фильтра намного лучше).

o       Задайте начальное значение переменной, в которой будет помещено вычисленное значение нужного пикселя (final). Для высотной фильтрации это будет – байт, для цветной фильтрации – это будет триплет rgb (три байта).

o       Для каждого пикселя в изображении,

o       Для пикселя и возле него,

o       Взять значение пикселя, и умножите его на соответствующее значение в сетке фильтра.

o       Добавьте этот результат к результату.

o       Теперь делите это число на "коэффициент деления". И поместите "финальный" пиксель, обратно в изображение.

 

На CИ это смотрелось бы примерно так:

 

        for(y=top; y<=bottom; y++)

          for(x=left; x<=right; x++)

          {

            ...

          }

 

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

 

А теперь, "сетка фильтра", т.е. то, что делает фильтр с исходным изображением. Вот, например сетка 5x5:

 

        0 0 0 0 0

        0 1 3 1 0

        0 3 5 3 0

        0 1 3 1 0

        0 0 0 0 0

        делитель: 21

 

Этот фильтр "смягчит" изображение. Попробуем разобраться, что делают эти числа. Вообразите, что пиксель, значение которого мы вычисляем, находится в центре сетки, там, где число 5. Пиксели, которые находятся рядом с этим пикселем, находятся под числами рядом с числом 5.

 

Это приводит нас снова, к тому, что надо сделать, чтобы применить фильтр.

 

Мы должны иметь цикл для обработки каждого из 25 пикселей в этой сетке. Для каждого пикселя в цикле, мы умножим значение этого пикселя на число в той же самой позиции в сетке. В этом примере, пиксели, которые отстоят на два пикселя дальше от обрабатываемого пикселя не используются (нулевое значение отменяет любой эффект, который могли бы внести эти пиксели). Затем мы добавляем это значение к результирующему значению для этого пикселя.

 

Обратите внимание, что значение в центре самое большое. Т.е. это самый важный пиксель в фильтре, и цвет его имеет наибольший "вес" в результате расчета.

 

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

 

Цикл теперь мог бы выглядеть теперь так:

 

        for(y=top; y<=bottom; y++) // Для каждого пикселя в изображении

          for(x=left; x<=right; x++)

          {

            gridCounter=0; // Сброс значений

            final = 0;

 

            for(y2=-2; y2<=2; y2++) // для каждого пикселя рядом

              for(x2=-2; x2<=2; x2++)

              {

                // Добавить в результат

                final += image[x+x2][y+y2] * filter[gridCounter];

                // Следующие значение в сетке

                gridCounter++;

              }

            // Делитель

            final /= divisionFactor;

 

            destination[x][y] = final;

 

          }

 

Примечания переводчика:

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

 

И когда это все сделано, надо скопировать приемник в источник, и избавляться от изображения приемника.

 

Этот цикл выполняет высотную фильтрацию на 256-цветном изображении. Довольно медленно, но его можно оптимизировать.

 

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

 

Примечание переводчика:

Для того чтобы найти самый близкий цвет в палитре необходимо сделать следующее:

 

Пусть r, g, b полученный, т.е. тот цвет, которому надо найти соответствие в исходной палитре. Тогда искомый цвет в исходной палитре будет найден по следующему алгоритму:

 

Минимальная разница = 1024

Для всех 256 цветов исходной палитры выполнять:

                        разница =       ( R - исходная палитра [ i ]. R )^2 * 0.229 +

                                                ( G - исходная палитра [ i ]. G ) ^2 * 0.587 +

                                                ( B - исходная палитра [ i ]. B ) ^2 * 0.114

                        Если разница меньше чем минимальная разница то

                                    считать этот цвет искомым

 

В данном случае разница находиться в эллипсе. А коэффициенты в данном случае учитывают предпочтение, отдаваемое человеческим глазом одним цветам по сравнению с другими.

 

ПРИМЕЧАНИЕ: Вы действительно должны использовать два изображения при работе фильтра. Если Вы не сделаете это, результат будет странный.

 

Простейшие фильтры

 

Сглаживание (среднее)

        0 0 0 0 0

        0 1 3 1 0

        0 3 9 3 0

        0 1 3 1 0

        0 0 0 0 0

         делитель: 25

 

Сглаживание (сильное)

        1 1 1 1 1

        1 1 1 1 1

        1 1 1 1 1

        1 1 1 1 1

        1 1 1 1 1

         делитель: 25

 

Сглаживание (слабое)

        0  1  2  1  0

        1  3  10 3  1

        2  10 90 10 2

        1  3  10 3  1

        0  1  2  1  0

             делитель: 154

 

Резкость (слабая) (отрицательные значения повышают контраст)

         0  0  0  0  0

         0 -1 -3 -1  0

         0 -3 41 -3  0

         0 -1 -3 -1  0

         0  0  0  0  0

              делитель: 25

 

Резкость (средняя)

        -1 -1 -1 -1 -1

        -1 -1 -1 -1 -1

        -1 -1 49 -1 -1

        -1 -1 -1 -1 -1

        -1 -1 -1 -1 –1

              делитель: 25

 

"Мягкая" Резкость

        -1 -1 -1 -1 -1

        -1  3  4  3 -1

        -1  4 13  4 -1

        -1  3  4  3 -1

        -1 -1 -1 -1 –1

              делитель: 25

 

Диагональная разбивка

        1 0 0 0 1

        0 0 0 0 0

        0 0 0 0 0

        0 0 0 0 0

        1 0 0 0 1

         делитель: 4

 

Горизонтальное размазывание

        0 0 0 0 0

        0 0 0 0 0

        1 2 3 2 1

        0 0 0 0 0

        0 0 0 0 0

         делитель: 9

 

Фильтр "огня" (создает эффект огня, который затем можно повторять)

        0 0 0 0 0

        0 0 0 0 0

        0 0 1 0 0

        0 1 1 1 0

        0 0 0 0 0

         делитель: 4

 

Другие идеи ...

 

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

 

Однако, полезен и другой тип фильтра: "контрастный" фильтр. Он повышает контраст каждого пикселя по сравнению с другими, вместо того, чтобы сравнить значения. Я действительно не знаю, как он должен работать; но, используя его можно делать вещи типа тиснения и выделения контуров.

 

Примечание переводчика:

Это можно сделать, например таким фильтром:

 

-1 –1 –1

-1  X –1

-1 –1 –1

 

Где X равно 100/S –1 + 8, где S – степень обострения от 1 до 100%.

 

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

 

Scott Scriven (http://toykeeper.net/) середина 1990 года.

Верстка и поддержка: Lennart Steinke

PMG  27 июля 2004 (c)  Сергей Анисимов