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 — соответствует ядру 3×3 с якорем по-центру.

[ ][ ][ ]
[ ][+][ ]
[ ][ ][ ]

структура ядра:

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


0 комментариев на «“17. OpenCV шаг за шагом. Обработка изображения — морфологические преобразования”»

    • сразу после запуска или в процессе работы?

    • да, окно открывается и сразу же вылетает такое сообщение и все.

    • Express Edition ни при чём, хотя 2.2 по-дефолту идёт для 2010 студии.

    • фэйл… Мда, видимо скелетам придется еще подождать..=(

    • а у Вас программы с предыдущих шагов работали? 🙂

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

    • щас на VS 2010 все проверили: работает. А у меня так и нет!

    • думаю, нужно просто пересобрать библиотеку под 2008-й и всё заработает 😉 библиотека пересобирается с помощью CMake так же как описано про установку 2.0

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

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

    • Спасибо! пофиксил.
      кажется — нет, но ведь никто не мешает использовать вместо OpenCV-х трэкбаров любые другие 😉

    • И правда… Спасибо! Так быстрее заработало 😉

Добавить комментарий

Arduino

Что такое Arduino?
Зачем мне Arduino?
Начало работы с Arduino
Для начинающих ардуинщиков
Радиодетали (точка входа для начинающих ардуинщиков)
Первые шаги с Arduino

Разделы

  1. Преимуществ нет, за исключением читабельности: тип bool обычно имеет размер 1 байт, как и uint8_t. Думаю, компилятор в обоих случаях…

  2. Добрый день! Я недавно начал изучать программирование под STM32 и ваши уроки просто бесценны! Хотел узнать зачем использовать переменную типа…

3D-печать AI Arduino Bluetooth CraftDuino DIY Google IDE iRobot Kinect LEGO OpenCV Open Source Python Raspberry Pi RoboCraft ROS swarm ИК автоматизация андроид балансировать бионика версия видео военный датчик дрон интерфейс камера кибервесна манипулятор машинное обучение наше нейронная сеть подводный пылесос работа распознавание робот робототехника светодиод сервомашинка собака управление ходить шаг за шагом шаговый двигатель шилд юмор

OpenCV
Робототехника
Будущее за бионическими роботами?
Нейронная сеть - введение