Привет, Хабр! Это продолжение туториала по библиотеке opencv в python. Для тех кто не читал первую и вторую части, сюда: Часть 1 и Часть 2, а всем остальным — приятного чтения!  В данной части мы рассмотрим арифметику изображений, разделение и слияние каналов, различные методы размытия. Надеюсь, что все знают такие арифметические операции как сложение и вычитание, но при работе с изображениями мы не должны забывать о типе данных.
К примеру, у нас есть RGB изображение, пиксели которого попадают в диапазон [0,255]. Итак, что же произойдёт, если мы попытаемся к пикселю с интенсивностью 250 прибавить 30 или от 70 отнять 100? Если бы мы пользовались стандартными арифметическими правилами, то получили бы 280 и -30 соответственно. Однако, если мы работаем с RGB изображениями, где значения пикселей представлены в виде 8-битного целого беззнакового числа, то 280 и -30 не является допустимыми значениями. Для того, чтобы разобраться, что же произойдёт, давайте посмотрим на строчки кода ниже: Как мы видим, сложение и вычитание можно осуществить с помощью функций opencv add и subtract соответственно, а также с помощью numpy. И результаты будут отличаться: OpenCV выполняет обрезку и гарантирует, что значения пикселей никогда не выйдут за пределы диапазона [0,255]. В numpy же всё происходит немного иначе. Представьте себе обычные настенные часы, где вместо 60 находится 255. Получается, что после достижение 255 следующим числом будет идти 0, а когда мы отнимаем от меньшего числа большее, то после 0 ( против часовой стрелки) будет идти 255.  Как мы знаем, RGB изображение состоит из красной, зелёной и синих компонент. И что, если мы захотим разделить изображение на соответствующие компоненты? Для этого в opencv есть специальная функция — split(): Сначала мы загружаем изображение. Для наглядности работы данной функции я взял следующее изображение:  Затем разделяем изображение на три канала и показываем каждый канал по отдельности. В результате выполнения данной функции отобразится три изображения в оттенках серого:  Как мы видим, для каждого изображения каждого канала только прямоугольник с тем же цветом отображается белым. Вот как будет выглядеть каждая компонента для девушки из предыдущих частей:  Как можно увидеть, красный канал очень светлый. Это происходит потому, что оттенки красного очень сильно представлены в нашем изображении. Синий и зелёный каналы, наоборот, очень тёмные. Это случается потому, что на данном изображении очень мало данных цветов.
Для того, чтобы объединить каналы воедино, достаточно воспользоваться функцией merge(), которая принимает значения каналов:   Таким образом, мы получаем такое же изображение как оригинальное, за исключением того, что я поменял местами синий с зелёным каналом. Размытие — это когда более резкие области на изображении теряют свою детализацию, в результате чего изображение становится менее чётким. В opencv имеются следующие основные методы размытия: averaging(усреднённое), gaussian(гауссово) и median(медианное).  Данный фильтр делает операцию свёртки на изображении с неким ядром, где свёртка — это вычисление нового значения пикселя, при котором учитываются значения соседних пикселей. Ядро свёртки — это квадратная матрица, где пиксель в центре этой матрицы затем устанавливается как среднее значение всех других пикселей, окружающих его. Для того, чтобы воспользоваться данным размытием достаточно вызвать метод blur(), который принимает изображение и кортеж, с указанием размера ядра: Чем больше размер ядра, тем более размытым будет становиться изображение:  Гауссово размытие похоже на предыдущее размытие, за исключением того, что вместо простого среднего мы теперь используем взвешенное среднее, где соседние пиксели, которые ближе к центральному пикселю, вносят больший «вклад» в среднее. Конечным результатом является то, что наше изображение размыто более естественно:   Это размытие реализуется в opencv с помощью функции GaussianBlur(), которая принимает первые два аргумента такие же как и предыдущая функция, а третьим аргументом указываем стандартное отклонение ядра Гаусса. Установив это значение в 0, мы тем самым говорим opencv автоматически вычислять его, в зависимости от размера нашего ядра: В медианном размытии центральный пиксель изображения заменяется медианой всех пикселей в области ядра, в результате чего это размытие наиболее эффективно при удалении шума в стиле «соли». Для того, чтобы применить данный вид размытия, необходимо вызвать функцию medianBlur() и передать туда два параметра: изображение и размер ядра: В результате у нас получится следующее:  На этом данная часть подошла к концу. Код, как всегда, доступен на github. До скорой встречи:)