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

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

Когда я говорил, что OpenCV реализует морфологические преобразования всего двумя функциями, я, разумеется, лукавил.
Есть ещё одна замечательная функция — cvMorphologyEx(). Она обеспечивает более сложные морфологические преобразования изображения.

CVAPI(void)  cvMorphologyEx( const CvArr* src, CvArr* dst,
                             CvArr* temp, IplConvKernel* element,
                             int operation, int iterations CV_DEFAULT(1) );
— выполняет сложное морфологическое преобразование

src — исходное изображение
dst — изображение для сохранения результата
temp — для промежуточного хранения результатов (размер изображения должен совпадать с размером исходного изображения) — требуется при определённом значении operation
operation — определяет тип морфологического преобразования:
#define CV_MOP_OPEN         2
#define CV_MOP_CLOSE        3
#define CV_MOP_GRADIENT     4
#define CV_MOP_TOPHAT       5
#define CV_MOP_BLACKHAT     6


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

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

! Порядок выполнения операции CV_MOP_CLOSE при числе итераций iterations==2:
Dilate-Dilate-Erode-Erode !


CV_MOP_GRADIENT:
gradient(src) = Dilate(src)–Erode(src)
Результатом этой операции над двоичным изображением станет выделение периметров существующих пятен. На картинке с градациями серого градиент покажет как быстро меняется яркость (поэтому и называется — градиент).


CV_MOP_TOPHAT и CV_MOP_BLACKHAT:
TopHat(src) = src–Open(src)
BlackHat(src) = Close(src)–src

CV_MOP_TOPHAT — изолирует яркие локальные пики

CV_MOP_BLACKHAT — изоляция тёмных регионов


//
// пример работы cvMorphologyEx()
//

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

IplImage* image = 0;
IplImage* dst = 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) {
	radius = pos;
}

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

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

	// окно для отображения картинки
	cvNamedWindow("original",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("morphology",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);

		// картинка для промежуточного хранения результатов cvCreateImage
		IplImage* Temp = 0;
		Temp = cvCreateImage(cvSize(image->width, image->height) , IPL_DEPTH_8U, 1);
		// выолняем преобразование
		cvMorphologyEx(image, dst, Temp, Kern, CV_MOP_OPEN, iterations);


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

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

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


а теперь соберём все параметры преобразования cvMorphologyEx() вместе:

//
// пример работы cvMorphologyEx()
//
// покажем все методы сразу
//

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

IplImage* image = 0;
IplImage* open = 0;
IplImage* close = 0;
IplImage* gradient = 0;
IplImage* tophat = 0;
IplImage* blackhat = 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) {
	radius = pos;
}

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

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

	// окно для отображения картинки
	cvNamedWindow("original",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("CV_MOP_OPEN",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("CV_MOP_CLOSE",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("CV_MOP_GRADIENT",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("CV_MOP_TOPHAT",CV_WINDOW_AUTOSIZE);
	cvNamedWindow("CV_MOP_BLACKHAT",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);

		// картинка для промежуточного хранения результатов cvCreateImage
		IplImage* Temp = 0;
		Temp = cvCreateImage(cvSize(image->width, image->height) , IPL_DEPTH_8U, 1);
		// выолняем преобразования
		cvMorphologyEx(image, open, Temp, Kern, CV_MOP_OPEN, iterations);
		cvMorphologyEx(image, close, Temp, Kern, CV_MOP_CLOSE, iterations);
		cvMorphologyEx(image, gradient, Temp, Kern, CV_MOP_GRADIENT, iterations);
		cvMorphologyEx(image, tophat, Temp, Kern, CV_MOP_TOPHAT, iterations);
		cvMorphologyEx(image, blackhat, Temp, Kern, CV_MOP_BLACKHAT, iterations);


		// показываем результат
		cvShowImage("CV_MOP_OPEN",open);
		cvShowImage("CV_MOP_CLOSE",close);
		cvShowImage("CV_MOP_GRADIENT",gradient);
		cvShowImage("CV_MOP_TOPHAT",tophat);
		cvShowImage("CV_MOP_BLACKHAT",blackhat);
		
		cvReleaseStructuringElement(&Kern);
                cvReleaseImage(&Temp);

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

	// освобождаем ресурсы
	cvReleaseImage(&image);
	cvReleaseImage(&open);
	cvReleaseImage(&close);
	cvReleaseImage(&gradient);
	cvReleaseImage(&tophat);
	cvReleaseImage(&blackhat);
	// удаляем окна
	cvDestroyAllWindows();
	return 0;
}



CVAPI(void) cvDestroyAllWindows(void);
— удаляет все окна

Читать далее: 19. Обработка изображения — заливка части изображения
  • 0
  • 1 октября 2010, 10:15
  • noonv

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

RSS свернуть / развернуть
+
+1
В первом примере есть хорошая утечка памяти так как не освобождается временное изображение (переменная Temp).

Нужно пере строкой
cvReleaseStructuringElement(&Kern);

добавить следующее:
cvReleaseImage(&Temp);

:)
avatar

Mur

  • 11 ноября 2010, 22:22
+
0
Верно :) Спасибо, пофиксил.
avatar

noonv

  • 11 ноября 2010, 22:26
+
0
Всегда пожалуйста :)

А потом будет открыта тайна какое практическое значение можно выудить из этих методов, а то уже интрига есть. Уж больно интересно :)
avatar

Mur

  • 11 ноября 2010, 22:34
+
0
Есть предложение по поводу кода, дабы не делать большую нагрузку на компьютер лучше обновлять картинки по изменению ползунков. Для этого достаточно немного модифицировать код.
1. cvWaitKey поставить с параметром 0.
2. В обработчики ползунков, после присваивания значений добавить следующую строчку:
keybd_event(VK_SPACE,0,KEYEVENTF_EXTENDEDKEY,0); //Нажата клавиша пробел

avatar

Mur

  • 11 ноября 2010, 23:47
+
0
keybd_event(VK_SPACE,0,KEYEVENTF_EXTENDEDKEY,0)

не могу понять зачем всовывать ее в обработчик ползунков. и вообще странные эти обработчики, которые вызываются однажды и работают как то постоянно, т.е. это не противоречит концепции с++, что выполненная функция должна стереться с лица памяти?)
где можно посмотреть прототип функции keybd_event() она из она библиотеки openCV?
avatar

Zybr

  • 13 февраля 2014, 14:50
+
0
Читая код с листа кажется, что код
void myTrackbarIterations(int pos) { radius = pos;}

должен выглядеть как
void myTrackbarIterations(int pos) { iterations = pos;}

Я что-то упускаю?
avatar

mvch

  • 21 декабря 2010, 18:55
+
0
:) экспериментируйте :)
avatar

noonv

  • 21 декабря 2010, 19:06

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