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

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

4. Работа с каналами, пороговая обработка,


заливка. Пример: поиск биллиардных шаров

http://www.svi.nl/wikiimg/SeedAndThreshold_02.png

лекции и объявления: вопросы отправляйте на адрес УрГУ / ИММ осень 2010


www.uralvision.blogspot.com perevalovds@gmail.com
Формат азбуки
1. Название функции
2. Что она делает
3. Для чего она применяется
4. Объявление и описание списка параметров
5. Пример работы:
- работающий код cpp, который считывает изображение, проводит
обработку и выдает картинку на экран или пишет в файл с помощью
функции imwrite
- входная картинка (png или jpg)
- результат работы (png или jpg)
Общие операции
над изображениями
Общие операции над
изображениями
split - разбиение на каналы

merge - сшивка каналов


resize - изменение размера (*)
cvtColor - конвертация цветовых пространств (*)

* - функции для самостоятельного изучения


в Практической задаче 1,
см. распределение по фамилиям на uralvision.blogspot.com
split и merge - описание

Функция split разбивает многоканальное изображение на


каналы.

Функция merge склеивает несколько одноканальных


изображений в многоканальное.

Чаще всего они применяются для поканальной обработки


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

Объявление и описание списка параметров:


void split ( const Mat& mtx, vector<Mat>& mv )
mtx - исходное цветное изображение
mv - результирующий набор 1-канальных изображений

void merge ( const vector<Mat>& mv, Mat& dst )


mv - исходный набор 1-канальных изображений
dst - результирующее цветное изображение
split и merge - пример применения
Задача - на входном цветном изображении обменять местами красный и синий канал, а также
рассчитать 1-канальное изображение, представляющее яркость.

Mat image = imread("C:\\abc-blocks.png"); //загрузка входного изображения


imshow( "Input image", image );

vector<Mat> planes;
split( image, planes ); //разбиение image на три канала planes
imshow( "Blue", planes[0] ); imshow( "Green", planes[1] ); imshow( "Red", planes[2] );

vector<Mat> planesIzm( 3 );
//смена Red и Blue местами:
planesIzm[0] = planes[2]; planesIzm[1] = planes[1]; planesIzm[2] = planes[0];
Mat imageIzm;
merge( planesIzm, imageIzm );
imshow( "Result", imageIzm );

//вычисляем яркость по формуле 0.299*R + 0.587*G + 0.114*B


//(Но, вообще-то, это правильней делать с помощью cvtColor)
Mat gray = 0.299*planes[2] + 0.587*planes[1] + 0.114*planes[0];
imshow( "Gray", gray );
split и merge - пример применения
split и merge - работа с памятью
1. Осуществляется ли копирование данных при
работе со split и merge?

2. В рассмотренном примере - если изменить


imageIzm, то изменится ли image?

- Правильный ответ на эти вопросы является


Практической задачей 2.
Попиксельные операции
Попиксельные операции

threshold - пороговая обработка

adaptiveThreshold - адаптивная пороговая обработка (*)


min, max - минимум, максимум (*)
abs - взятие абсолютного значения (*)
pow - возведение в степень (*)
sqrt - извлечение квадратного корня (*)
randu - заполнение случайными значениями (*)
threshold - описание

Функция threshold осуществляет пороговую обработку


изображения.

Чаще всего она применяются для выделения пикселов


интересующих объектов на изображении.
threshold - список параметров
Объявление и описание списка параметров:
double threshold(const Mat& src, Mat& dst,
double thresh, double maxVal,
int thresholdType)

src и dst - исходное и результирующее 1-канальные изображения.


Допускается, чтобы dst был равен src.
thresh - порог,
maxVal - новое максимальное значение (применяется для THRESH_BINARY,
THRESH_BINARY_INV )
thresholdType - тип функции пороговой обработки:
THRESH_BINARY
THRESH_BINARY_INV
THRESH_TRUNC
THRESH_TOZERO
THRESH_TOZERO_INV
THRESH_OTSU (- тут порог находится автоматически, и это возвращаемое значение)
threshold - список параметров
thresholdType - тип функции пороговой обработки:

THRESH_BINARY

THRESH_BINARY_INV

THRESH_TRUNC

THRESH_TOZERO

THRESH_TOZERO_INV

THRESH_OTSU (- тут порог находится автоматически, и это возвращаемое значение)


threshold - пример применения
Задача - на изображении бильярдного поля выделить пикселы, не являющиеся полем
(условия съемки такие, что поле - темное)

Mat image = imread("C:\\billiard.png"); //загрузка входного изображения


imshow( "Input image", image );
vector<Mat> planes;
split( image, planes );
Mat gray = 0.299*planes[2] + 0.587*planes[1] + 0.114*planes[0];

double thresh = 50.0; //Порог, подбирается опытным путем


threshold( gray, gray, 50.0, 255.0, CV_THRESH_BINARY );

imshow( "Threshold", gray );


threshold - пример применения

Обратите внимание: мы выделили просто пикселы "не поля". Чтобы найти


координаты центров шаров и положение кия - требуется дальнейшая
обработка.
Работа с областями
Работа с областями
floodFill - выделение связных областей

морфологические операции
dilate - дилатация (*)
erode - эрозия (*)
floodFill - описание

Функция floodFill осуществляет заливку области, начиная из некоторого


пиксела (x, y), с заданными границами останова,
используя 4- или 8- смежность пикселов.

Важно: она портит исходное изображение - так как заливает его.

1. Чаще всего она применяются для выделения областей, выделенных


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

2. Также ее можно использовать для удаления мелких шумов на бинарном


изображении (в отличие от способа "эрозия + дилатация" - не портит
границы больших областей).

3.Если расширить габаритный бокс найденной области на 1 пиксел со


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

int floodFill(Mat& image, Point seed, Scalar newVal,


Rect* rect=0,
Scalar loDiff=Scalar(), Scalar upDiff=Scalar(),
int flags=4)
image - входное изображение, 1- или 3-канальное, 8 или 32-битное.
seed - пиксел, с которого начать заливку
rect - габаритный прямоугольник найденной области
loDiff, upDiff - допустимая разность с соседями
(либо - с зародышевым пикселом, если
flags |= FLOODFILL_FIXED_RANGE)
то есть, новый пиксел valueNew должен удовлетворять
value - loDiff <= valueNew <= value + upDiff.
flags = 4 или 8 - связность.

Результирующее значение - число пикселов в залитой области.


floodFill - список параметров

Примечание про типы OpenCV:

Point - целочисленная точка с полями int x, y;


Rect - целочисленный прямоугольник с полями
int x, y, width, height;
Scalar - представление цвета,
например, Scalar( 255 ) - 1-канальный цвет,
Scalar( 255, 255, 255 ) - 3-канальный цвет
floodFill - пример применения
Задача - на изображении биллиардного полян найти биллиардные шары - то есть. вычислить
их центры и размеры. Идея - используя результат примера с threshold, перебрать все связные
области с помощью floodFill, и среди найденных областей считать шарами те, размеры
которых лежат в заранее заданных границах.

const int minRectDim = 25; //макс и мин размеры шаров


const int maxRectDim = 35;

//перебор пикселов изображения


for (int y=0; y<gray.rows; y++) {
for (int x=0; x<gray.cols; x++) {
int value = gray.at<uchar>(y, x);
if ( value == 255 ) { //если значение - 255, то заливаем
//значением 200
Rect rect; //сюда запишется габаритный прямоугольник
int count = floodFill( gray, Point( x, y ), Scalar( 200 ), &rect );
floodFill - пример применения
//проверка размера
if ( rect.width >= minRectDim && rect.width <= maxRectDim
&& rect.height >= minRectDim && rect.height <= maxRectDim )
{
//центр
int x = rect.x + rect.width / 2;
int y = rect.y + rect.height / 2;
//радиус
int rad = ( rect.width + rect.height ) / 4;
//рисуем окружность толщиной 2 пиксела
circle( image, Point( x, y ), rad, Scalar( 255, 0, 255 ), 2 );
}
}
}
}

imshow( "out", image );


floodFill - пример применения
floodFill - пример применения

В данном примере мы рассмотрели простейший способ нахождения шаров на


изображении - путем анализа размеров габаритных прямоугольников.

Такой анализ работает в предположении, что на изображении нет других объектов с


подобными габаритными прямоугольниками.

Для реального применения, требуется более детальный анализ областей.


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

Возможные подходы решения такой проблемы:

1. Залить внутренность области, выделить контур полученной области и


проанализировать его участки выпуклости и вогнутости для выделения шаров.

2. Использовать шаблон "круг", который прикладывать к найденной области и искать


оптимальные его расположения.
Домашнее задание

Практическая задача 1
- см. по фамилии, на uralvision.blogspot.com

Практическая задача 2
- см. в тексте про split и merge.

Оценить