OpenCV в Python. Часть 2

  • Tutorial

Привет, Хабр! Продолжаем туториал по библиотеке opencv в python. Для тех кто не читал первую часть, сюда: Часть 1, а всем остальным — увлекательного чтения!


part_2_logo


Введение


Теперь, когда вы ознакомились с основами данной библиотеки, пора приступить к базовым преобразованиям изображений: изменение размера, смещение вдоль осей, кадрирование(обрезка), поворот.


Изменение размера изображения


Первый метод, который мы изучим — это как поменять высоту и ширину у изображения. Для этого в opencv есть такая функция как resize():


def resizing():
    res_img = cv2.resize(img, (500, 900), cv2.INTER_NEAREST)

Данная функция первым аргументом принимает изображение, размер которого мы хотим изменить, вторым — кортеж, который должен содержать в себе ширину и высоту для нового изображения, третьим — метод интерполяции(необязательный). Интерполяция — это алгоритм, который находит неизвестные промежуточные значения по имеющемуся набору известных значений. Фактически, это то, как будут заполняться новые пиксели при модификации размера изображения. К примеру, интерполяция методом ближайшего соседа (cv2.INTER_NEAREST) просто берёт для каждого пикселя итогового изображения один пиксель исходного, который наиболее близкий к его положению — это самый простой и быстрый способ. Кроме этого метода в opencv существуют следующие: cv2.INTER_AREA, cv2.INTER_LINEAR( используется по умолчанию), cv2.INTER_CUBIC и cv2.INTER_LANCZOS4. Наиболее предпочтительным методом интерполяции для сжатия изображения является cv2.INTER_AREA, для увелечения — cv2.INTER_LINEAR. От данного метода зависит качество конечного изображения, но как показывает практика, если мы уменьшаем/увеличиваем изображение меньше, чем в 1.5 раза, то не важно каким методом интерполяции мы воспользовались — качество будет схожим. Данное утверждение можно проверить на практике. Напишем следующий код:


res_img_nearest = cv2.resize(img, (int(w / 1.4), int(h / 1.4)), 
                                 cv2.INTER_NEAREST)
res_img_linear = cv2.resize(img, (int(w / 1.4), int(h / 1.4)), 
                                cv2.INTER_LINEAR)

Слева — изображение с интерполяцией методом ближайшего соседа, справа — изображение с билинейной интерполяцией:


conc_girl


Очень важно при изменении размера изображения учитывать соотношение сторон. Соотношение сторон — это пропорциональное соотношение ширины и высоты изображения.Если мы забудем о данном понятии, то получим изображение такого плана:


res_girl


Поэтому текущую функцию для изменения размера необходимо модифицировать:


def resizing(new_width=None, new_height=None, interp=cv2.INTER_LINEAR):
    h, w = img.shape[:2]

    if new_width is None and new_height is None:
        return img

    if new_width is None:
        ratio = new_height / h
        dimension = (int(w * ratio), new_height)

    else:
        ratio = new_width / w
        dimension = (new_width, int(h * ratio))

    res_img = cv2.resize(img, dimension, interpolation=interp)

Соотношение сторон мы вычисляем в переменной ratio. В зависимости от того, какой параметр не равен None, мы берём установленную нами новую высоту/ширину и делим на старую высоту/ширину. Далее, в переменной dimension мы определяем новые размеры изображения и передаём в функцию cv2.resize().


Смещение изображения вдоль осей


С помощью функции cv2.warpAffine() мы можем перемещать изображение влево и вправо, вниз и вверх, а также любую комбинацию из перечисленного:


def shifting():
    h, w = img.shape[:2]
    translation_matrix = np.float32([[1, 0, 200], [0, 1, 300]])
    dst = cv2.warpAffine(img, translation_matrix, (w, h))
    cv2.imshow('Изображение, сдвинутое вправо и вниз', dst)
    cv2.waitKey(0)

Сначала, в переменной translation_matrix мы создаём матрицу преобразований как показано ниже:


1


Первая строка матрицы — [1, 0, tx ], где tx — количество пикселей, на которые мы будем сдвигать изображение влево или вправо. Отрицательное значения tx будет сдвигать изображение влево, положительное — вправо.
Вторая строка матрицы — [ 0, 1, ty], где ty — количество пикселей, на которые мы будем сдвигать изображение вверх или вниз. Отрицательное значения ty будет сдвигать изображение вверх, положительное — вниз. Важно помнить, что данная матрица определяется как массив с плавающей точкой.
На следующей строчке и происходит сдвиг изображения вдоль осей, с помощью, как я писал выше, функции cv2.warpAffine(), которая первым аргументом принимает изображение, вторым — матрицу, третьим — размеры нашего изображения. Если вы запустите данный код, то увидите следующее:


girl_right_and_down


Вырез фрагмента изображения


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


def cropping():
    crop_img = img[10:450, 300:750]

В данной строчке мы предоставляем массив numpy для извлечения прямоугольной области изображения, начиная с (300, 10) и заканчивая (750, 450), где 10 — это начальная координата по y, 300 — начальная координата по x, 450 — конечная координата по y и 750 — конечная координата по x.Выполнив код выше, мы увидим, что обрезали лицо девочке:


crop_face


Поворот изображения


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


def rotation():
    (h, w) = img.shape[:2]
    center = (int(w / 2), int(h / 2))
    rotation_matrix = cv2.getRotationMatrix2D(center, -45, 0.6)
    rotated = cv2.warpAffine(img, rotation_matrix, (w, h))

Когда мы поворачиваем изображение, нам нужно указать, вокруг какой точки мы будем вращаться, именно это принимает первым аргументом функция cv2.getRotationMatrix2D(). В данном случае я указал центр изображения, однако opencv позволяет указать любую произвольную точку, вокруг которой вы захотите вращаться. Следующим аргументом данная функция принимает угол, на который мы хотим повернуть наше изображение, а последним аргументом — коэффициент масштабирования. Мы используем 0.6, то есть уменьшаем изображение на 40%, для того, чтобы оно поместилось в кадр. Данная функция возвращает массив numpy, который мы передаём вторым аргументом в функцию cv2.warpAffine(). В итоге, у вас на экране должно отобразиться следующее изображение:


rotated_girl


Вот и вторая часть подошла к концу, исходный код доступен на github. Спасибо за уделённое внимание! До скорой встречи!

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

More

Comments 5

    0
    Изучаю сейчас эту библиотеку, тренируясь стреляя по мишеням в 3d-шутере.

    Открыл для себя великолепие hsv, для поиска зон с определённым диапазоном цветов и освещенности.
      0
      Что за 3d-шутер?))
        0
        Will to Live. Пробую разные реализации.

        Сейчас скрипт довольно неплохо работает на cv.matchTemplate. Если отойти чуть подальше от мишеней — работать перестанет, думаю можно ресайзить тимплейт и сравнивать несколько раз.
        Так же можно использовать массив из нескольких тимплейтов. Начал использовать mss для граба экрана с целью увеличения производительности.
        Потом попробовал по цветам на основе hsv — занятно, сколько схожих цветов на картинке, которые глаз вообще не различает.
        Немного разобрался, как с контурами работать в массиве и сравнивать их размер. Но пока не представляю как можно с помощью математки и геометрии эти контуры можно сопоставить с шаблонами. Возможно попробую сопоставить по площади, а затем найти в этих контурах определённые цвета (сами мишени белые, а в них круги с красными точками в центре).

        Большая мечта — тензорфлоу и обучение модели. Но это для моего уровня очень сложно.
          0
          Да в этом тензорфлоу нет большой магии. Есть много обучающих роликов + много готовых моделек на github)
            0
            Да, я нашёл неплохие гайды по использованию готовых моделек на том же хабре, а вот как свою создать меньше инфы толковой. На ютубе да, вроде есть обучалки именно по созданию. Возможно на этапе реализации станет понятно, когда сам попробую пописать.

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