OpenCV в Python. Часть 1 +9




Привет, Хабр! Запускаю цикл статей по библиотеке OpenCV в Python. Кому интересно, добро пожаловать под кат!


my_logo


Введение


OpenCV — это open source библиотека компьютерного зрения, которая предназначена для анализа, классификации и обработки изображений. Широко используется в таких языках как C, C++, Python и Java.


Установка


Будем считать, что Python и библиотека OpenCV у вас уже установлены, если нет, то вот инструкция для установки python на windows и на ubuntu, установка OpenCV на windows и на ubuntu.


Немного про пиксели и цветовые пространства


Перед тем как перейти к практике, нам нужно разобраться немного с теорией. Каждое изображение состоит из набора пикселей. Пиксель — это строительный блок изображения. Если представить изображение в виде сетки, то каждый квадрат в сетке содержит один пиксель, где точке с координатой ( 0, 0 ) соответствует верхний левый угол изображения. К примеру, представим, что у нас есть изображение с разрешением 400x300 пикселей. Это означает, что наша сетка состоит из 400 строк и 300 столбцов. В совокупности в нашем изображении есть 400*300 = 120000 пикселей.


В большинстве изображений пиксели представлены двумя способами: в оттенках серого и в цветовом пространстве RGB. В изображениях в оттенках серого каждый пиксель имеет значение между 0 и 255, где 0 соответствует чёрному, а 255 соответствует белому. А значения между 0 и 255 принимают различные оттенки серого, где значения ближе к 0 более тёмные, а значения ближе к 255 более светлые:


4850884 91136851 P7DI0Ak0 greyscalesteps0255


Цветные пиксели обычно представлены в цветовом пространстве RGB(red, green, blue — красный, зелёный, синий), где одно значение для красной компоненты, одно для зелёной и одно для синей. Каждая из трёх компонент представлена целым числом в диапазоне от 0 до 255 включительно, которое указывает как «много» цвета содержится. Исходя из того, что каждая компонента представлена в диапазоне [0,255], то для того, чтобы представить насыщенность каждого цвета, нам будет достаточно 8-битного целого беззнакового числа. Затем мы объединяем значения всех трёх компонент в кортеж вида (красный, зеленый, синий). К примеру, чтобы получить белый цвет, каждая из компонент должна равняться 255: (255, 255, 255). Тогда, чтобы получить чёрный цвет, каждая из компонент должна быть равной 0: (0, 0, 0). Ниже приведены распространённые цвета, представленные в виде RGB кортежей:
Снимок экрана от 2020-08-31 01-29-26


Импорт библиотеки OpenCV


Теперь перейдём к практической части. Первое, что нам необходимо сделать — это импортировать библиотеку. Есть несколько путей импорта, самый распространённый — это использовать выражение:


import cv2

Также можно встретить следующую конструкцию для импорта данной библиотеки:


from cv2 import cv2

Загрузка, отображение и сохранение изображения


def loading_displaying_saving():
    img = cv2.imread('girl.jpg', cv2.IMREAD_GRAYSCALE)
    cv2.imshow('girl', img)
    cv2.waitKey(0)
    cv2.imwrite('graygirl.jpg', img)

Для загрузки изображения мы используем функцию cv2.imread(), где первым аргументом указывается путь к изображению, а вторым аргументом, который является необязательным, мы указываем, в каком цветовом пространстве мы хотим считать наше изображение. Чтобы считать изображение в RGB — cv2.IMREAD_COLOR, в оттенках серого — cv2.IMREAD_GRAYSCALE. По умолчанию данный аргумент принимает значение cv2.IMREAD_COLOR. Данная функция возвращает 2D (для изображения в оттенках серого) либо 3D (для цветного изображения) массив NumPy. Форма массива для цветного изображения: высота x ширина x 3, где 3 — это байты, по одному байту на каждую из компонент. В изображениях в оттенках серого всё немного проще: высота x ширина.


С помощью функции cv2.imshow() мы отображаем изображение на нашем экране. В качестве первого аргумента мы передаём функции название нашего окна, а вторым аргументом изображение, которое мы загрузили с диска, однако, если мы далее не укажем функцию cv2.waitKey(), то изображение моментально закроется. Данная функция останавливает выполнение программы до нажатия клавиши, которую нужно передать первым аргументом. Для того, чтобы любая клавиша была засчитана передаётся 0. Слева представлено изображение в оттенках серого, а справа в формате RGB:


concatenate_two_girl


И, наконец, с помощью функции cv2.imwrite() записываем изображение в файл в формате jpg(данная библиотека поддерживает все популярные форматы изображений:png, tiff,jpeg,bmp и т. д., поэтому можно было сохранить наше изображение в любом из этих форматов), где первым аргументом передаётся непосредственно само название и расширение, а следующим параметром изображение, которое мы хотим сохранить.


Доступ к пикселям и манипулирование ими


Для того, чтобы узнать высоту, ширину и количество каналов у изображения можно использовать атрибут shape:


print("Высота:"+str(img.shape[0]))
print("Ширина:" + str(img.shape[1]))
print("Количество каналов:" + str(img.shape[2]))

Важно помнить, что у изображений в оттенках серого img.shape[2] будет недоступно, так как данные изображения представлены в виде 2D массива.


Чтобы получить доступ к значению пикселя, нам просто нужно указать координаты x и y пикселя, который нас интересует. Также важно помнить, что библиотека OpenCV хранит каналы формата RGB в обратном порядке, в то время как мы думаем в терминах красного, зеленого и синего, то OpenCV хранит их в порядке синего, зеленого и красного цветов:


(b, g, r) = img[0, 0]
print("Красный: {}, Зелёный: {}, Синий: {}".format(r, g, b))

Cначала мы берём пиксель, который расположен в точке (0,0). Данный пиксель, да и любой другой пиксель, представлены в виде кортежа. Заметьте, что название переменных расположены в порядке b, g и r. В следующей строке выводим значение каждого канала на экран. Как можно увидеть, доступ к значениям пикселей довольно прост, также просто можно и манипулировать значениями пикселей:


img[0, 0] = (255, 0, 0)
(b, g, r) = img[0, 0]
 print("Красный: {}, Зелёный: {}, Синий: {}".format(r, g, b))

В первой строке мы устанавливаем значение пикселя (0, 0) равным (255, 0, 0), затем мы снова берём значение данного пикселя и выводим его на экран, в результате мне на консоль вывелось следующее:


Красный: 251, Зелёный: 43, Синий: 65
Красный: 0, Зелёный: 0, Синий: 255

На этом у нас конец первой части. Если вдруг кому-то нужен исходный код и картинка, то вот ссылка на github. Всем спасибо за внимание!




Комментарии (9):

  1. staylow
    /#22078362 / +1

    Именно то, чего я ждал. Пиши следующую часть!

  2. geksogen
    /#22081770 / +1

    Ага, поддерживаю. Жду следующую и последующую части!

  3. userDev
    /#22081774 / +1

    спасибо! Пиши еще!

  4. MiXaiLL76
    /#22081776

    Неплохо бы всё это в докере запускать. Нафига нам на нашем любимом компе плодить библиотеки?
    Или хотя бы всё это под анакондой рассказывал, а показывал как заведено в юпитере) Удобнее же. Читаемо. На гите можно код с MD сразу класть.

  5. Jeffwingchun
    /#22086312

    Написано доступно. Жду продолжения.
    Интересно, какие преимущества в использовании BGR вместо привычного RGB?

    • Atomality
      /#22090456

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

    • wadik69
      /#22090600

      Как таковых преимуществ я не вижу. Просто синий и красный каналы меняются местами:


      bgr_vs_rgb

  6. andrecpc
    /#22090458 / +1

    Спасибо!