Вы находитесь на странице: 1из 16

с/к Анализ изображений, OpenCV

3. Основы OpenCV для C++: класс Mat

http://blog.iseesystems.com/wp-content/uploads/2009/07/cube-matrix.jpg
Виды изображений
в компьютере
1. Цикл жизни изображений

1. Ввод — 8bit
(видео/фото камера).

2. Программа обработки — 32 бит


(OpenCV, Photoshop, 3D-видеокарта).

3. Вывод — 8 бит
(на экран, принтер, веб, в виде bmp, jpg, png).

Почему так: дело в том, что для проведения точных вычислений интервал целых
значений 0..255 - слишком мал. А для вывода информации на экран человеку —
вполне достаточен.
2. Понятие полутоновых
изображений
Полутоновое изображение — в котором значения пикселов
являются скалярной величиной.

1) Значения могут быть целым числом


(обычно 8-битным, значения 0..255).

Такие изображения применяются для вывода изображений на экран, а также для


ввода данных с видео и фото камер.
В частности, jpg, png и bmp форматы хранят изображения в таком виде.

2) Значения могут быть числом с плавающей точкой


(обычно 32-битные float).

Такие изображения используются видеокартами, программами обработки


изображений и алгоритмами анализа изображений для проведения вычислений.
3. Понятие цветных изображений
«Цветное» изображение
— еще оно называется многоканальным

— значения пикселов являются вектором.

Также значения могут быть целым числом либо числом с плавающей точкой.

Число каналов:
чаще всего 3,
чаще всего это RGB = Red, Green, Blue.
3. Понятие цветных изображений
Кроме RGB, для компьтерного зрения ценным является формат YUV.
Он содержит отдельно компоненту яркости, а две других отвечают за цвет.

Для дизайна также применяются форматы HUI, HSV — они отдельно представляют
яркость, насщенность, контраст.

В полиграфии применяется CMYK.


4. Многоканальные изображения
в OpenCV
OpenCV работает с 1, 2, 3, 4-канальными изображениями.

1-канальные — полутоновые.

2-канальные — используются для представляния векторных полей (типа


оптического потока).

Внимание: они не будут выводиться на экран обычными средствами отображения


типа imshow.

3-канальные — цветные.

4-канальные — содержат дополнительный канал Alpha, который используется


обычно для задания прозрачности.

Внимание: текущая реализация OpenCV не учитывает в работе канал Alpha. В


частности, при рисовании изображений средствами OpenCV 4-канальные
изображения не будут прозрачными.
Создание и обработка
изображений
в OpenCV C++
1. Основной тип данных в OpenCV C++
Mat - класс для хранения изображений
Создание изображений:

1) Пустое изображение без определенного типа

Mat imageEmpty;

2) Изображение w x h пикселов, значения 0..255 (8U = unsigned 8 bit),


полутоновое (C1, т.е. один канал)

int w=150; int h=100;


Mat imageGray( h, w, CV_8UC1 );
//Обратите внимание, что w и h переставлены местами

3) 1-канальное со значениями с плавающей точкой (32F = float 32 bit)

Mat imageFloat( h, w, CV_32FC1 );

4) 3-канальное изображения со значениями 0..255 в каждом канале

Mat imageRGB( h, w, CV_8UC3 );


2. Конвертация типов
Примечание:
При выводе на экране изображений с плавающей точкой средствами OpenCV
надо иметь в виду, что они отображаются в предположении, что их значения
лежат в [0,1]. Поэтому при конвертации 8-битных изображений в изображения с
плавающей точкой нужно делать трансформацию — умножение на 1.0 / 255.0.

Для конвертации используется член класса convertTo.


В нем второй параметр — тип получаемого изображения.

imageGray.convertTo( imageFloat, CV_32FC1, 1.0 / 255.0 );

Внимание:
OpenCV может автоматически сменить тип результирующего изображения и
размер. В частности, если результирующее изобаржение было пустым, после
применения convertTo оно будет нужного типа и размера. Такое замечание Это
относится ко всем основным функциям OpenCV:

imageRGB.convertTo( imageEmpty, CV_32FC3, 1.0 / 255.0 );

(Тут произошла конвертация 3-канального 8-битного изображения в 3-


канальное с плавающей точкой. Заметьте, что до применения команды
imageEmpty было пустым.)
3. Копирование изображений
и управление памятью
Базовой для понимания этого является иделогия работы с памятью в OpenCV
C++:

1. Память для изображений выделяется и очищается автоматически.

Это значит, что OpenCV сам создает изображение нужного типа и размера,
если это изображение является выходным параметром некоторой функции:

Image imageFloat;
imageGray.convertTo( imageFloat, CV_32FC1, 1.0 / 255.0 );

- здесь OpenCV сам выделит память под imageFloat.


Важно, что если изображение уже нужного размера, то никаких операций по
выделению памяти не производится.

2. Операции присваивания осуществляются не копированием данных (как


это делает std::vector), и не путем копирования указателей, а с
использованием механизма счетчика ссылок.
3. Копирование изображений
и управление памятью
Механизм счетчика ссылок (в STL это shared_ptr, в Java он на всех
указателях)
Работает так:

void fun() {
Mat A( 100, 100, CV_8UC1 );
//выделилась память под изображение, при этом запомнилось, что эта
//память используется одним изображением.
{
Mat B = A;
//тут память под изображение не выделяется, а просто данные в B
//указывают на ту же область в памяти. Поэтому, если менять B, то
//изменится и A. Счетчик ссылок изображения увеличился, стал
//равным 2.
}
//Тут B вышло из области видимости, счетчик ссылок уменьшился,
//и стал равен 1.
}
Тут A вышло из области видимости, счетчик ссылок стал равен 0,
и память под изображения автоматически очищается, так как она уже никем
не используется..
3. Копирование изображений
и управление памятью
Поэтому, чтобы создать копию изображения для последующего
использования, применяются явные команды copyTo и clone:

image1.copyTo( image2 );
image3 = image1.clone();

Итог:
1) операция присваивания Mat B = A; работает очень быстро, и не
осуществляет копирование данных, а настраивает специальным образом
указатели. Это позволяет передавать Mat в функции прямо, без указателей и
ссылок. При этом не возникнет нежелательного копирования Mat в стек (как
это бы сталал std::vector).

Хотя, конечно, const Mat & будет передаваться все равно быстрее.

2) для копирования изображений нужно пользоваться явными командами


copyTo() и clone().
4. Вырезание прямоугольных
фрагментов
Есть возможность эффективно вырезать прямоугольную часть изображения. При
этом также не происходит копирования данных, что делает такую операцию
чрезвычайно эффективной и удобной для проведения изменения и анализа
фрагментов изображений.

Технически это реализуется с помощью хранения скачка между соседними


строками изображения.

Как это делается:

Rect rect(0, 0, 100, 100); //создается прямоугольник x, y, w, h:

Mat subimage = image( rect );


//вырезает часть изображение, при этом данные не копируются,
//и также увеличивается счетчик ссылок

//Если же требуется копирование данных:


image( rect ).copyTo( subimage );
5. Попиксельный доступ
к изображениям
В OpenCV есть несколько способов попиксельного доступа к изображениям.
Они различны по степени безопасности (контроль типов и выхода за границы), по
скорости работы и удобству.

Всюду, где это возможно, следует стараться избегать прямых обращений к


пикселам, а вместо этого пользоваться функциями OpenCV, так как они обычно
работают быстрее, а код понятнее.

Один из способов доступа к пикселам для изображений, у которых известен тип -


использование метода at. Для одноканального изображения 0...255 это делается
так:

//Взятие значения
int value = imageGray.at<uchar>(y, x);
//Установка значения
imageGray.at<uchar>(y, x) = 100;

Обратите внимание, что x и y в вызове переставлены местами.


6. О выводе изображений
на экран
Функция imshow показывает изображение в отдельном окне экрана

imshow( “image”, image );


//Показывает image в окне с названием «image»

Эта функция чрезвычайно полезна для отладки и настройки


алгоритмов путем показа промежуточных изображений в ходе
обработки.

В то же время, в конечном продукте эти окна обычно показывать не


стоит.

Примечания:
1. Эта функция не показывает 2-канальные изображения.
2. Помните, что при показе изображений типа float предполагается,
что значения каналов пикселов лежат в отрезке [0,1]. Поэтому
значения, выходящие за пределы этого отрезка, будут образаться.