Это статья рассчитана на новичков, которые только начинают осваивать методы обработки изображений. Сама я часто сталкиваюсь с отсутствием легких примеров, особенно на русском языке, поэтому надеюсь данный материал окажется полезным.
Как-то встала передо мной следующая задача. У меня было много фотографий болгарских перцев и необходимо было отделить растение от фона. На примере этой задачи я покажу один из самых примитивных способов как это можно сделать при помощи openCV 2.4.
Суть задачи: закрасить белым все что не является растением.

Исходная фотография (слева) и то что должно получиться (справа).
Для начала загрузим изображение:
По умолчанию в opencv цветное изображение хранится палитре BGR. Определять цвет в BGR не очень удобно, поэтому для начала переведем изображение в формат HSV.

Так как искать растение мы будем именно по цвету, то больше всего нас интересует именно тон.
Преобразуем изображение в палитру HSV и разобьем на три составляющие Hue Saturation Value соответственно.
Зададим диапазон значений тона. В OpenCV зеленый находится в диапазоне от 34 до 72. Перец на фотографиях не полностью зеленый. Поэтому опытным путем был подобран диапазон от 21 до 110.
Далее пробежимся по нашему изображению. Для каждого пикселя получим все три компоненты. Интенсивность мы использовать не будем, но, чтобы было понятнее и не перескакивать индексы я ее оставлю. Если тон не укладывается в заданный диапазон или яркость слишком низкая – значит это фон, поэтому закрашиваем все белым цветом.
В результате у нас получится такое изображение:

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

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

Слева маска, справа результат применения маски.
Вот таким способом можно примитивно выделить объект из фона.
→ Полный код примера
UPD: исправлена битая ссылка.
Как-то встала передо мной следующая задача. У меня было много фотографий болгарских перцев и необходимо было отделить растение от фона. На примере этой задачи я покажу один из самых примитивных способов как это можно сделать при помощи openCV 2.4.
Суть задачи: закрасить белым все что не является растением.

Исходная фотография (слева) и то что должно получиться (справа).
Для начала загрузим изображение:
Mat src = imread("1.jpg"); //Исходное изображение
По умолчанию в opencv цветное изображение хранится палитре BGR. Определять цвет в BGR не очень удобно, поэтому для начала переведем изображение в формат HSV.
HSV (или HSB) означает Hue, Saturation, Value (Brightness), где:
Hue — цветовой тон, т.е. оттенок цвета.
Saturation — насыщенность. Чем выше этот параметр, тем «чище» будет цвет, а чем ниже, тем ближе он будет к серому.
Value (Brightness) — значение (яркость) цвета. Чем выше значение, тем ярче будет цвет (но не белее). А чем ниже, тем темнее (0% — черный)

Так как искать растение мы будем именно по цвету, то больше всего нас интересует именно тон.
Преобразуем изображение в палитру HSV и разобьем на три составляющие Hue Saturation Value соответственно.
//Переводим в формат HSV
Mat hsv = Mat(src.cols, src.rows, 8, 3); //
vector<Mat> splitedHsv = vector<Mat>();
cvtColor(src, hsv, CV_BGR2HSV);
split(hsv, splitedHsv);
Зададим диапазон значений тона. В OpenCV зеленый находится в диапазоне от 34 до 72. Перец на фотографиях не полностью зеленый. Поэтому опытным путем был подобран диапазон от 21 до 110.
const int GREEN_MIN = 21;
const int GREEN_MAX = 110;
Далее пробежимся по нашему изображению. Для каждого пикселя получим все три компоненты. Интенсивность мы использовать не будем, но, чтобы было понятнее и не перескакивать индексы я ее оставлю. Если тон не укладывается в заданный диапазон или яркость слишком низкая – значит это фон, поэтому закрашиваем все белым цветом.
for (int y = 0; y < hsv.cols; y++) {
for (int x = 0; x < hsv.rows; x++) {
// получаем HSV-компоненты пикселя
int H = static_cast<int>(splitedHsv[0].at<uchar>(x, y)); // Тон
int S = static_cast<int>(splitedHsv[1].at<uchar>(x, y)); // Интенсивность
int V = static_cast<int>(splitedHsv[2].at<uchar>(x, y)); // Яркость
//Если яркость слишком низкая либо Тон не попадает у заданный диапазон, то закрашиваем белым
if ((V < 20) || (H < GREEN_MIN) || (H > GREEN_MAX)) {
src.at<Vec3b>(x, y)[0] = 255;
src.at<Vec3b>(x, y)[1] = 255;
src.at<Vec3b>(x, y)[2] = 255;
}
}
}
В результате у нас получится такое изображение:

В целом фон удалился, но остались непонятные шумы в левом углу.
Один из способов убрать мелкие несвязные частицы — это морфологическая обработка изображений.
Дилатация (морфологическое расширение) – свертка изображения или выделенной области изображения с некоторым ядром. Ядро может иметь произвольную форму и размер. При этом в ядре выделяется единственная ведущая позиция, которая совмещается с текущим пикселем при вычислении свертки. Во многих случаях в качестве ядра выбирается квадрат или круг с ведущей позицией в центре. Ядро можно рассматривать как шаблон или маску. Применение дилатации сводится к проходу шаблоном по всему изображению и применению оператора поиска локального максимума к интенсивностям пикселей изображения, которые накрываются шаблоном. Такая операция вызывает рост светлых областей на изображении. На рисунке серым цветом отмечены пиксели, которые в результате применения дилатации будут белыми.
Эрозия (морфологическое сужение) – обратная операция. Действие эрозии подобно дилатации, разница лишь в том, что используется оператор поиска локального минимума серым цветом залиты пиксели, которые станут черными в результате эрозии.
Подробнее про это дело можно почитать тут. Применим морфологические операции к нашим картинкам. В качестве структурного элемента возьмем эллипс.
int an = 5;
//Морфологическое замыкание для удаления остаточных шумов.
Mat element = getStructuringElement(MORPH_ELLIPSE, Size(an * 2 + 1, an * 2 + 1), Point(an, an));
dilate(src, tmp, element);
erode(tmp, tmp, element);

Результат морфологической обработки.
Большинство шумов убрались, но и само изображение размылось, а это не совсем то что мы хотели. Поэтому мы будем использовать преобразованное изображение как маску, чтобы удалить ненужный шум.
Mat grayscaleMat;
cvtColor(tmp, grayscaleMat, CV_BGR2GRAY);
//Делаем бинарную маску
Mat mask(grayscaleMat.size(), grayscaleMat.type());
Mat out(src.size(), src.type());
threshold(grayscaleMat, mask, 200, 255, THRESH_BINARY_INV);
//Финальное изображение предварительно красим в белый цвет
out = Scalar::all(255);
//Копируем зашумленное изображение через маску
src.copyTo(out, mask);

Слева маска, справа результат применения маски.
Вот таким способом можно примитивно выделить объект из фона.
→ Полный код примера
UPD: исправлена битая ссылка.