Фильтры играют важную роль в обработке изображений и сигналов, позволяя улучшить качество изображения, удалить шум, выделить интересующие области и многое другое. Существует несколько типов фильтров, используемых в цифровой обработке сигналов и компьютерном зрении. В этой статье мы рассмотрим точечные фильтры и изучим принципы их работы.
Для начала импортируем модули для дальнейшей работы с изображениями.
import math import random from PIL import Image, ImageChops
-
math— модуль математических функций и констант. -
random— модуль для работы с случайными числами. -
PIL.ImageиPIL.ImageChops— модули для работы с изображениями в формате PIL.
Определим класс Filters, который будет содержать несколько свойств и методов для работы с изображениями и фильтрами.
class Filters: def __init__(self, image): self.image = image self.pixels = image.load() self.width, self.height = image.size self.pixels = list(image.getdata()) self.new_pixels = [] self.newimg = Image.new("RGB", (self.width, self.height), "white")
-
В конструкторе
__init__()происходит инициализация объекта класса Filters. Он принимает изображение в качестве аргумента и сохраняет его в свойствеself.image. -
Метод
load()используется для загрузки пикселей изображения и сохранения их в свойствеself.pixelsв виде двумерного массива. -
Свойства
self.widthиself.heightхранят ширину и высоту изображения соответственно. -
Пиксели изображения сохраняются в виде списка при помощи метода
list(image.getdata())и присваиваются свойствуself.pixels. -
Создается пустой список
self.new_pixels, который будет использоваться для хранения обработанных пикселей. -
Создается новое изображение
self.newimgс помощьюImage.new(). Оно имеет такие же размеры, как и исходное изображение, и начальный цвет «white».
Теперь перейдём к реализации самих фильтров. Выберем фотографию, чтобы увидеть как работают фильтры и какой результат у нас получится.
Точечные фильтры
Точечные фильтры, также известные как фильтры одного пикселя, применяются к каждому пикселю изображения независимо от других пикселей. Они обычно используются для изменения яркости, контрастности и цветовых характеристик изображения. Рассмотрим алгоритмы обработки изображений с помощью точечных фильтров.
Первым делом создадим класс SpotFilter, который будет наследовать все свойства и методы класса Filters. И сразу же добавим в него первый фильтр.
Inversion
Inversion filterclass SpotFilters(Filters): def inversion(self): for pixel in self.pixels: self.new_pixels.append((255 - pixel[0], 255 - pixel[1], 255 - pixel[2])) self.newimg.putdata(self.new_pixels) self.newimg.save('Results/Spot_filters/Inversion.jpg', 'JPEG')
-
В цикле
forкаждый пиксель изself.pixelsобрабатывается и добавляется в списокself.new_pixels. Обработка пикселя выполняется путем вычитания значений каждого цветового канала (R, G, B) из 255, что приводит к инверсии цвета. Новые пиксели сохраняются в виде кортежей (R, G, B) вself.new_pixels. -
После завершения цикла, метод
putdata()вызывается для нового изображенияself.newimg. Он принимает списокself.new_pixelsв качестве аргумента и устанавливает пиксели нового изображения. -
Затем метод
save()вызывается для сохранения нового изображения на диск. Он принимает два аргумента: путь и имя файла для сохранения ('Results/Spot_filters/Inversion.jpg') и формат файла ('JPEG').
Grayscale
Grayscale filterdef grayscale(self): for pixel in self.pixels: self.new_pixels.append((int((pixel[0] + pixel[1] + pixel[2]) / 3), int((pixel[0] + pixel[1] + pixel[2]) / 3), int((pixel[0] + pixel[1] + pixel[2]) / 3))) self.newimg.putdata(self.new_pixels) self.newimg.save('Results/Spot_filters/Grayscale.jpg', 'JPEG')
-
В цикле
forкаждый пиксель изself.pixelsобрабатывается и добавляется в списокself.new_pixels. Обработка пикселя выполняется путем вычисления среднего значения цветовых каналов (R, G, B) и присваивания этого значения каждому цветовому каналу нового пикселя. Таким образом, все цветовые каналы нового пикселя будут иметь одно и то же значение, что создаст оттенок серого. -
После цикла
for, методputdata()вызывается для нового изображенияself.newimg. Он принимает списокself.new_pixelsв качестве аргумента и устанавливает пиксели нового изображения. -
Затем метод
save()вызывается для сохранения нового изображения на диск. Он принимает два аргумента: путь и имя файла для сохранения ('Results/Spot_filters/Grayscale.jpg') и формат файла ('JPEG').
Black and white
Black and white filterdef blackwhite(self): for pixel in self.pixels: if (pixel[0] + pixel[1] + pixel[2]) / 3 > 128: self.new_pixels.append((255, 255, 255)) else: self.new_pixels.append((0, 0, 0)) self.newimg.putdata(self.new_pixels) self.newimg.save('Results/Spot_filters/Black_white.jpg', 'JPEG')
-
В цикле
forкаждый пиксель изself.pixelsобрабатывается. -
Вычисляется среднее значение цветовых каналов (R, G, B) пикселя путем деления суммы значений на 3.
-
Если среднее значение больше 128 (половины максимального значения цветового канала), то пиксель считается более светлым и добавляется в список
self.new_pixelsс цветом(255, 255, 255)(белый цвет). -
Если среднее значение меньше или равно 128, то пиксель считается более темным и добавляется в список
self.new_pixelsс цветом(0, 0, 0)(черный цвет). -
После завершения цикла, метод
putdata()вызывается для нового изображенияself.newimg. Он принимает списокself.new_pixelsв качестве аргумента и устанавливает пиксели нового изображения. -
Затем метод
save()вызывается для сохранения нового изображения на диск. Он принимает два аргумента: путь и имя файла для сохранения ('Results/Spot_filters/Black_white.jpg') и формат файла ('JPEG').
Если кратко, то мы преобразовываем изображение в черно-белое (бинарное) изображение, где пиксели со средним значением яркости больше 128 становятся белыми, а пиксели со значением меньше или равным 128 становятся черными.
Sepia
Sepia filterdef sepia(self): for pixel in self.pixels: self.new_pixels.append((int((pixel[0] * 0.393) + (pixel[1] * 0.769) + (pixel[2] * 0.189)), int((pixel[0] * 0.349) + (pixel[1] * 0.686) + (pixel[2] * 0.168)), int((pixel[0] * 0.272) + (pixel[1] * 0.534) + (pixel[2] * 0.131)))) self.newimg.putdata(self.new_pixels) self.newimg.save('Results/Spot_filters/Sepia.jpg', 'JPEG')
-
В цикле
forкаждый пиксель изself.pixelsобрабатывается. -
Для каждого пикселя вычисляются новые значения цветовых каналов (R, G, B) с помощью заданных коэффициентов для каждого канала. Коэффициенты используются для создания эффекта сепии. Вычисленные значения округляются до целых чисел с помощью
int(). -
Вычисленные значения цветовых каналов добавляются в список
self.new_pixels. -
После завершения цикла, метод
putdata()вызывается для нового изображенияself.newimg. Он принимает списокself.new_pixelsв качестве аргумента и устанавливает пиксели нового изображения. -
Затем метод
save()вызывается для сохранения нового изображения на диск. Он принимает два аргумента: путь и имя файла для сохранения ('Results/Spot_filters/Sepia.jpg') и формат файла ('JPEG').
Значения коэффициентов, используемых для преобразования цветов изображения в сепию, выбираются на основе исторических соображений и эстетических предпочтений. Эти значения позволяют приблизительно имитировать эффект старых фотографий, создавая характерные оттенки и теплую атмосферу.
В данном коде используются следующие значения коэффициентов:
-
Для красного канала (R): 0.393, 0.349, 0.272.
-
Для зеленого канала (G): 0.769, 0.686, 0.534.
-
Для синего канала (B): 0.189, 0.168, 0.131.
Эти значения выбраны на основе экспериментов и эмпирического опыта, чтобы достичь характерных оттенков сепии. Коэффициенты определяют вклад каждого цветового канала в формирование нового значения для каждого канала. Чем больше коэффициент для определенного канала, тем больший вклад этого канала в итоговое значение цвета.
Brightness
Brightness filterdef brightness(self, value=50): for pixel in self.pixels: self.new_pixels.append((int(pixel[0] + value), int(pixel[1] + value), int(pixel[2] + value))) self.newimg.putdata(self.new_pixels) self.newimg.save('Results/Spot_filters/Brightness.jpg', 'JPEG')
-
Метод
brightness()принимает необязательный аргументvalue, который по умолчанию равен 50. Значениеvalueуказывает на величину изменения яркости изображения. -
В цикле
forкаждый пиксель изself.pixelsобрабатывается. -
Для каждого цветового канала (R, G, B) каждого пикселя производится сдвиг на значение
value. Это осуществляется путем прибавления значенияvalueк текущему значению цветового канала. -
Вычисленные значения цветовых каналов добавляются в список
self.new_pixels. -
После завершения цикла, метод
putdata()вызывается для нового изображенияself.newimg. Он принимает списокself.new_pixelsв качестве аргумента и устанавливает пиксели нового изображения. -
Затем метод
save()вызывается для сохранения нового изображения на диск. Он принимает два аргумента: путь и имя файла для сохранения ('Results/Spot_filters/Brightness.jpg') и формат файла ('JPEG').
Тут мы изменяем яркость изображения путем сдвига значений цветовых каналов каждого пикселя на указанное значение value. Положительное значение value увеличит яркость изображения, а отрицательное значение уменьшит яркость.
Сontrast
Сontrast filterdef contrast(self, value=2): for pixel in self.pixels: self.new_pixels.append((int(pixel[0] * value), int(pixel[1] * value), int(pixel[2] * value))) self.newimg.putdata(self.new_pixels) self.newimg.save('Results/Spot_filters/Contrast.jpg', 'JPEG')
-
Метод
contrast()принимает необязательный аргументvalue, который по умолчанию равен 2. Значениеvalueуказывает на множитель изменения контрастности изображения. -
В цикле
forкаждый пиксель изself.pixelsобрабатывается. -
Для каждого цветового канала (R, G, B) каждого пикселя производится умножение на значение
value. Это осуществляется путем умножения текущего значения цветового канала наvalue. -
Вычисленные значения цветовых каналов добавляются в список
self.new_pixels. -
После завершения цикла, метод
putdata()вызывается для нового изображенияself.newimg. Он принимает списокself.new_pixelsв качестве аргумента и устанавливает пиксели нового изображения. -
Затем метод
save()вызывается для сохранения нового изображения на диск. Он принимает два аргумента: путь и имя файла для сохранения ('Results/Spot_filters/Contrast.jpg') и формат файла ('JPEG').
Изменения контрастности изображения достигаются путем масштабирования значений цветовых каналов каждого пикселя на указанное значение value. Значение value определяет множитель контрастности, где значение больше 1 увеличивает контрастность, а значение меньше 1 уменьшает контрастность.
Gamma
Gamma filter def gamma(self, value=2): for pixel in self.pixels: self.new_pixels.append((int(pixel[0] ** value), int(pixel[1] ** value), int(pixel[2] ** value))) self.newimg.putdata(self.new_pixels) self.newimg.save('Results/Spot_filters/Gamma.jpg', 'JPEG')
-
Метод
gamma()принимает необязательный аргументvalue, который по умолчанию равен 2. Значениеvalueуказывает на значение гаммы для коррекции изображения. -
В цикле
forкаждый пиксель изself.pixelsобрабатывается. -
Для каждого цветового канала (R, G, B) каждого пикселя производится возведение в степень
value. Это осуществляется путем возведения текущего значения цветового канала в степеньvalue. -
Вычисленные значения цветовых каналов добавляются в список
self.new_pixels. -
После завершения цикла, метод
putdata()вызывается для нового изображенияself.newimg. Он принимает списокself.new_pixelsв качестве аргумента и устанавливает пиксели нового изображения. -
Затем метод
save()вызывается для сохранения нового изображения на диск. Он принимает два аргумента: путь и имя файла для сохранения ('Results/Spot_filters/Gamma.jpg') и формат файла ('JPEG').
Этот код реализует фильтр гамма-коррекции изображения, который изменяет яркость и контрастность изображения путем возведения значений цветовых каналов каждого пикселя в указанную степень value. Значение value определяет, насколько сильно будет изменяться яркость и контрастность изображения.
Blackout
Blackout filter-
Метод
blackout()принимает необязательный аргументvalue, который по умолчанию равен 5. Значениеvalueуказывает на величину затемнения изображения. -
В цикле
forкаждый пиксель изself.pixelsобрабатывается. -
Для каждого цветового канала (R, G, B) каждого пикселя производится деление на значение
value. Это осуществляется путем деления текущего значения цветового канала наvalue. -
Вычисленные значения цветовых каналов добавляются в список
self.new_pixels. -
После завершения цикла, метод
putdata()вызывается для нового изображенияself.newimg. Он принимает списокself.new_pixelsв качестве аргумента и устанавливает пиксели нового изображения. -
Затем метод
save()вызывается для сохранения нового изображения на диск. Он принимает два аргумента: путь и имя файла для сохранения ('Results/Spot_filters/Blackout.jpg') и формат файла ('JPEG').
Реализовываем фильтр затемнения изображения путем уменьшения яркости каждого пикселя на указанную величину value. Чем больше значение value, тем сильнее будет затемнение изображения.
Red
Red filterdef green(self): for pixel in self.pixels: self.new_pixels.append((0, pixel[1], 0)) self.newimg.putdata(self.new_pixels) self.newimg.save('Results/Spot_filters/Green.jpg', 'JPEG')
-
В цикле
forкаждый пиксель изself.pixelsобрабатывается. -
Для каждого пикселя создается новый пиксель с составляющей красного цвета
pixel[0], а остальные составляющие устанавливаются в ноль (R=pixel[0], G=0, B=0). Таким образом, все пиксели получают красный оттенок, где значение красного цвета остается неизменным, а остальные цветовые каналы устанавливаются в ноль. -
Сформированный новый пиксель добавляется в список
self.new_pixels. -
После завершения цикла, метод
putdata()вызывается для нового изображенияself.newimg. Он принимает списокself.new_pixelsв качестве аргумента и устанавливает пиксели нового изображения. -
Затем метод
save()вызывается для сохранения нового изображения на диск. Он принимает два аргумента: путь и имя файла для сохранения ('Results/Spot_filters/Red.jpg') и формат файла ('JPEG').
В фильтре красного оттенка изображения все пиксели получают красный цвет, а остальные цветовые каналы устанавливаются в ноль. В зелёном и синем фильтрах используется тот же способ, только меняются значения (R=0, G=pixel[1], B=0) и (R=0, G=0, B=pixel[2]).
Green
Green filterdef green(self): for pixel in self.pixels: self.new_pixels.append((0, pixel[1], 0)) self.newimg.putdata(self.new_pixels) self.newimg.save('Results/Spot_filters/Green.jpg', 'JPEG')
Blue
Blue filterdef blue(self): for pixel in self.pixels: self.new_pixels.append((0, 0, pixel[2])) self.newimg.putdata(self.new_pixels) self.newimg.save('Results/Spot_filters/Blue.jpg', 'JPEG')
Надеюсь, что данная статья была полезна. В следующий раз разберем матричные фильтры, основанные на матрицах коэффициентов, называемых ядрами, и математическую морфологию, которая основана на теории множеств и применяется для анализа и обработки двумерных изображений 🙂
ссылка на оригинал статьи https://habr.com/ru/articles/735316/
Добавить комментарий