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

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
19. Обработка изображения — заливка части изображения

cvFloodFill() — полезная функция, если требуется пометить или изолировать область изображения для дальнейшего анализа. Т.е. эта функция реализует заливку области, что наводит на мысли об аналогичных инструментах в графических редакторах :)

CVAPI(void)  cvFloodFill( CvArr* image, CvPoint seed_point,
                          CvScalar new_val, CvScalar lo_diff CV_DEFAULT(cvScalarAll(0)),
                          CvScalar up_diff CV_DEFAULT(cvScalarAll(0)),
                          CvConnectedComp* comp CV_DEFAULT(NULL),
                          int flags CV_DEFAULT(4),
                          CvArr* mask CV_DEFAULT(NULL));
— заполняет связанную область заданным цветом. Начиная с заданной начальной точки и далее, определяя принадлежность области по близости значений соседних пикселей.

image — входное изображение (1- или 3-канальное), 8-битное или 32F. Изображение модифицируется функцией, если не установлен флаг CV_FLOODFILL_MASK_ONLY
seed_point — начальная точка
new_val — новое значение пикселей
lo_diff — максимальное нижнее значение разницы в яркости/цвете между наблюдаемым пикселем и одним из его соседей, чтобы добавить его в область. В случае 8-битного цветного изображения — это упакованное значение.
up_diff — максимальное верхнее значение разницы в яркости/цвете между наблюдаемым пикселем и одним из его соседей, чтобы добавить его в область. В случае 8-битного цветного изображения — это упакованное значение.
comp — указатель на структуру CvConnectedComp, которую заполняет функция, возвращая в неё информацию о заполненной области:
typedef struct CvConnectedComp
{
    double area;    /* площадь  */
    CvScalar value; /* усреднённый цвет области */
    CvRect rect;    /* ROI - область интереса */
    CvSeq* contour; /* граница */
}
CvConnectedComp;


flags — флаг операции. Младшие биты содержат значение связности — 4(по-умолчанию) или 8, используемое функцией. Связность определяет сколько соседей пикселя обрабатываются. Старшие биты могут быть 0 или комбинацией флагов:
#define CV_FLOODFILL_FIXED_RANGE (1 << 16)
#define CV_FLOODFILL_MASK_ONLY   (1 << 17)


CV_FLOODFILL_FIXED_RANGE — если установлен, используется разница между текущим пикселем и начальным пикселем, в противном случае — используется разница между соседними пикселями (плавающий диапазон)

CV_FLOODFILL_MASK_ONLY — если установлен, то функция не вносит изменений в изображение, но заполняет маску (которая, в данном случа, должна быть отлична от NULL )

mask — маска операции, 1-канальное 8-битное изображение, на 2 пикселя шире и длинее, чем изображение. Если отлично от NULL, то функция использует и обновляет маску. Заполнение не будет идти поверх ненулевых пикселей маски. Например, детектор границ может использоваться в качестве маски для остановки заливки на границах. Возможно использование одной маски в нескольких вызовах функции, для уверенности, что заполненные области не перекроются.

! NB: т.к. маска больше, чем изображение — пиксель маски, соответствующий пикселю (x,y) изображения, имеет координаты (x+1, y+1)


//
// пример использования функции cvFloodFill()
// для заливки области
// начальный пиксель области выбирается по клику мышкой
//

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

// заливка области картинки цветом
void fill(IplImage* src, CvPoint seed, CvScalar color=CV_RGB(255, 0, 0))
{
	assert(src);

	CvConnectedComp comp;

	cvFloodFill( src, seed, color, 
                 cvScalarAll(10), // минимальная разность
                 cvScalarAll(10), // максимальная разность
                 &comp,
                 CV_FLOODFILL_FIXED_RANGE + 8,
                 0);

	// покажем площадь заливки
	printf("[filled area] %.2f\n", comp.area);
}

// обработчик событий от мышки
void myMouseCallback( int event, int x, int y, int flags, void* param )
{
	IplImage* img = (IplImage*) param;

	switch( event ){
		case CV_EVENT_MOUSEMOVE: 
			break;

		case CV_EVENT_LBUTTONDOWN:
			printf("%d x %d\n", x, y);

			// вызываем нашу функцию-обёртку вокруг cvFloodFill()
			fill(img, cvPoint(x, y));
			
			break;

		case CV_EVENT_LBUTTONUP:
			break;
	}
}

int main(int argc, char* argv[])
{
	IplImage *src=0, *dst=0;

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

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

	// покажем изображение
	cvNamedWindow( "original", 1 );

	// вешаем обработчик мышки
	cvSetMouseCallback( "original", myMouseCallback, (void*) src);

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

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

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




Пример работы функции при клике в верхнем левом углу и установленном флаге CV_FLOODFILL_FIXED_RANGE. Если же этот флаг убрать, то при той же начальной точке будет закрашена почти вся картинка.

Читать далее: 20. Обработка изображения — альфа-смешивание
  • 0
  • 18 октября 2010, 10:07
  • noonv

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

RSS свернуть / развернуть
+
0
IplImage *src=0, *dst=0;

*dst — походу лишние.:)
avatar

loGIc

  • 22 января 2011, 17:54
+
0
Привет! Спасибо за классные уроки.
А есть ли способ обнаружить на картинке все пиксели заданного цвета, с некоторой разницей яркости, и изменить их цвет на другой?
Спасибо.
avatar

Dreddik

  • 9 февраля 2011, 14:42
+
0
Уроки супер, спасибо огромное!!! Вопрос, как сделать так, что бы при новом нажатии ЛКМ старая область затиралась?
avatar

Francuz

  • 23 марта 2011, 21:43
+
0
рисовать не на оригинальном изображении, а на его копии, которую обновлять при следующем нажатиии.
avatar

noonv

  • 23 марта 2011, 22:28
+
0
Помогите, пожалуйста, вопрос такой:
компилятор ругается на функцию fill(img, cvPoint(x, y));
Якобы 'fill': identifier not found
Нигде на просторах Вселенной не смогла найти ответ на эту загадку)
avatar

kirsten_Zh

  • 12 мая 2018, 11:31
+
0
Возможно компилятору не нравится, что нет объявления функции — можно попробовать добавить его после includ-ов.
avatar

admin

  • 14 мая 2018, 10:09

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