17. OpenCV шаг за шагом. Обработка изображения - морфологические преобразования

1. OpenCV шаг за шагом. Введение.
2. Установка.
3. Hello World.
4. Загрузка картинки.
5. Вывод видео
6. Ползунок
7. Захват видео с камеры
8. Запись видео
9. События от мышки
10. Обработка изображения — сглаживание
11. Обработка изображения — изменение размеров
12. ROI — интересующая область изображения
13. Типы данных OpenCV
14. Матрица
15. Сохранение данных в XML
16. Генерация случайных чисел
17. Обработка изображения — морфологические преобразования

Основные морфологические преобразования:
Erode — размывание(операция сужения)
Dilate — растягивание(операция расширения)

OpenCV реализует их двумя функциями:
CVAPI(void)  cvErode( const CvArr* src, CvArr* dst,
                      IplConvKernel* element CV_DEFAULT(NULL),
                      int iterations CV_DEFAULT(1) );
— размывает(операция сужения) изображение с использованием фильтра(ядра) один или несколько раз,
если element == NULL используется ядро 3х3
(изображение формируется из локальных минимумов — т.е. будут увеличиваться тёмные области)

CVAPI(void)  cvDilate( const CvArr* src, CvArr* dst,
                       IplConvKernel* element CV_DEFAULT(NULL),
                       int iterations CV_DEFAULT(1) );
— растягивает(операция расширения) изображение с использованием фильтра(ядра) один или несколько раз,
если element == NULL используется ядро 3х3
(изображение формируется из локальных максимумов — т.е. будут увеличиваться светлые области)

// #define CV_DEFAULT(val) = val

src — исходное изображение
dst — получаемое изображение
element — структурирующий элемент (ядро) по-умолчанию NULL — соответствует ядру 3x3 с якорем по-центру.
[ ][ ][ ]
[ ][+][ ]
[ ][ ][ ]

структура ядра:
typedef struct _IplConvKernel
{
    int  nCols;
    int  nRows;
    int  anchorX;
    int  anchorY;
    int *values;
    int  nShiftR;
}
IplConvKernel;


iterations — число итераций (сколько раз повторить морфологическое преобразование)

! обе функции позволяют, чтобы в качесте dst выступало исходное изображение src.

В cvErode() ядро накладывается на изображение и на месте якоря (центр ядра) остаётся минимальное значение, лежащее под ядром (в случае cvDilate() — наоборот — максимальное )

Эрозия (размывание/сужение) изображения обычно используется для избавления от случайных вкраплений на изображении. Идея состоит в том, что вкрапления при размывании устранятся, тогда как крупные и соответсвенно более визуально-значимые регионы остаются.

Растягивание (расширение) же, по идее, так же должно устранять шум и способствовать объединению областей изображения, которые были разделены шумом, тенями, etc.
Применение же небольшого растягивания должно сплавить эти области в одну.

Морфологические операции, чаще всего, применяются над двоичными изображениями, которые получаются после порогового преобразования (thresholding).

Создание ядра произвольной формы осуществляется функцией cvCreateStructuringElementEx():

CVAPI(IplConvKernel*)  cvCreateStructuringElementEx( int cols, int  rows, int  anchor_x, int  anchor_y, int shape, int* values CV_DEFAULT(NULL) );
— создание структурирующего элемента (ядра) для морфологических операций.
например, cvErode() или cvDilate()

cols — число колонок ядра
rows — число стор ядра
anchor_x — относительное горизонтальное смещение якоря ядра
anchor_y — относительное вертикальное смещение якоря ядра
shape — форма ядра:
#define  CV_SHAPE_RECT      0
#define  CV_SHAPE_CROSS     1
#define  CV_SHAPE_ELLIPSE   2
#define  CV_SHAPE_CUSTOM    100

— в последнем случае, форму определяет пользователь через values, которая содержит маску, определяющую какие соседние пиксели должны учитываться

values — указатель на массив, в котором ненулевые элементы определяют значимые пиксели. Если values==NULL все элементы считаются ненулевыми.
(этот параметр учитывается только в случае shape==CV_SHAPE_CUSTOM)

CVAPI(void)  cvReleaseStructuringElement( IplConvKernel** element );
— освобождение памяти, выделенной под структурирующий элемент(ядро)

Выбирая различную структуру ядра можно решать различные задачи обработки изображений:
— подавление шумов;
— выделение границ объекта;
— выделение скелета объекта;

//
// пример базовых морфологических преобразований
// cvErode() и cvDilate()
//

#include <cv.h>
#include <highgui.h>
#include <stdlib.h>
#include <stdio.h>

IplImage* image = 0;
IplImage* dst = 0;

IplImage* erode = 0;
IplImage* dilate = 0;

int radius = 1;
int radius_max=10;

//
// функция-обработчик ползунка - 
// радиус ядра
void myTrackbarRadius(int pos) {
	radius = pos;
}

int iterations = 1;
int iterations_max = 10;

//
// функция-обработчик ползунка - 
// число итераций
void myTrackbarIterations(int pos) {
	iterations = pos;
}

int main(int argc, char* argv[])
{
	// имя картинки задаётся первым параметром
	char* filename = argc == 2 ? argv[1] : "Image0.jpg";
	// получаем картинку
	image = cvLoadImage(filename,1);
	// клонируем картинку 
	dst = cvCloneImage(image);
	erode = cvCloneImage(image);
	dilate = cvCloneImage(image);

	printf("[i] image: %s\n", filename);
	assert( image != 0 );

	// окно для отображения картинки
	cvNamedWindow("original",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("erode",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("dilate",CV_WINDOW_AUTOSIZE);

	cvCreateTrackbar("Radius", "original", &radius, radius_max, myTrackbarRadius);
	cvCreateTrackbar("Iterations", "original", &iterations, iterations_max, myTrackbarIterations);


	while(1){

		// показываем картинку
		cvShowImage("original",image);

		// создаём ядро
		IplConvKernel* Kern = cvCreateStructuringElementEx(radius*2+1, radius*2+1, radius, radius, CV_SHAPE_ELLIPSE);

		// выполняем преобразования
		cvErode(image, erode, Kern, iterations);
		cvDilate(image, dilate, Kern, iterations);

		// показываем результат
		cvShowImage("erode",erode);
		cvShowImage("dilate",dilate);
		
		cvReleaseStructuringElement(&Kern);

		char c = cvWaitKey(33);
		if (c == 27) { // если нажата ESC - выходим
			break;
		}
	}

	// освобождаем ресурсы
	cvReleaseImage(&image);
	cvReleaseImage(&dst);
	cvReleaseImage(&erode);
	cvReleaseImage(&dilate);
	// удаляем окно
	cvDestroyWindow("original");
	cvDestroyWindow("erode");
	cvDestroyWindow("dilate");
	return 0;
}



Далее: 18. Обработка изображения — морфологические преобразования 2
  • +1
  • 23 сентября 2010, 10:24
  • noonv

Комментарии (18)

RSS свернуть / развернуть
+
0
Что-то у меня вообще код не идет. Вылетает «прекращена работа lala.exe» и все тут!
в чем косяк?=\
avatar

NoHope

  • 30 января 2011, 01:04
+
0
сразу после запуска или в процессе работы?
avatar

noonv

  • 30 января 2011, 09:57
+
0
да, окно открывается и сразу же вылетает такое сообщение и все.
avatar

NoHope

  • 30 января 2011, 14:13
+
0
странно :) а какая версия OpenCV?
avatar

noonv

  • 30 января 2011, 14:18
+
0
2.2. Наверняка с установкой какие-то проблемы=\ у меня Visual Studio 2008 Express Edition стоит, мб в этом косяк?
avatar

NoHope

  • 30 января 2011, 16:01
+
0
Express Edition ни при чём, хотя 2.2 по-дефолту идёт для 2010 студии.
avatar

noonv

  • 30 января 2011, 16:16
+
0
фэйл… Мда, видимо скелетам придется еще подождать..=(
avatar

NoHope

  • 30 января 2011, 16:59
+
0
fatal error LNK1104: cannot open file 'C:\Program.obj'
вот что он пишет теперь…
avatar

NoHope

  • 30 января 2011, 17:04
+
0
а у Вас программы с предыдущих шагов работали? :)
avatar

noonv

  • 30 января 2011, 17:08
+
0
с предыдущих вылетал .exe, а теперь тема с этим C:\Program. Но откуда оно взялось, я только что поняла: когда в линкере-инпуте прописываешь пути к .lib, там стоит C:\Program Files\OpenCV и тд. Так вот когда я нажимаю ОК, закрываю все, запускаю прогу, появляется эта ошибка. Если снова зайти в линкер, то там вместо того, что я прописывала, появляется следующая картина:
C:\Program
Files\OpenCV\и тд. И почему он слово «Files» перекидывает на другую строчку, мне ваще не понятно ><
avatar

NoHope

  • 30 января 2011, 17:21
+
0
щас на VS 2010 все проверили: работает. А у меня так и нет!
avatar

NoHope

  • 30 января 2011, 19:25
+
0
м, кстати, может Вы посоветуете насчет алгоритмом скелетизации и сред для их реализации что-нить? где лучше, какой именно?)
avatar

NoHope

  • 30 января 2011, 19:24
+
0
думаю, нужно просто пересобрать библиотеку под 2008-й и всё заработает ;) библиотека пересобирается с помощью CMake так же как описано про установку 2.0
avatar

noonv

  • 30 января 2011, 19:44
+
0
вроде по инструкции я все поставила, и теперь снова вылетает .exe!!! ><
avatar

NoHope

  • 30 января 2011, 21:48
+
0
Так, наконец-то все заработало)
Скажите, а как выделять скелет с помощью этого всего?
avatar

NoHope

  • 2 февраля 2011, 16:15
+
0
Маааленькая ошибочка:
// функция-обработчик ползунка —
// число итераций
void myTrackbarIterations(int pos) {
// radius = pos;
iterations = pos;
}

А вопрос мой вот в чём:
Позволяет ли OpenCV реализовать слушателей трэкбара без колбэков?
(Пишу на JavaCV, с колюэком возникли проблемы, тк функции типа cvCreateTrackbar(...) не принимают в качестве параметра указатель на функцию)
avatar

Kseniya

  • 8 апреля 2012, 08:14
+
0
Спасибо! пофиксил.
кажется — нет, но ведь никто не мешает использовать вместо OpenCV-х трэкбаров любые другие ;)
avatar

noonv

  • 8 апреля 2012, 08:18
+
0
И правда… Спасибо! Так быстрее заработало ;)
avatar

Kseniya

  • 8 апреля 2012, 08:46

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.