Бинаризация изображений методом Оцу на D с dlib

Бинаризация изображений методом Оцу на D с dlib

Бинаризация изображений — это процесс преобразования изображения в два цвета, обычно черный и белый. Этот метод часто используется в области обработки изображений и компьютерного зрения для упрощения анализа и обработки изображений, таких как выделение объектов, распознавание текста и улучшение контрастности. Одним из самых популярных методов автоматической бинаризации является метод Оцу, который автоматически определяет оптимальный порог для разделения пикселей на два класса.

Метод Оцу

Метод Оцу, предложенный Нобуюки Оцу в 1979 году, представляет собой алгоритм, который автоматически находит оптимальный порог бинаризации, минимизируя внутриклассовую дисперсию. Идея метода заключается в том, чтобы максимизировать межклассовую дисперсию, что эквивалентно минимизации внутриклассовой дисперсии. Этот метод предполагает, что изображение состоит из двух классов пикселей (например, фон и объект) и находит порог, который лучше всего разделяет эти два класса.

Принципы работы метода Оцу

  1. Построение гистограммы яркостей изображения.
  2. Вычисление вероятностей и средних значений для каждого возможного порога.
  3. Вычисление внутриклассовой дисперсии для каждого порога.
  4. Определение порога, при котором внутриклассовая дисперсия минимальна.

Пошаговое руководство по созданию проекта на 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);
    }

    Рекомендации по использованию метода Оцу

    1. Метод Оцу хорошо работает, когда изображение имеет четкое разделение между фоном и объектом.
    2. В случаях с большим количеством шумов или неоднородным фоном, предварительная обработка изображения может улучшить результаты.

    Карпов Ярослав

    Автор статьи:

    Обновлено:

    30.05.2024


    Комментарии

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

    Ваш адрес email не будет опубликован. Обязательные поля помечены *