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 комментариев на «“18. OpenCV шаг за шагом. Обработка изображения — морфологические преобразования 2”»
В первом примере есть хорошая утечка памяти так как не освобождается временное изображение (переменная Temp).
Нужно пере строкой
cvReleaseStructuringElement(&Kern);
добавить следующее:
cvReleaseImage(&Temp);
🙂
Верно 🙂 Спасибо, пофиксил.
Всегда пожалуйста 🙂
А потом будет открыта тайна какое практическое значение можно выудить из этих методов, а то уже интрига есть. Уж больно интересно 🙂
Есть предложение по поводу кода, дабы не делать большую нагрузку на компьютер лучше обновлять картинки по изменению ползунков. Для этого достаточно немного модифицировать код.
1. cvWaitKey поставить с параметром 0.
2. В обработчики ползунков, после присваивания значений добавить следующую строчку:
keybd_event(VK_SPACE,0,KEYEVENTF_EXTENDEDKEY,0); //Нажата клавиша пробел
не могу понять зачем всовывать ее в обработчик ползунков. и вообще странные эти обработчики, которые вызываются однажды и работают как то постоянно, т.е. это не противоречит концепции с++, что выполненная функция должна стереться с лица памяти?)
где можно посмотреть прототип функции keybd_event() она из она библиотеки openCV?
Читая код с листа кажется, что код
void myTrackbarIterations(int pos) { radius = pos;}
должен выглядеть как
void myTrackbarIterations(int pos) { iterations = pos;}
Я что-то упускаю?
🙂 экспериментируйте 🙂