Задачи компьютерного
зрения можно условно разделить на простые и сложные.
Сложные задачи отвечают на вопросы: что за объект на картинке, к какому классу
она относится и чаще всего используют те или иные методы машинного обучения.
Простые методы манипулируют непосредственно с пикселями,
используют эвристики, и чаще всего не используют машинное обучение.
Разделение условное, но тем не менее, мы сегодня в этом видео поговорим
про задачи простого компьютерного зрения или «низкоуровневого» зрения.
Важно отметить, что вот такие задачи
простые и низкоуровневые, они очень часто используются
как составной кирпичик более сложных задач распознавания.
Например, можно картинку предобработать,
чтобы потом машинное обучение проще распознавать, что на ней изображено.
Давайте сначала обсудим, какие библиотеки можно использовать
для работы с низкоуровневым компьютерным зрением.
На самом деле есть одна самая популярная и
известная библиотека opencv, в ней содержится огромное количество алгоритмов.
Есть интерфейс как на c++, так и на python.
Другой пример такой библиотеки — это skimage,
который активно используется в скриптах на python.
Мы в примерах будем использовать opencv.
Ну на самом деле таких библиотек существует несколько,
и у них есть свои плюсы и минусы.
Чтобы понять, как манипулировать с изображением, прежде всего нужно понять,
как картинки представляются в памяти компьютера.
И если человек видит некие цельные
картины и объекты, то в памяти компьютера
это числа — картинка состоит из пикселей.
Если речь про картинку без цвета,
то каждый пиксель описывается некой яркостью.
Для однобайтовых изображений эта яркость лежит в диапазоне от 0 до 255.
Если в картинке есть еще и цвет, то каждый пиксель описывается тремя числами.
Например, самая простая и понятная
интуитивно тройка чисел — это яркости в красном,
зеленом и синем канале.
Они тоже лежат в определенном диапазоне для однобайтовых изображений,
это от 0 до 255.
Существуют и другие представления цвета, о них мы поговорим чуть позже.
Соответственно, картинки — это некие матрицы чисел.
В случае с серыми картинками — это
матрица размера ширина картинки на высоту картинки.
В случае цветных картинок появляется еще одна
размерность и чаще всего она равна трем каналам.
Если вы работали с библиотекой numpy,
то вы знаете, как можно с этими матрицами работать.
Соответственно, в библиотеке opencv для представления
картинок используются представления матриц numpy.
Это означает, что мы можем использовать встроенные арифметические операции,
например, сложения.
Но не все так просто.
Если мы воспользуемся сложением из numpy,
то это сложение не учитывает переполнение.
А для картинок переполнение — это нелогичная операция.
То есть если мы две картинки складываем, и яркость получается больше,
чем 255, то чаще всего мы хотим,
чтобы она и осталась 255, а не превратилась, например, в 4.
Вот на данном слайде пример, как отличается сложение в numpy и в opencv.
Как это выглядит на реальной картинке?
Если мы возьмем вот это изображение, превратим его в серое изображение.
Для этого мы воспользуемся такой командой из opencv,
мы ее будем неоднократно видеть,
она используется для преобразования цветовых пространств,
в том числе и для преобразования из RGB в серые картинки.
Соответственно, мы картинку перевели в серое,
после этого мы прибавляем к ней какое-то число.
Такое преобразование эквивалентно увеличению яркости картинки.
Мы можем не прибавлять, а умножать на некий коэффициент,
например...
умножение на коэффициент, на самом деле оно увеличивает контраст картинки.
Если умножить еще на большее число,
то вот получаем такой эффект.
Сейчас мы рассмотрели примеры, как меняется картинка...
вот прибавление или умножение на некое число.
На самом деле ровно так работают алгоритмы изменения яркости и
контраста во многих популярных графических редакторах и в мобильных приложениях.
Но мы можем использовать более сложные функции для изменения яркости и контраста.
Приведу пример такого подхода, который называет эквилизацией гистограммы.
Что такое гистограмма?
Гистограмма — это представление картинки,
которая отвечает на вопрос сколько пикселей той или иной яркости.
На данной картинке мы видим график,
гистограмму некоего изображения.
Черным цветом обозначена кумулятивная гистограмма,
которая отвечает на вопрос: сколько пикселей
яркости меньше, чем значение x.
Соотвественно, эквилизация гистограммы делает
следующее: она растягивает гистограмму картинки таким образом,
чтобы кумулятивная гистограмма была близка к линейной функции.
Выглядит это следующим образом: вот эквилизация гистограммы,
примененная к нашему изображению.
Видно, что контраст улучшился, темные области стали темнее, яркие светлее.
Чтобы произвести эквилизацию гистограммы,
нужно применить некое преобразование к яркости пикселей,
и это достаточно просто сделать, это хорошая задачка на алгоритмы.
Можете попробовать написать такое преобразование.
Приведу еще один пример простых арифметических операций с картинками.
Представьте, что у нас стоит задача скомбинировать два изображения.
Можно их на самом деле просто сложить, но может получиться проблема, потому
что если на картинке два объекта друг на друга наложатся, то получится каша.
Давайте сделаем так, что нам известно,
где на одной картинке объект, а все остальное место покрыто фоном.
Соответственно, мы можем эти два объекта накладывать таким образом,
что там, где фон, мы берем второй объект.
Там, где первый объект закрывается вторым, мы тоже используем второй объект.
Но такое объединение,
оно достаточно требовательно к качеству вырезания картинки.
Если по краям мы не очень аккуратно вырежем фон,
то будет видна такая некрасивая белая черта.
То есть, например, на левой картинке такие проблемы можно заметить.
С одной стороны, кажется, проблема достаточно сложная
— научиться вырезать объект с фона аккуратно.
Почему это сложно?
Потому что фон неоднородный, и просто выбросить белые пиксели недостаточно.
Но можно поступить другим образом: можно воспользоваться хитрым
алгоритмом смешивания двух картинок и построить
маску таким образом, что она тем больше,
чем пиксель дальше от белого.
Соответственно, там где у нас вот эти белые пятна — артефакты — у
нас будут браться пиксели со второго изображения,
и неаккуратное вырезание объекта будет не так заметно.
Вот на данных картинках вы видите,
как такое простое преобразование помогает избавиться от этой проблемы.
Есть более сложные алгоритмы блендинга,
когда перед нами стоит задача скопировать объект с
неоднородным фоном и вставить его в другое изображение,
Простые методы, которые смешивают цвета, не помогают.
Существуют более хитрые методы,
которые используют оптимизацию для того,
чтобы определить, где объект,
а где фон, и перенести свойства объекта без изменений,
а свойства фона взять с картинки, в которую мы этот объект вставляем.
Мы с вами упоминали цветовые пространства, и самое интуитивное и популярное
— это представление цвета в каналах красного, зелёного и синего.
Другой пример цветового преобразования — это HSV (Hue, Saturation, Value).
Что в перевод на русский означает «тон, насыщенность и значение».
Так вот, это пространство позволяет манипулировать
с цветом и с насыщенностью цвета отдельно.
Тон, он обозначает,
какой цвет есть у данного пикселя.
Он в данном случае закодирован числом от 0 до 360,
как угол на этом цилиндре.
А насыщенность характеризует, насколько насыщен этот цвет.
То есть, если насыщенность 0, то у нас картинка серая.
Как это цветовое пространство можно использовать на практике?
Приведу такой пример, что мы сконвертируем картинку в это пространство,
возьмём канал насыщенности и
умножим его на некий коэффициент больше 1.
Сконвертируем обратно в пространство RGB и вот такой эффект получим.
То есть картинка стала более насыщенная, и цвета — более сочные.
Приведу ещё один пример задачи, это задача детекции лиц.
Задача детекции лиц достаточно сильно эволюционировала,
применялись разнообразные методы,
но одним из первых удачных методов были так называемые каскады Хаара.
Что это такое?
Мы можем из картинки вычленять достаточно простые признаки следующим образом.
Мы берём несколько прямоугольников, вот они проиллюстрированы на картинке.
Там, где белый прямоугольник, мы пиксели берём со знаком «+»,
там, где чёрный — «−».
Все эти пиксели суммируются, и получаем одно число.
Соответственно, у лица есть некоторые характерные паттерны,
с помощью алгоритма обучения AdaBoost мы выбираем
такие прямоугольники и назначаем им соответствующие веса,
и каскад такого рода фильтров Хаара отвечает на вопрос,
есть ли в данном прямоугольнике лицо или нет.
Каскады Хаара — это не самый лучший метод, который сейчас существует,
сейчас существуют более качественные алгоритмы детекции лиц.
Но тем не менее, он достаточно простой,
и его очень легко найти готовым к использованию.
Соответственно, когда не стоит задача очень хорошего качества,
зато нужно быстро и просто получить такой детектор,
каскады Хаара из OpenCv — отличный вариант.
Ещё одна задача, которую достаточно просто решить, это задача сегментации.
Существует огромное количество методов сегментации,
но часть из них можно очень просто сделать, например,
отрезав пиксели выше какого‐то порога
и назначив их одному объекту, а пиксели ниже порога — к фону.
Вот на данной картинке нужно
разделить монеты и фон.
Видно, что монеты намного более тёмные, чем фон.
Соответственно, достаточно просто подобрать такую границу,
что все монеты окажутся ниже этой границы.
Вот кусочек кода из OpenCv, который позволяет это сделать.
На самом деле, это можно сделать многим числом разнообразных способов.
В этом видео я привёл несколько примеров «низкоуровневого» зрения.
Отдельный большой класс задач такого рода — это фильтрация изображений.
Именно про это мы поговорим в следующем видео.