В обработке изображений часто возникает необходимость поворота изображения на произвольный угол. Эта задача может быть решена с использованием различных алгоритмов и библиотек. В данной статье мы рассмотрим, как реализовать поворот изображения на произвольный угол с использованием языка программирования 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");
}
Автор статьи:
Обновлено:
Добавить комментарий