Эквализация гистограмм

Обработкой изображений: реализация эквализации гистограмм

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

Что такое эквализация гистограмм?

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

Пример на пальцах

Допустим, у тебя есть фотография, на которой очень плохо видны детали из-за недостаточного освещения. После применения эквализации гистограмм все мелкие детали станут более различимыми. Это как если бы ты взял резинку и аккуратно растянул все оттенки серого на картинке, делая их более равномерно распределенными.

Эквализация гистограмм на практике

Давай перейдем к практике и напишем программу на языке D, которая будет выполнять эквализацию гистограмм. Для этого нам понадобятся некоторые базовые библиотеки и знания о том, как работать с изображениями.

Подключение необходимых библиотек

Для работы с изображениями в D существует несколько библиотек, но одной из самых популярных является arsd.simpledisplay. Установим ее с помощью менеджера пакетов dub. Для этого в файле dub.json добавим следующую зависимость:

"dependencies": {
    "arsd-official": "~>10.5.2"
}

Чтение изображения

Первым шагом будет чтение изображения. Мы будем использовать формат PNG для простоты. Создадим функцию, которая будет загружать изображение и преобразовывать его в массив пикселей.

import arsd.png;

ubyte[][] loadImage(string filename) {
    auto image = PngImage(filename);
    return image.toLuminance(); // Преобразуем изображение в градации серого
}

Построение гистограммы

Теперь, когда у нас есть массив пикселей, давай построим гистограмму. Это позволит нам понять распределение интенсивностей в изображении.

uint[] buildHistogram(ubyte[][] pixels) {
    uint[256] histogram = 0; // Инициализируем массив из 256 элементов

    foreach (row; pixels) {
        foreach (pixel; row) {
            histogram[pixel]++;
        }
    }

    return histogram;
}

Вычисление функции распределения

Следующим шагом будет вычисление кумулятивной функции распределения (CDF), которая нам понадобится для перераспределения интенсивностей.

uint[] buildCDF(uint[] histogram) {
    uint[] cdf = new uint[256];
    uint cumulative = 0;

    foreach (i, count; histogram) {
        cumulative += count;
        cdf[i] = cumulative;
    }

    return cdf;
}

Применение эквализации

Теперь, когда у нас есть CDF, мы можем применить эквализацию к изображению.

ubyte[][] applyEqualization(ubyte[][] pixels, uint[] cdf) {
    uint totalPixels = pixels.length * pixels[0].length;
    ubyte[] equalized = new ubyte[256];

    foreach (i, value; cdf) {
        equalized[i] = cast(ubyte)(255.0 * value / totalPixels);
    }

    ubyte[][] result = new ubyte[][](pixels.length);
    foreach (i, row; pixels) {
        result[i] = new ubyte[](row.length);
        foreach (j, pixel; row) {
            result[i][j] = equalized[pixel];
        }
    }

    return result;
}

Сохранение изображения

Последним шагом будет сохранение эквализованного изображения.

void saveImage(string filename, ubyte[][] pixels) {
    auto image = PngImage(pixels[0].length, pixels.length);

    foreach (y, row; pixels) {
        foreach (x, value; row) {
            image.setPixel(x, y, PngImage.Pixel(value, value, value)); // Устанавливаем пиксели в градациях серого
        }
    }

    image.save(filename);
}

Полный пример

Теперь, когда у нас есть все части, давай соберем их вместе в полноценную программу.

import arsd.png;

void main(string[] args) {
    if (args.length < 3) {
        writeln("Usage: histogram_equalization <input.png> <output.png>");
        return;
    }

    string inputFile = args[1];
    string outputFile = args[2];

    auto pixels = loadImage(inputFile);
    auto histogram = buildHistogram(pixels);
    auto cdf = buildCDF(histogram);
    auto equalizedPixels = applyEqualization(pixels, cdf);
    saveImage(outputFile, equalizedPixels);

    writeln("Histogram equalization completed!");
}

ubyte[][] loadImage(string filename) {
    auto image = PngImage(filename);
    return image.toLuminance();
}

uint[] buildHistogram(ubyte[][] pixels) {
    uint[256] histogram = 0;

    foreach (row; pixels) {
        foreach (pixel; row) {
            histogram[pixel]++;
        }
    }

    return histogram;
}

uint[] buildCDF(uint[] histogram) {
    uint[] cdf = new uint[256];
    uint cumulative = 0;

    foreach (i, count; histogram) {
        cumulative += count;
        cdf[i] = cumulative;
    }

    return cdf;
}

ubyte[][] applyEqualization(ubyte[][] pixels, uint[] cdf) {
    uint totalPixels = pixels.length * pixels[0].length;
    ubyte[] equalized = new ubyte[256];

    foreach (i, value; cdf) {
        equalized[i] = cast(ubyte)(255.0 * value / totalPixels);
    }

    ubyte[][] result = new ubyte[][](pixels.length);
    foreach (i, row; pixels) {
        result[i] = new ubyte[](row.length);
        foreach (j, pixel; row) {
            result[i][j] = equalized[pixel];
        }
    }

    return result;
}

void saveImage(string filename, ubyte[][] pixels) {
    auto image = PngImage(pixels[0].length, pixels.length);

    foreach (y, row; pixels) {
        foreach (x, value; row) {
            image.setPixel(x, y, PngImage.Pixel(value, value, value));
        }
    }

    image.save(filename);
}

Мы написали программу для эквализации гистограмм на языке программирования D. Этот процесс включал в себя чтение изображения, построение гистограммы, вычисление кумулятивной функции распределения и применение эквализации.

Теперь ты знаешь, как улучшить контрастность изображений и как использовать язык D для выполнения задач обработки изображений. Не бойся экспериментировать и улучшать этот код. Возможно, ты захочешь добавить поддержку других форматов изображений или оптимизировать некоторые части алгоритма.

Надеюсь, тебе было интересно и полезно. Удачи в твоих проектах по обработке изображений!


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

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

Обновлено:

23.05.2024


Комментарии

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

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