Создание векторной графики с использованием библиотеки dlib

Создание векторной графики с использованием библиотеки dlib

Библиотека dlib на языке программирования D предоставляет мощные инструменты для работы с графикой, включая возможности для рисования различных примитивов, работы с изображениями и применения алгоритмов машинного обучения. В контексте создания векторной графики dlib позволяет рисовать линии, многоугольники, кривые и другие фигуры с помощью простого и понятного API.

Пример кода для рендеринга произвольного многоугольника

Для рендеринга произвольного многоугольника используется алгоритм, основанный на правиле четности-нечетности (even-odd rule). Этот алгоритм определяет, находится ли точка внутри многоугольника, проверяя, сколько раз горизонтальная линия от этой точки пересекает стороны многоугольника.

Пример кода

import dlib;

void main() {
    // Создание изображения
    auto img = new Image!(IntegerPixelFormat.RGB8)(800, 600);

    // Определение вершин многоугольника
     Vector2f[] vertices = [Vector2f(200.0f, 300.0f), 
     Vector2f(400.0f, 100.0f), Vector2f(600.0f, 300.0f), 
     Vector2f(500.0f, 500.0f), Vector2f(300.0f, 500.0f)];    

    bool vhodit;
    foreach (y; 0 .. img.height) {
        foreach (x; 0 .. img.width) {        
            vhodit = false;
            ulong j = vertices.length - 1;
            Vector2f point = Vector2f(x, y);
            for (int i = 0; i < vertices.length; i++) {
                if ( (vertices[i].y < point.y && vertices[j].y >= point.y || vertices[j].y < point.y && vertices[i].y >= point.y) &&
                    (vertices[i].x + (point.y - vertices[i].y) / (vertices[j].y - vertices[i].y) * (vertices[j].x - vertices[i].x) < point.x) )
                    vhodit = !vhodit;
                j = i;
            }
            if (vhodit) {
                img[x, y] = Color4f(255.0f, 0.0f, 0.0f, 255.0f); // RGBA format: red, green, blue, alpha
            }        
        }
    }



    // Сохранение изображения
    savePNG(img, "polygon.png");
}

В этом примере создается изображение размером 800×600 пикселей, определяются вершины многоугольника, и он рисуется на изображении. Результат сохраняется в файл polygon.png.

Произвольный многоугольник

Метод сглаживания: суперсэмплинг

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

Пример реализации кода

import dlib;

void main() {
    // Создание изображения
    auto img = new Image!(IntegerPixelFormat.RGB8)(3200, 2400);

    // Определение вершин многоугольника
     Vector2f[] vertices = [Vector2f(800.0f, 1200.0f), 
     Vector2f(1600.0f, 400.0f), Vector2f(2400.0f, 1200.0f), 
     Vector2f(2000.0f, 2000.0f), Vector2f(1200.0f, 2000.0f)];

    // Рисование многоугольника
    //img.drawPolygon(vertices, Color(0, 0, 0), true);

    bool vhodit;

    foreach (y; 0 .. img.height) {
        foreach (x; 0 .. img.width) {        
            vhodit = false;
            ulong j = vertices.length - 1;
            Vector2f point = Vector2f(x, y);
            for (int i = 0; i < vertices.length; i++) {
                if ( (vertices[i].y < point.y && vertices[j].y >= point.y || vertices[j].y < point.y && vertices[i].y >= point.y) &&
                    (vertices[i].x + (point.y - vertices[i].y) / (vertices[j].y - vertices[i].y) * (vertices[j].x - vertices[i].x) < point.x) )
                    vhodit = !vhodit;
                j = i;
            }
            if (vhodit) {
                img[x, y] = Color4f(255.0f, 0.0f, 0.0f, 255.0f); // RGBA format: red, green, blue, alpha
            }        
        }
    }


    auto resizedImg = resampleBicubic(img, 800, 600);

    // Сохранение изображения
    savePNG(resizedImg, "polygon_anti_aliased.png");
}

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

Произвольный многоугольник со сглаживанием

Рисование фигур на основе кривых Безье

Кривые Безье часто используются в компьютерной графике для создания гладких и плавных кривых. Для аппроксимации кривой Безье можно использовать последовательность коротких отрезков линии.

Пример кода для рисования кривой Безье

import dlib;
import std.math;
import std.conv:to;

void drawBezier(Image!(IntegerPixelFormat.RGB8) image, 
Vector2f p0, Vector2f p1, Vector2f p2, Vector2f p3, Color4f color) {
    int xr;
    int yr;
    for (double t = 0; t <= 1; t += 0.001) {
        double x = pow(1-t, 3) * p0.x + 3 * t * pow(1-t, 2) * p1.x + 3 * pow(t, 2) * (1-t) * p2.x + pow(t, 3) * p3.x;
        double y = pow(1-t, 3) * p0.y + 3 * t * pow(1-t, 2) * p1.y + 3 * pow(t, 2) * (1-t) * p2.y + pow(t, 3) * p3.y;
        xr = to!int(floor(x));
        yr = to!int(floor(y));
        image[xr, yr] = color;
    }
}


void main() {
    // Создание изображения
    auto img = new Image!(IntegerPixelFormat.RGB8)(800, 600);

    // Определение контрольных точек кривой Безье
    Vector2f p0 = Vector2f(100.0f, 500.0f);
    Vector2f p1 = Vector2f(200.0f, 100.0f);
    Vector2f p2 = Vector2f(600.0f, 100.0f);
    Vector2f p3 = Vector2f(700.0f, 500.0f);

    // Рисование кривой Безье
    drawBezier(img, p0, p1, p2, p3, Color4f(255.0f, 0.0f, 0.0f, 255.0f));

    // Сохранение изображения
    savePNG(img, "bezier_curve.png");
}

В этом примере функция drawBezier используется для рисования кривой Безье на изображении путем итерации параметра t от 0 до 1 и вычисления координат точки на кривой.

Рисование кривой Безье

Использование аффинных преобразований для трансформации фигур

Аффинные преобразования включают операции трансляции, масштабирования, вращения и отражения. Они полезны для изменения формы и положения фигур на плоскости.

Пример кода для поворота фигуры

import dlib;
import std.math;
import std.conv:to;
import std.algorithm;
import std.array;

Vector2f rotatePoint(Vector2f p, Vector2f center, double angle) {
    double s = sin(angle);
    double c = cos(angle);

    // Перенос точки в начало координат
    p.x -= center.x;
    p.y -= center.y;

    // Вращение точки
    double xnew = p.x * c - p.y * s;
    double ynew = p.x * s + p.y * c;

    // Перенос точки обратно
    p.x = xnew + center.x;
    p.y = ynew + center.y;

    return p;
}


void main() {
    // Создание изображения
    auto img = new Image!(IntegerPixelFormat.RGB8)(800, 600);

    // Определение вершин многоугольника
    Vector2f[] vertices = [Vector2f(200.0f, 300.0f), Vector2f(400.0f, 100.0f), 
    Vector2f(600.0f, 300.0f), Vector2f(500.0f, 500.0f), Vector2f(300.0f, 500.0f)];

    // Определение центра вращения и угла
    Vector2f center = Vector2f(200.0f, 150.0f);
    double angle = PI / 4; // 45 градусов

    // Вращение вершин многоугольника
    Vector2f[] rotatedVertices = vertices.map!(p => rotatePoint(p, center, angle)).array;


    // Рисование исходного многоугольника
    bool vhodit;
    foreach (y; 0 .. img.height) {
        foreach (x; 0 .. img.width) {        
            vhodit = false;
            ulong j = vertices.length - 1;
            Vector2f point = Vector2f(x, y);
            for (int i = 0; i < vertices.length; i++) {
                if ( (vertices[i].y < point.y && vertices[j].y >= point.y || vertices[j].y < point.y && vertices[i].y >= point.y) &&
                    (vertices[i].x + (point.y - vertices[i].y) / (vertices[j].y - vertices[i].y) * (vertices[j].x - vertices[i].x) < point.x) )
                    vhodit = !vhodit;
                j = i;
            }
            if (vhodit) {
                img[x, y] = Color4f(0.0f, 0.0f, 255.0f, 255.0f); // RGBA format: red, green, blue, alpha
            }        
        }
    }

    // Рисование исходного и повернутого многоугольников
    foreach (y; 0 .. img.height) {
        foreach (x; 0 .. img.width) {        
            vhodit = false;
            ulong j = rotatedVertices.length - 1;
            Vector2f point = Vector2f(x, y);
            for (int i = 0; i < rotatedVertices.length; i++) {
                if ( (rotatedVertices[i].y < point.y && rotatedVertices[j].y >= point.y || rotatedVertices[j].y < point.y && rotatedVertices[i].y >= point.y) &&
                    (rotatedVertices[i].x + (point.y - rotatedVertices[i].y) / (rotatedVertices[j].y - rotatedVertices[i].y) * (rotatedVertices[j].x - rotatedVertices[i].x) < point.x) )
                    vhodit = !vhodit;
                j = i;
            }
            if (vhodit) {
                img[x, y] = Color4f(255.0f, 0.0f, 0.0f, 255.0f); // RGBA format: red, green, blue, alpha
            }        
        }
    }

    // Сохранение изображения
    savePNG(img, "rotated_polygon.png");
}

В этом примере функция rotatePoint используется для поворота точки вокруг заданного центра на определенный угол. Многоугольник рисуется дважды: в исходном положении и после поворота.

Аффинные преобразования для трансформации фигур

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

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

Обновлено:

07.06.2024


Комментарии

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

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