Бинаризация изображений — это процесс преобразования изображения в два цвета, обычно черный и белый. Этот метод часто используется в области обработки изображений и компьютерного зрения для упрощения анализа и обработки изображений, таких как выделение объектов, распознавание текста и улучшение контрастности. Одним из самых популярных методов автоматической бинаризации является метод Оцу, который автоматически определяет оптимальный порог для разделения пикселей на два класса.
Метод Оцу
Метод Оцу, предложенный Нобуюки Оцу в 1979 году, представляет собой алгоритм, который автоматически находит оптимальный порог бинаризации, минимизируя внутриклассовую дисперсию. Идея метода заключается в том, чтобы максимизировать межклассовую дисперсию, что эквивалентно минимизации внутриклассовой дисперсии. Этот метод предполагает, что изображение состоит из двух классов пикселей (например, фон и объект) и находит порог, который лучше всего разделяет эти два класса.
Принципы работы метода Оцу
- Построение гистограммы яркостей изображения.
- Вычисление вероятностей и средних значений для каждого возможного порога.
- Вычисление внутриклассовой дисперсии для каждого порога.
- Определение порога, при котором внутриклассовая дисперсия минимальна.
Пошаговое руководство по созданию проекта на D с использованием dlib
Шаг 1: Создание нового проекта
Создайте новый проект D и добавьте библиотеку dlib:
dub init ootsu_binarization
cd ootsu_binarization
dub add dlib
Шаг 2: Импорт необходимых модулей
Добавьте необходимые модули в файл source/app.d
:
import std.stdio;
import std.file;
import std.conv;
import dlib.image;
import dlib.image.io;
import dlib.algorithm;
Шаг 3: Создание гистограммы изображения
Для создания гистограммы изображения используте следующий код:
uint[] createHistogram(Image image) {
uint[] histogram = new uint[256];
foreach (pixel; image) {
histogram[pixel] += 1;
}
return histogram;
}
Шаг 4: Вычисление порога бинаризации методом Оцу
Для вычисления порога бинаризации методом Оцу использйуте следующий код:
uint otsuThreshold(uint[] histogram, size_t totalPixels) {
uint sum = 0;
for (uint t = 0; t < 256; ++t) {
sum += t * histogram[t];
}
uint sumB = 0;
uint wB = 0;
uint wF = 0;
double maxVariance = 0.0;
uint threshold = 0;
for (uint t = 0; t < 256; ++t) {
wB += histogram[t];
if (wB == 0) continue;
wF = totalPixels - wB;
if (wF == 0) break;
sumB += t * histogram[t];
double mB = double(sumB) / wB;
double mF = double(sum - sumB) / wF;
double varianceBetween = double(wB) * double(wF) * (mB - mF) * (mB - mF);
if (varianceBetween > maxVariance) {
maxVariance = varianceBetween;
threshold = t;
}
}
return threshold;
}
Шаг 5: Применение бинаризации к изображению
Для применения бинаризации к изображению используйте следующий код:
Image binarizeImage(Image image, uint threshold) {
Image binaryImage = image.dup;
foreach (ref pixel; binaryImage) {
pixel = pixel > threshold ? 255 : 0;
}
return binaryImage;
}
Полный пример кода
Вот полный пример кода, объединяющий все шаги:
import std.stdio;
import std.file;
import std.conv;
import dlib.image;
import dlib.image.io;
import dlib.algorithm;
uint[] createHistogram(Image image) {
uint[] histogram = new uint[256];
foreach (pixel; image) {
histogram[pixel] += 1;
}
return histogram;
}
uint otsuThreshold(uint[] histogram, size_t totalPixels) {
uint sum = 0;
for (uint t = 0; t < 256; ++t) {
sum += t * histogram[t];
}
uint sumB = 0;
uint wB = 0;
uint wF = 0;
double maxVariance = 0.0;
uint threshold = 0;
for (uint t = 0; t < 256; ++t) {
wB += histogram[t];
if (wB == 0) continue;
wF = totalPixels - wB;
if (wF == 0) break;
sumB += t * histogram[t];
double mB = double(sumB) / wB;
double mF = double(sum - sumB) / wF;
double varianceBetween = double(wB) * double(wF) * (mB - mF) * (mB - mF);
if (varianceBetween > maxVariance) {
maxVariance = varianceBetween;
threshold = t;
}
}
return threshold;
}
Image binarizeImage(Image image, uint threshold) {
Image binaryImage = image.dup;
foreach (ref pixel; binaryImage) {
pixel = pixel > threshold ? 255 : 0;
}
return binaryImage;
}
void main(string[] args) {
if (args.length < 3) {
writeln("Usage: <input_image> <output_image>");
return;
}
auto inputImage = args[1];
auto outputImage = args[2];
auto image = readImage(inputImage);
auto histogram = createHistogram(image);
auto threshold = otsuThreshold(histogram, image.length);
auto binaryImage = binarizeImage(image, threshold);
writeImage(outputImage, binaryImage);
}
Рекомендации по использованию метода Оцу
- Метод Оцу хорошо работает, когда изображение имеет четкое разделение между фоном и объектом.
- В случаях с большим количеством шумов или неоднородным фоном, предварительная обработка изображения может улучшить результаты.
Автор статьи:
Обновлено:
Добавить комментарий