21. 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. Обработка изображения — заливка части изображения
20. Обработка изображения — альфа-смешивание
21. Обработка изображения — пороговое преобразование

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

CVAPI(double)  cvThreshold( const CvArr*  src, CvArr*  dst,
                            double  threshold, double  max_value,
                            int threshold_type );
— выполняет фиксированное пороговое преобразование для элементов массива.

src — исходный массив(изображение) (одноканальное, 8-битное или 32-битное)
dst — целевой массив, должен иметь тот же тип что и src или 8-битный
threshold — пороговая величина
max_value — максимальное значение (используется совместно с CV_THRESH_BINARY и CV_THRESH_BINARY_INV)
threshold_type — тип порогового преобразования:
#define CV_THRESH_BINARY      0  /* value = value > threshold ? max_value : 0       */
#define CV_THRESH_BINARY_INV  1  /* value = value > threshold ? 0 : max_value       */
#define CV_THRESH_TRUNC       2  /* value = value > threshold ? threshold : value   */
#define CV_THRESH_TOZERO      3  /* value = value > threshold ? value : 0           */
#define CV_THRESH_TOZERO_INV  4  /* value = value > threshold ? 0 : value           */
#define CV_THRESH_MASK        7
#define CV_THRESH_OTSU        8  /* use Otsu algorithm to choose the optimal threshold value;
                                    combine the flag with one of the above CV_THRESH_* values */



обычное пороговое преобразование никак не учитывает, что части объектов могут иметь различную яркость из-за разности в освещённости. Это можно исправить если использовать адаптивное пороговое преобразование, которое рассматривает значение не в одном пикселе, а в окрестности пикселя. Это значение может быть просто средним значением пикселей окрестности(т.е. все пиксели равнозначны)(CV_ADAPTIVE_THRESH_MEAN_C), либо пиксели окрестности умножаются на весовой коэффициент (взвешиваются) в соответствии с функцией, например с гауссовой функцией (CV_ADAPTIVE_THRESH_GAUSSIAN_C).

CVAPI(void)  cvAdaptiveThreshold( const CvArr* src, CvArr* dst, double max_value,
                                  int adaptive_method CV_DEFAULT(CV_ADAPTIVE_THRESH_MEAN_C),
                                  int threshold_type CV_DEFAULT(CV_THRESH_BINARY),
                                  int block_size CV_DEFAULT(3),
                                  double param1 CV_DEFAULT(5));
— выполняет адаптивное пороговое преобразование для элементов массива.

src — исходное изображение
dst — целевое изображение
max_value — максимальное значение (используется совместно с CV_THRESH_BINARY и CV_THRESH_BINARY_INV)
adaptive_method — используемый адаптационный алгоритм:
#define CV_ADAPTIVE_THRESH_MEAN_C  0
#define CV_ADAPTIVE_THRESH_GAUSSIAN_C  1


threshold_type — тип порогового преобразования:
#define CV_THRESH_BINARY      0  /* value = value > threshold ? max_value : 0       */
#define CV_THRESH_BINARY_INV  1  /* value = value > threshold ? 0 : max_value       */


block_size — размер окрестности (в пикселях), которая используется для расчёта порогового значения: 3, 5, 7 и т.д.
param1 — параметр, зависящий от используемого метода. Для методов CV_ADAPTIVE_THRESH_MEAN_C и CV_ADAPTIVE_THRESH_GAUSSIAN_C — это константа, вычитаемая из среднего или взвешенного значения (может быть отрицательной)
//
// пример порогового преобразования
// cvThreshold() и cvAdaptiveThreshold()
//

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

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

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

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

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

	dst = cvCreateImage( cvSize(src->width, src->height), IPL_DEPTH_8U, 1);
	dst2 = cvCreateImage( cvSize(src->width, src->height), IPL_DEPTH_8U, 1);

	cvThreshold(src, dst, 50, 250, CV_THRESH_BINARY);
	cvAdaptiveThreshold(src, dst2, 250, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, 7, 1);

	// показываем результаты
	cvNamedWindow( "cvThreshold", 1 );
	cvShowImage( "cvThreshold", dst);
	cvNamedWindow( "cvAdaptiveThreshold", 1 );
	cvShowImage( "cvAdaptiveThreshold", dst2);

	// ждём нажатия клавиши
	cvWaitKey(0);

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



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

CVAPI(void) cvInRange( const CvArr* src, const CvArr* lower,
                      const CvArr* upper, CvArr* dst );
— по-элементная проверка элементов массива: проверяет, что значения элементов массива лежат между значениями элементов двух других массивов.
формула:
dst(idx) = lower(idx) <= src(idx) < upper(idx)

src — исходный массив
lower — массив с нижней границей (включая)
upper — массив с верхней границей (не включая)
dst — массив для хранения результата (тип 8S или 8U)

CVAPI(void) cvInRangeS( const CvArr* src, CvScalar lower,
                       CvScalar upper, CvArr* dst );
— проверяет, что элемент массива лежит между двух скаляров
формула:
dst(idx) = lower <= src(idx) < upper

src — исходный массив
lower — скаляр с нижней границей (включая)
upper — скаляр с верхней границей (не включая)
dst — массив для хранения результата (тип 8S или 8U)

Пример использования:

//
// пример выборки значений в заданном интервале
// cvInRangeS()
//

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

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

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

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

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

	dst = cvCreateImage( cvSize(src->width, src->height), IPL_DEPTH_8U, 1);

	cvInRangeS(src, cvScalar(50), cvScalar(255), dst);

	// показываем результаты
	cvNamedWindow( "cvInRangeS", 1 );
	cvShowImage( "cvInRangeS", dst);

	// ждём нажатия клавиши
	cvWaitKey(0);

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


Простой пример практического применения этих функций — выборка определённых областей изображения, которые отличаются от других яркостью (в случае изображения 1-канального изображения (в градациях серого) ) или цветом (в случае цветного изображения).

дополнительно:
Вопросы OpenCV — пороговое преобразование над цветной картинкой

Читать далее: 22. Поиск объекта по цвету — RGB.
  • 0
  • 18 ноября 2010, 10:54
  • noonv

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

RSS свернуть / развернуть
+
0
Огромное спасибо тебе за уроки!!! если можно пришли свой Email хочу переговорить с тобой….
korvova@yandex.ru
avatar

korvova

  • 27 ноября 2010, 17:56
+
0
А почему на вход должны поступать только изображения в градациях серого?
avatar

orcchg

  • 5 декабря 2010, 21:28
+
0
avatar

noonv

  • 6 декабря 2010, 11:02
+
+1
В cvAdaptiveThreshold не можест стоять что-то, кроме Binary и Binary_inv
opencv.willowgarage.com/documentation/miscellaneous_image_transformations.html
avatar

Asgard

  • 2 декабря 2012, 22:56
+
0
Спасибо! пофиксил
avatar

noonv

  • 3 декабря 2012, 05:03

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