Привет, дорогой читатель! Если ты интересуешься обработкой изображений и программированием, то эта статья для тебя. Сегодня мы поговорим о таком важном инструменте, как эквализация гистограмм. И сделаем это на языке программирования 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 для выполнения задач обработки изображений. Не бойся экспериментировать и улучшать этот код. Возможно, ты захочешь добавить поддержку других форматов изображений или оптимизировать некоторые части алгоритма.
Надеюсь, тебе было интересно и полезно. Удачи в твоих проектах по обработке изображений!
Автор статьи:
Обновлено:
Добавить комментарий