Обработка изображений: цифровые фильтры

Цифровые фильтры для обработки изображений

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

Создание нового проекта

Начнем с создания нового проекта. Мы будем использовать пакетный менеджер DUB для управления зависимостями и сборки проекта.

dub init image-filter-gui qt
cd image-filter-gui

Добавление зависимостей и настройка окружения

Для работы с GUI и обработки изображений добавим необходимые зависимости в файл dub.json:

{
    "name": "image-filter-gui",
    "dependencies": {
        "dlib": "~>0.20.0",
        "qte5": "~>5.0.0"
    }
}

Создание формы

Теперь создадим форму с двумя элементами для отображения исходного и измененного изображения.

import dlib.image;
import qte5.qtcore;
import qte5.qtgui;
import qte5.qtwidgets;

class ImageFilterApp : QApplication {
    QPixmap originalImage;
    QPixmap filteredImage;
    QLabel originalLabel;
    QLabel filteredLabel;
    QPushButton applyButton;
    QPushButton openButton;

    this(int argc, char** argv) {
        super(argc, argv);

        auto mainWidget = new QWidget();
        auto layout = new QVBoxLayout();
        mainWidget.setLayout(layout);

        originalLabel = new QLabel();
        filteredLabel = new QLabel();
        openButton = new QPushButton("Open Image");
        applyButton = new QPushButton("Apply Filter");

        layout.addWidget(originalLabel);
        layout.addWidget(filteredLabel);
        layout.addWidget(openButton);
        layout.addWidget(applyButton);

        mainWidget.show();

        openButton.clicked.connect(&this.openImage);
        applyButton.clicked.connect(&this.applyFilter);
    }

    void openImage() {
        auto fileName = QFileDialog.getOpenFileName(null, "Open Image", "", "Images (*.png *.xpm *.jpg)");
        if (!fileName.isEmpty()) {
            originalImage = QPixmap(fileName);
            originalLabel.setPixmap(originalImage);
        }
    }

    void applyFilter() {
        // Logic for applying filter will be added here
    }
}

int main(string[] args) {
    auto app = new ImageFilterApp(args.length, args.ptr);
    return app.exec();
}

Выбор изображения

Для выбора изображения с помощью диалогового окна используем метод QFileDialog.getOpenFileName.

void openImage() {
    auto fileName = QFileDialog.getOpenFileName(null, "Open Image", "", "Images (*.png *.xpm *.jpg)");
    if (!fileName.isEmpty()) {
        originalImage = QPixmap(fileName);
        originalLabel.setPixmap(originalImage);
    }
}

Применение фильтра

Для обработки изображения с выбранным фильтром и отображения результата создадим функцию applyFilter.

void applyFilter() {
    // Logic for applying filter
    string filterFileName = QFileDialog.getOpenFileName(null, "Open Filter File", "", "Text Files (*.txt)");
    if (filterFileName.isEmpty()) return;

    string inputImagePath = originalImage.fileName();
    string outputImagePath = "filtered_image.png";

    runApplyFilters(inputImagePath, filterFileName, outputImagePath);

    filteredImage = QPixmap(outputImagePath);
    filteredLabel.setPixmap(filteredImage);
}

Действие кнопки «Apply»

Программа получает имя выбранного файла изображения и имя файла с описанием фильтра, затем генерирует имя для нового файла с преобразованным изображением.

void applyFilter() {
    string filterFileName = QFileDialog.getOpenFileName(null, "Open Filter File", "", "Text Files (*.txt)");
    if (filterFileName.isEmpty()) return;

    string inputImagePath = originalImage.fileName();
    string outputImagePath = "filtered_image.png";

    runApplyFilters(inputImagePath, filterFileName, outputImagePath);

    filteredImage = QPixmap(outputImagePath);
    filteredLabel.setPixmap(filteredImage);
}

Процесс обработки изображения

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

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

Пример кода для метода runApplyFilters

void runApplyFilters(string inputImagePath, string filterFileName, string outputImagePath) {
    auto originalImage = loadImage(inputImagePath);
    auto filter = loadFilter(filterFileName);

    auto filteredImage = applyConvolutionFilter(originalImage, filter);
    saveImage(outputImagePath, filteredImage);
}

Image loadImage(string path) {
    // Load image using dlib
    return readImage(path);
}

void saveImage(string path, Image img) {
    // Save image using dlib
    writeImage(path, img);
}

Описание класса для цифрового фильтра

Создадим класс для цифрового фильтра, включая конструктор и методы для получения параметров фильтра.

class Filter {
    float[][] kernel;
    int size;

    this(float[][] kernel) {
        this.kernel = kernel;
        this.size = kernel.length;
    }

    int getSize() {
        return size;
    }

    float[][] getKernel() {
        return kernel;
    }
}

Загрузка фильтра из текстового файла

Метод загрузки фильтра из текстового файла и формат текстового файла с описанием фильтра.

Filter loadFilter(string fileName) {
    auto lines = cast(string[]) readText(fileName).splitLines();
    auto size = lines.length;
    float[][] kernel = new float[][](size, size);

    foreach (i, line; lines) {
        auto values = line.strip().split(" ");
        foreach (j, value; values) {
            kernel[i][j] = to!float(value);
        }
    }

    return new Filter(kernel);
}

Пример текстового файла с описанием фильтра:

0 -1 0
-1 5 -1
0 -1 0

Свертка изображения с фильтром

Пример кода для метода свертки изображения с фильтром.

Image applyConvolutionFilter(Image img, Filter filter) {
    auto kernel = filter.getKernel();
    int size = filter.getSize();
    int offset = size / 2;

    Image result = img.dup;
    foreach (y; 0 .. img.height) {
        foreach (x; 0 .. img.width) {
            float newValue = 0;
            foreach (ky; 0 .. size) {
                foreach (kx; 0 .. size) {
                    int ix = x + kx - offset;
                    int iy = y + ky - offset;
                    if (ix >= 0 && iy >= 0 && ix < img.width && iy < img.height) {
                        newValue += img[iy, ix] * kernel[ky][kx];
                    }
                }
            }
            result[y, x] = clamp(newValue, 0, 255);
        }
    }
    return result;
}

Пример текстовых файлов с описанием различных фильтров

Пример текстового файла с описанием оператора Лапласа:

0 -1 0
-1 4 -1
0 -1 0

Пример текстового файла с описанием оператора Собеля:

-1 0 1
-2 0 2
-1 0 1

Таким образом, мы создали простой графический интерфейс на языке программирования D с использованием библиотек dlib и QtE5 для наложения фильтров на изображения. Этот проект демонстрирует, как можно сочетать мощные возможности обработки изображений dlib с гибким и удобным интерфейсом, предоставляемым QtE5.


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

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

Обновлено:

23.05.2024


Комментарии

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

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