Поворот изображения на произвольный угол с D и Farbfelded

Поворот изображения на произвольный угол с D и Farbfelded

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

Теоретические основы

Преобразование координат

Поворот изображения на угол θ осуществляется с использованием матрицы поворота. Для точки с координатами (x, y) новые коордианты (x’, y’) после поворота вычисляются по следующим формулам:

x′ = x⋅cos(θ) − y⋅sin(θ)

y′ = x⋅cos⁡(θ) + y⋅sin⁡(θ)

Билинейная интерполяция

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

f(x,y) ≈ (1−dx) ⋅ (1−dy) ⋅ f(x1,y1) + dx ⋅ (1−dy) ⋅ f(x2,y1) + (1−dx) ⋅ dy ⋅ f(x1,y2) + dx ⋅ dy ⋅ f(x2,y2)

где dx и dy — дробные части координат, а f(x1,y1), f(x2,y1), f(x1,y2), f(x2,y2) — значения цветов ближайших пикселей.

Практическая реализация

Подготовка среды

Для работы с D и библиотекой Farbfelded необходимо установить компилятор D и саму библиотеку. Установку можно выполнить через DUB — менеджер пакетов для D.

dub init rotate_image_dlang
cd rotate_image_dlang
dub add farbfelded

Код функции поворота

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

import std.math;
import std.stdio;
import std.conv;
import farbfelded;

Image rotateImage(const Image source, float angle) {
    float radians = angle * PI / 180.0;
    int width = source.width;
    int height = source.height;
    Image result = Image(width, height);

    float centerX = width / 2.0;
    float centerY = height / 2.0;

    foreach (y; 0 .. height) {
        foreach (x; 0 .. width) {
            float relativeX = x - centerX;
            float relativeY = y - centerY;

            float originalX = relativeX * cos(radians) + relativeY * sin(radians) + centerX;
            float originalY = -relativeX * sin(radians) + relativeY * cos(radians) + centerY;

            if (originalX >= 0 && originalX < width && originalY >= 0 && originalY < height) {
                int x1 = cast(int)originalX;
                int y1 = cast(int)originalY;
                int x2 = min(x1 + 1, width - 1);
                int y2 = min(y1 + 1, height - 1);

                float dx = originalX - x1;
                float dy = originalY - y1;

                auto c1 = source.getPixel(x1, y1);
                auto c2 = source.getPixel(x2, y1);
                auto c3 = source.getPixel(x1, y2);
                auto c4 = source.getPixel(x2, y2);

                result.setPixel(x, y, interpolate(c1, c2, c3, c4, dx, dy));
            } else {
                result.setPixel(x, y, Color(0, 0, 0, 255));
            }
        }
    }

    return result;
}

Color interpolate(Color c1, Color c2, Color c3, Color c4, float dx, float dy) {
    ubyte r = cast(ubyte)((1 - dx) * (1 - dy) * c1.r + dx * (1 - dy) * c2.r + (1 - dx) * dy * c3.r + dx * dy * c4.r);
    ubyte g = cast(ubyte)((1 - dx) * (1 - dy) * c1.g + dx * (1 - dy) * c2.g + (1 - dx) * dy * c3.g + dx * dy * c4.g);
    ubyte b = cast(ubyte)((1 - dx) * (1 - dy) * c1.b + dx * (1 - dy) * c2.b + (1 - dx) * dy * c3.b + dx * dy * c4.b);
    ubyte a = cast(ubyte)((1 - dx) * (1 - dy) * c1.a + dx * (1 - dy) * c2.a + (1 - dx) * dy * c3.a + dx * dy * c4.a);
    return Color(r, g, b, a);
}

Пример использования

Входное изображение

Для иллюстрации используем изображение input.png.

Поворот изображения

import std.file;

void main() {
    auto source = Image.fromFile("input.png");
    auto rotated = rotateImage(source, 45.0);
    rotated.save("output.png");
}

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

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

Обновлено:

31.05.2024


Комментарии

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

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