音視頻入門-06-代碼畫圖時間

音視頻入門文章目錄

代碼畫圖

網上查資料的過程中,發現一些比較好的用代碼畫圖的例子。這裏記錄下來,供欣賞。如果對開發過程中有所幫助就更好了。

開始畫圖

畫彩虹條

rainbow.jpg

#include <stdio.h>
#include <stdlib.h>
#include "bmp/bmp.h"

// 彩虹的七種顏色
u_int32_t rainbowColors[] = {
        0XFF0000, // 紅
        0XFFA500, // 橙
        0XFFFF00, // 黃
        0X00FF00, // 綠
        0X007FFF, // 青
        0X0000FF, // 藍
        0X8B00FF  // 紫
};

void writeRGBToBmp(char *filename, int width, int height) {
    char bmp[BMP_SIZE(width, height)];
    bmp_init(bmp, width, height);

    for (int i = 0; i < width; ++i) {
        // 當前顏色
        u_int32_t currentColor = rainbowColors[0];
        if(i < 100) {
            currentColor = rainbowColors[0];
        } else if(i < 200) {
            currentColor = rainbowColors[1];
        } else if(i < 300) {
            currentColor = rainbowColors[2];
        } else if(i < 400) {
            currentColor = rainbowColors[3];
        } else if(i < 500) {
            currentColor = rainbowColors[4];
        } else if(i < 600) {
            currentColor = rainbowColors[5];
        } else if(i < 700) {
            currentColor = rainbowColors[6];
        }
        for (int j = 0; j < height; ++j) {
            bmp_set(bmp, j, i, currentColor);
        }
    }

    FILE *f = fopen(filename, "wb");
    fwrite(bmp, sizeof(bmp), 1, f);
    fclose(f);
}

int main() {
    writeRGBToBmp("/Users/staff/Desktop/draw-rainbow.bmp", 700, 700);
    return 0;
}

畫棋盤格

checkerboard.jpg

#include <stdio.h>
#include "bmp/bmp.h"

void writeRGBToBmp(char *filename, int width, int height) {
    char bmp[BMP_SIZE(width, height)];
    bmp_init(bmp, width, height);

    // Draw a checkerboard pattern:
    for (size_t y = 0; y < width; y++){
        for (size_t x = 0; x < height; x++) {
            if ((y % 128 < 64 && x % 128 < 64) ||
                (y % 128 >= 64 && x % 128 >= 64)) {
                bmp_set(bmp, x, y, bmp_encode(255, 255, 255));
            } else {
                bmp_set(bmp, x, y, bmp_encode(0, 0, 0));
            }
        }
    }

    FILE *f = fopen(filename, "wb");
    fwrite(bmp, sizeof(bmp), 1, f);
    fclose(f);
}

int main() {
    writeRGBToBmp("/Users/staff/Desktop/draw-checkerboard.bmp", 512, 512);
    return 0;
}

畫漸變圖

gradient.jpg

#include <stdio.h>
#include <stdlib.h>
#include "bmp/bmp.h"

void writeRGBToBmp(char *filename, int width, int height) {
    char bmp[BMP_SIZE(width, height)];
    bmp_init(bmp, width, height);

    for (int y = 0; y < height; y++) {
        for (int x = 0; x < width; x++) {
            float r = y / (float)height;
            float g = x / (float)width;
            float b = 1.0f;
            bmp_set(bmp, x, y, bmp_encode(r, g, b));
        }
    }

    FILE *f = fopen(filename, "wb");
    fwrite(bmp, sizeof(bmp), 1, f);
    fclose(f);
}

int main() {
    writeRGBToBmp("/Users/staff/Desktop/draw-gradient.bmp", 512, 512);
    return 0;
}

Mandelbrot Set 分形圖

mandelbrot-set.jpg

#include <stdio.h>
#include <math.h>
#include "common.h"
#include "bmp/bmp.h"

void writeRGBToBmp(char *filename, int width, int height) {
    char bmp[BMP_SIZE(width, height)];
    bmp_init(bmp, width, height);

    double    cr,    ci;
    double nextr, nexti;
    double prevr, previ;

    const unsigned int max_iterations = 1000;

    for (unsigned int y = 0; y < height; ++y)
    {
        for (unsigned int x = 0; x < width; ++x)
        {
            cr = 1.5 * (2.0 * x / width - 1.0) - 0.5;
            ci =       (2.0 * y / height - 1.0);

            nextr = nexti = 0;
            prevr = previ = 0;

            for (unsigned int i = 0; i < max_iterations; ++i)
            {
                prevr = nextr;
                previ = nexti;

                nextr =     prevr * prevr - previ * previ + cr;
                nexti = 2 * prevr * previ + ci;

                if (((nextr * nextr) + (nexti * nexti)) > 4) {

                    const double z = sqrt(nextr * nextr + nexti * nexti);

                    //https://en.wikipedia.org/wiki/Mandelbrot_set#Continuous_.28smooth.29_coloring
                    const unsigned int index = (1000.0 * log2(1.75 + i - log2(log2(z))) / log2(max_iterations));
                    
                    rgb_t color = jet_colormap[index];
                    bmp_set(bmp, x, y, bmp_encode(color.red, color.green, color.blue));
                    break;
                }
            }
        }
    }

    FILE *f = fopen(filename, "wb");
    fwrite(bmp, sizeof(bmp), 1, f);
    fclose(f);
}

int main() {
    writeRGBToBmp("/Users/staff/Desktop/draw-mandelbrot-set.bmp", 600, 400);
    return 0;
}

Julia Set 分形圖

julia-set.jpg

#include <stdio.h>
#include "bmp/bmp.h"
#include "common.h"

void writeRGBToBmp(char *filename, int width, int height) {
    char bmp[BMP_SIZE(width, height)];
    bmp_init(bmp, width, height);

    const unsigned int max_iterations = 300;

    const double cr = -0.70000;
    const double ci =  0.27015;

    double prevr, previ;

    for (unsigned int y = 0; y < height; ++y) {
        for (unsigned int x = 0; x < width; ++x) {
            double nextr = 1.5 * (2.0 * x / width - 1.0);
            double nexti =       (2.0 * y / height - 1.0);

            for (unsigned int i = 0; i < max_iterations; ++i) {
                prevr = nextr;
                previ = nexti;

                nextr =     prevr * prevr - previ * previ + cr;
                nexti = 2 * prevr * previ + ci;

                if (((nextr * nextr) + (nexti * nexti)) > 4) {
                    const unsigned int index = ((1000.0 * i) / max_iterations);
                    rgb_t color = hsv_colormap[index];
                    bmp_set(bmp, x, y, bmp_encode(color.red, color.green, color.blue));
                    break;
                }
            }
        }
    }

    FILE *f = fopen(filename, "wb");
    fwrite(bmp, sizeof(bmp), 1, f);
    fclose(f);
}

int main() {
    writeRGBToBmp("/Users/staff/Desktop/draw-julia-set.bmp", 600, 400);
    return 0;
}

放大鏡效果

magnifying-glass.jpg

#include <math.h>
#include "common.h"
#include "bmp/bmp.h"
#include <string.h>
#include <stdio.h>

void writeRGBToBmp(char *baseFilename, char *filename, int width, int height) {

    char base[BMP_SIZE(width, height)];
    bmp_init(base, width, height);

    {
        // Draw a checkerboard pattern:
        for (size_t y = 0; y < width; y++){
            for (size_t x = 0; x < height; x++) {
                if ((y % 128 < 64 && x % 128 < 64) ||
                    (y % 128 >= 64 && x % 128 >= 64)) {
                    bmp_set(base, x, y, bmp_encode(255, 255, 255));
                } else {
                    bmp_set(base, x, y, bmp_encode(0, 0, 0));
                }
            }
        }
    }

    char lens_image[BMP_SIZE(width, height)];
    bmp_init(lens_image, width, height);

    memcpy(lens_image, base, sizeof(base));

    const double lens_center_x = width / 2.0;
    const double lens_center_y = height / 2.0;
    const double lens_radius   = fmin(width, height) / 4.0;
    const double lens_factor   = 0.7;

    for (unsigned int y = 0; y < height; ++y) {
        for (unsigned int x = 0; x < width; ++x) {
            const double dx = x - lens_center_x;
            const double dy = y - lens_center_y;

            const double distance = sqrt((dx * dx) + (dy * dy));

            if (distance <= lens_radius) {
                const double radius     = distance / lens_radius;
                const double angle      = atan2(dy, dx);
                const double distortion = pow(radius, lens_factor) * distance;

                int sx = (distortion * cos(angle) + lens_center_x);
                int sy = (distortion * sin(angle) + lens_center_y);

                if (
                        (sx >= 0)                 &&
                        (sy >= 0)                 &&
                        (sx < (int)width) &&
                        (sy < (int)height)
                        ) {

                    bmp_set(lens_image, x, y, bmp_get(base, sx, sy));
                }
            }
        }
    }

    FILE *baseFile = fopen(baseFilename, "wb");
    FILE *file = fopen(filename, "wb");
    fwrite(base, sizeof(base), 1, baseFile);
    fwrite(lens_image, sizeof(lens_image), 1, file);
    fclose(baseFile);
    fclose(file);

}

int main() {
    writeRGBToBmp("/Users/staff/Desktop/draw-magnifying-glass-base.bmp", "/Users/staff/Desktop/draw-magnifying-glass.bmp", 600, 600);
    return 0;
}

旋渦效果

swirl-effect.jpg

#include <math.h>
#include "common.h"
#include "bmp/bmp.h"
#include <string.h>
#include <stdio.h>

void writeRGBToBmp(char *baseFilename, char *filename, int width, int height) {

    char base[BMP_SIZE(width, height)];
    bmp_init(base, width, height);

    {
        // Draw a checkerboard pattern:
        for (size_t y = 0; y < width; y++){
            for (size_t x = 0; x < height; x++) {
                if ((y % 128 < 64 && x % 128 < 64) ||
                    (y % 128 >= 64 && x % 128 >= 64)) {
                    bmp_set(base, x, y, bmp_encode(255, 255, 255));
                } else {
                    bmp_set(base, x, y, bmp_encode(0, 0, 0));
                }
            }
        }
    }

    char swirl_image[BMP_SIZE(width, height)];
    bmp_init(swirl_image, width, height);

    const double swirl_center_x = width / 2.0;
    const double swirl_center_y = height / 2.0;
    const double swirl_radius   = fmin(width, height) / 3.0;

    const double pi_ = 3.1415926535897932384626433832795028841971;
    const double swirl_angle = pi_ / 3.0;

    for (unsigned int y = 0; y < height; ++y)
    {
        for (unsigned int x = 0; x < width; ++x)
        {
            const double dx = x - swirl_center_x;
            const double dy = y - swirl_center_y;

            const double distance = sqrt((dx * dx) + (dy * dy));

            const double angle = swirl_angle * (distance / swirl_radius);

            const double cosa = cos(angle);
            const double sina = sin(angle);

            int sx = (dx * cosa - dy * sina + swirl_center_x);
            int sy = (dx * sina + dy * cosa + swirl_center_y);

            if (
                    (sx >= 0)                 &&
                    (sy >= 0)                 &&
                    (sx < (int)width) &&
                    (sy < (int)height)
                    ) {
                bmp_set(swirl_image, x, y, bmp_get(base, sx, sy));
            }
        }
    }

    FILE *baseFile = fopen(baseFilename, "wb");
    FILE *file = fopen(filename, "wb");
    fwrite(base, sizeof(base), 1, baseFile);
    fwrite(swirl_image, sizeof(swirl_image), 1, file);
    fclose(baseFile);
    fclose(file);

}

int main() {
    writeRGBToBmp("/Users/staff/Desktop/draw-swirl-effect-base.bmp", "/Users/staff/Desktop/draw-swirl-effect.bmp", 600, 600);
    return 0;
}

毛玻璃效果

frosted-glass-effect.jpg

#include <math.h>
#include "common.h"
#include "bmp/bmp.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

void writeRGBToBmp(char *baseFilename, char *filename, int width, int height) {
    
    const int kernel_size =  10;
    char base[BMP_SIZE(width, height)];
    bmp_init(base, width, height);

    {
        // Draw a checkerboard pattern:
        for (size_t y = 0; y < width; y++){
            for (size_t x = 0; x < height; x++) {
                if ((y % 128 < 64 && x % 128 < 64) ||
                    (y % 128 >= 64 && x % 128 >= 64)) {
                    bmp_set(base, x, y, bmp_encode(255, 255, 255));
                } else {
                    bmp_set(base, x, y, bmp_encode(0, 0, 0));
                }
            }
        }
    }

    char glass_image[BMP_SIZE(width, height)];
    bmp_init(glass_image, width, height);

    memcpy(glass_image, base, sizeof(base));

    for (int y = 0; y < height; ++y)
    {
        for (int x = 0; x < width; ++x)
        {
            const unsigned int min_x = fmax(0, x - kernel_size);
            const unsigned int min_y = fmax(0, y - kernel_size);
            const unsigned int max_x = fmin(x + kernel_size, width  - 1);
            const unsigned int max_y = fmin(y + kernel_size, height - 1);
            const unsigned int dx    = (max_x - min_x);
            const unsigned int dy    = (max_y - min_y);
            const unsigned int N     = rand() % (dx * dy);
            const unsigned int cx    = (N % dx) + min_x;
            const unsigned int cy    = (N / dx) + min_y;

            bmp_set(glass_image, x, y, bmp_get(base, cx, cy));
        }
    }


    FILE *baseFile = fopen(baseFilename, "wb");
    FILE *file = fopen(filename, "wb");
    fwrite(base, sizeof(base), 1, baseFile);
    fwrite(glass_image, sizeof(glass_image), 1, file);
    fclose(baseFile);
    fclose(file);

}

int main() {
    writeRGBToBmp("/Users/staff/Desktop/draw-frosted-glass-effect-base.bmp", "/Users/staff/Desktop/draw-frosted-glass-effect.bmp", 600, 600);
    return 0;
}

迷宮圖

maze.jpg

#include <cstdlib>
#include "bitmap/bitmap_image.hpp"

enum compass { N = 1, E = 2, S = 4, W = 8 };

const int untouched = (N | E | S | W);

struct move_t { int x, y, inverse; };

const move_t move[5] =
        {
                { 0, 0, 0 },
                // North        East         South         West
                { 0, -1, S }, { 1, 0, W }, { 0, 1, N },  { -1, 0, E }
        };

const int movemap[] = {0, 1, 2, 0, 3, 0, 0, 0, 4};

const compass permutations[] =
        {
                N,S,E,W, S,N,E,W, E,N,S,W, N,E,S,W, S,E,N,W, E,S,N,W, E,S,W,N, S,E,W,N,
                W,E,S,N, E,W,S,N, S,W,E,N, W,S,E,N, W,N,E,S, N,W,E,S, E,W,N,S, W,E,N,S,
                N,E,W,S, E,N,W,S, S,N,W,E, N,S,W,E, W,S,N,E, S,W,N,E, N,W,S,E, W,N,S,E
        };

void generate_maze(int cx, int cy, response_image<int>& maze)
{
    const unsigned int perm_index = 4 * ((rand() % 24));

    std::vector<compass>
            directions(&permutations[perm_index], &permutations[perm_index + 4]);

    for (std::size_t i = 0; i < directions.size(); ++i)
    {
        const move_t m = move[movemap[directions[i]]];

        const int x = cx + m.x;
        const int y = cy + m.y;

        if (
                (x < 0) || (y < 0)        ||
                (x >= (int)maze.width ()) ||
                (y >= (int)maze.height()) ||
                (untouched != maze(x,y))
                )
            continue;

        // Eliminate the wall corresponding to the selected direction.
        maze(cx,cy) = maze(cx,cy) & ~directions[i];
        maze( x, y) = maze( x, y) & ~m.inverse;

        generate_maze(x,y, maze);
    }
}

int main() {
    const std::size_t maze_width  = 80;
    const std::size_t maze_height = 70;

    response_image<int> maze(maze_width, maze_height);

    maze.set_all(untouched);

    generate_maze(rand() % maze_width, rand() % maze_height, maze);

    const std::size_t wall_size_x = 10; // 10 pixels
    const std::size_t wall_size_y =  8; //  8 pixels
    const std::size_t pen_size    =  2; //  2 pixels

    bitmap_image image(
            (maze_width ) * wall_size_x + (pen_size - 1),
            (maze_height) * wall_size_y + (pen_size - 1)
    );

    image.clear();

    {
        // Render background using Plasma effect
        const double c1 = 0.9;
        const double c2 = 0.5;
        const double c3 = 0.3;
        const double c4 = 0.7;

        ::srand(0xA5AA5AA5);

        plasma(image, 0, 0, image.width(), image.height(), c1, c2, c3, c4, 3.0, jet_colormap);
    }

    image_drawer draw(image);

    draw.pen_width(2);
    draw.pen_color(0, 0, 0);

    draw.rectangle(0, 0, image.width() - pen_size, image.height() - pen_size);

    // Draw the maze
    for (std::size_t y = 0; y < maze.height(); ++y)
    {
        for (std::size_t x = 0; x < maze.width(); ++x)
        {
            // Cell(x,y) coordinates
            const int x0 = x * wall_size_x;
            const int y0 = y * wall_size_y;
            const int x1 = x * wall_size_x + wall_size_x;
            const int y1 = y * wall_size_y + wall_size_y;

            const int cell = maze(x,y);

            // Is north wall present?
            if ((cell & N))
                draw.line_segment(x0, y0, x1, y0);

            // Is south wall present?
            if ((cell & S))
                draw.line_segment(x0, y1, x1, y1);

            // Is east wall present?
            if ((cell & E))
                draw.line_segment(x1, y0, x1, y1);

            // Is west wall present?
            if ((cell & W))
                draw.line_segment(x0, y0, x0, y1);
        }
    }
    image.save_image("/Users/staff/Desktop/draw-maze.bmp");
    return 0;
}

沿着利薩曲線的火球

fireballs.jpg

#include <cmath>
#include <iterator>
#include <vector>
#include "bitmap/bitmap_image.hpp"

struct lissajous_curve
{
    lissajous_curve(const double xs, const double ys)
            : scale_x(xs),
              scale_y(ys)
    {}

    inline double x(const double t) const { return scale_x * std::sin(4 * t); }
    inline double y(const double t) const { return scale_y * std::cos(3 * t); }

    double scale_x;
    double scale_y;
};

int main()
{
    bitmap_image image(700,500);

    image.clear();

    lissajous_curve curve(image.width () / 2.0 - 25, image.height() / 2.0 - 25);

    const double pi_   = 3.1415926535897932384626433832795028841971;
    const double delta = (2.0 * pi_) / 100000.0;

    const std::size_t max_fire_balls   = 30;
    const std::size_t number_of_frames = 3000;

    const double cooling_factor = 0.940; // [0,1]

    // Arc-length of curve: x(t) = a0 * sin(4t), y(t) = a1 * cos(3t)
    const double curve_length = 6151.0;

    double segment_length  = curve_length / max_fire_balls;
    double curr_seg_length = 0;

    double prev_x = curve.x(0);
    double prev_y = curve.y(0);

    std::vector<double> fire_ball;

    // Set the initial location for each fireball
    for (double t = delta;  fire_ball.size() < max_fire_balls; t += delta)
    {
        const double center_x = curve.x(t);
        const double center_y = curve.y(t);

        const double dx = (prev_x - center_x);
        const double dy = (prev_y - center_y);

        curr_seg_length += std::sqrt((dx * dx) + (dy * dy));

        prev_x = center_x;
        prev_y = center_y;

        if (curr_seg_length >= segment_length)
        {
            curr_seg_length = 0.0;
            fire_ball.push_back(t);
        }
    }

    response_image<double> resp_image(image.width(),image.height(), -1.0);
    response_image<double> fb_misses (image.width(),image.height(), -1.0);

    resp_image.set_all(-999.0);
    fb_misses .set_all(   0.0);

    std::vector<rgb_t> fire_palette;

    // Baseline colours used in fire palette
    rgb_t black  = make_colour(  0,   0,   0);
    rgb_t red    = make_colour(255,   0,   0);
    rgb_t yellow = make_colour(255, 255,   0);
    rgb_t white  = make_colour(255, 255, 255);

    // Setup the fire palette:
    // Black (Coolest - 0) --> Red --> Yellow --> White (Hottest - 999)
    generate_colours(334,  black,    red, std::back_inserter(fire_palette));
    generate_colours(333,    red, yellow, std::back_inserter(fire_palette));
    generate_colours(333, yellow,  white, std::back_inserter(fire_palette));

    for (std::size_t k = 0; k < number_of_frames; ++k)
    {
        fb_misses.inc_all(1);

        // Render fireballs on response image
        for (std::size_t i = 0; i < fire_ball.size(); ++i)
        {
            const double fb_x = curve.x(fire_ball[i]) + image.width () / 2.0;
            const double fb_y = curve.y(fire_ball[i]) + image.height() / 2.0;

            // Draw circles with radii in the range [1,10]
            for (double t = 0;  t < (2 * pi_); t += (((2.0 * pi_) / 360)))
            {
                for (double r = 1; r <= 10; ++r)
                {
                    std::size_t rx = static_cast<std::size_t>(r * std::sin(t) + fb_x);
                    std::size_t ry = static_cast<std::size_t>(r * std::cos(t) + fb_y);

                    // Per-frame in the range [0,100]
                    double heat_distortion = 50.0 * std::cos(delta * i) + 50;

                    resp_image(rx,ry) = fire_palette.size() * 0.8 +
                                        heat_distortion +
                                        (::rand() % 100);

                    fb_misses (rx,ry) = 0;
                }
            }

            // Move fireball to its next location
            fire_ball[i] += delta;
        }

        // Apply cooling process to the entire plane
        for (std::size_t y = 1; y < resp_image.height() - 1; ++y)
        {
            for (std::size_t x = 1; x < resp_image.width() - 1; ++x)
            {
                double avg = (
                                     resp_image(x - 1, y - 1) + resp_image(x    , y - 1) +
                                     resp_image(x + 1, y - 1) + resp_image(x - 1, y    ) +
                                     resp_image(x + 1, y    ) + resp_image(x    , y + 1) +
                                     resp_image(x - 1, y + 1) + resp_image(x + 1, y + 1)
                             ) / (7.0 + cooling_factor);

                // Only allow cooler averages to be applied
                if (avg > resp_image(x, y))
                    continue;

                // More rapidly cool points that haven't seen fireballs in the last N-frames
                if (fb_misses(x,y) > 2000)
                    avg *= 0.90 + ((::rand() % 10) / 100.0);

                // Clamp average in the range [0,999]
                resp_image(x,y) = ((avg < 0.0) ? 0.0 : ((avg > 999.0) ? 999.0 : avg));
            }
        }
    }

    convert_rsp_to_image(resp_image, fire_palette, image);

    image.save_image("/Users/staff/Desktop/draw-fireballs.bmp");

    return 0;
}

謝爾賓斯基三角形-蒙特卡羅方法

sierpinski-triangle.jpg

#include <cmath>
#include <cstdlib>
#include "bitmap/bitmap_image.hpp"

struct point_t { double x,y; };

int main()
{
    const int canvas_width  = 600;
    const int canvas_height = 400;

    cartesian_canvas canvas(canvas_width,canvas_height);

    {
        // Render background using Plasma effect
        const double c1 = 0.9;
        const double c2 = 0.3;
        const double c3 = 0.5;
        const double c4 = 0.7;

        ::srand(0xA5AA5AA5);

        plasma(canvas.image(), c1, c2, c3, c4, 3.5, jet_colormap);
    }

    point_t triangle[3];

    triangle[0].x = 0;
    triangle[0].y = +canvas_height / 2.0;
    triangle[1].x = -canvas_width  / 2.0;
    triangle[1].y = -canvas_height / 2.0;
    triangle[2].x = +canvas_width  / 2.0;
    triangle[2].y = -canvas_height / 2.0;

    point_t pnt = triangle[0];

    const std::size_t max_iterations = 1000000;

    for (std::size_t i = 0; i < max_iterations; ++i)
    {
        const point_t target_point = triangle[rand() % 3];

        pnt.x += (target_point.x - pnt.x) / 2.0;
        pnt.y += (target_point.y - pnt.y) / 2.0;

        canvas.plot_pen_pixel(pnt.x,pnt.y);
    }

    canvas.image().save_image("/Users/staff/Desktop/draw-sierpinski-triangle.bmp");

    return 0;
}

圓型和等邊三角形

circles_and_triangles.jpg

#include <cmath>
#include <cstdlib>
#include "bitmap/bitmap_image.hpp"

struct point_t { double x,y; };

int main()
{
    const int canvas_width  = 700;
    const int canvas_height = 460;

    cartesian_canvas canvas(canvas_width,canvas_height);

    canvas.image().clear(255);

    canvas.pen_width(1);

    ::srand(0xA5A5A5A5);

    for (std::size_t i = 0; i < 100; ++i)
    {
        double cx = ((rand() % canvas_width ) - canvas_width  / 2.0);
        double cy = ((rand() % canvas_height) - canvas_height / 2.0);
        double r  = (rand() % 70) + 10;

        const double pi_   = 3.1415926535897932384626433832795028841971;
        const double _120d = (2.0 * pi_/ 3.0);

        double rndang = ((2.0 * pi_) / 360.0) * ((rand() % 360) + 1.0);

        point_t p0, p1, p2;
        point_t p3, p4, p5;

        p0.x = r * std::sin(1.0 * _120d + rndang) + cx;
        p0.y = r * std::cos(1.0 * _120d + rndang) + cy;
        p1.x = r * std::sin(2.0 * _120d + rndang) + cx;
        p1.y = r * std::cos(2.0 * _120d + rndang) + cy;
        p2.x = r * std::sin(3.0 * _120d + rndang) + cx;
        p2.y = r * std::cos(3.0 * _120d + rndang) + cy;

#define rnd_colour (copper_colormap[rand() % 1000])

        // Draw and fill the circle
        canvas.pen_color(rnd_colour);
        canvas.fill_circle(cx, cy, r);
        canvas.pen_color(rnd_colour);
        canvas.circle(cx, cy, r);

        // Draw and fill the main equilateral triangles
        canvas.pen_color(rnd_colour);
        canvas.fill_triangle(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y);
        canvas.pen_color(rnd_colour);
        canvas.triangle(p0.x, p0.y, p1.x, p1.y, p2.x, p2.y);

        // Draw the inner-equilateral triangles
        for (unsigned int j = 0; j < 4; ++j)
        {
            p3.x = (p0.x + p1.x) / 2.0;
            p3.y = (p0.y + p1.y) / 2.0;
            p4.x = (p1.x + p2.x) / 2.0;
            p4.y = (p1.y + p2.y) / 2.0;
            p5.x = (p2.x + p0.x) / 2.0;
            p5.y = (p2.y + p0.y) / 2.0;

            p0 = p3; p1 = p4; p2 = p5;

            canvas.pen_color(rnd_colour);
            canvas.fill_triangle(p3.x, p3.y, p4.x, p4.y, p5.x, p5.y);
            canvas.pen_color(rnd_colour);
            canvas.triangle(p3.x, p3.y, p4.x, p4.y, p5.x, p5.y);
        }
    }

    canvas.image().save_image("/Users/staff/Desktop/draw-circles_and_triangles.bmp");

    return 0;
}

阿基米德螺旋

archimedean-spirals.jpg

#include <cmath>
#include <cstdlib>
#include "bitmap/bitmap_image.hpp"

struct point_t
{
    point_t(double _x = 0.0, double _y = 0.0) : x(_x), y(_y) {}
    double x,y;
};

int main()
{
    const double pi_ = 3.1415926535897932384626433832795028841971;
    const double a   = 20.0;
    const double b   = 20.0;
    const double dr  = (2.0 * pi_) / 1000.0;

    const std::size_t N = 5;
    const double delta_angle = (2.0 * pi_) / N;

    std::vector<point_t> spiral;

    for (std::size_t i = 0; i < N; ++i)
    {
        spiral.push_back(
                point_t(a * std::cos((delta_angle * i)),
                        a * std::sin((delta_angle * i))));
    }

    const int canvas_width  = 600;
    const int canvas_height = 600;

    cartesian_canvas canvas(canvas_width,canvas_height);

    canvas.image().clear(0);

    {
        // Render background using Plasma effect
        const double c1 = 0.9;
        const double c2 = 0.5;
        const double c3 = 0.3;
        const double c4 = 0.7;

        bitmap_image& image = canvas.image();

        ::srand(0xA5AA5AA5);

        plasma(image, 0, 0, image.width(), image.height(), c1, c2, c3, c4, 3.0, gray_colormap);
    }

    for (double angle = dr; (a + b * angle) < canvas.image().width() / 2.0; angle += dr)
    {
        for (std::size_t i = 0; i < spiral.size(); ++i)
        {
            const double theta = angle + delta_angle * i;
            const double d     = (a + b * angle);
            const point_t curr(d * std::cos(theta), d * std::sin(theta));

            const double centre_ratio =
                    (sqrt(curr.x * curr.x + curr.y * curr.y) / (canvas.image().width() / 2.0));

            if (centre_ratio <= 0.25) canvas.pen_width(1);
            else if (centre_ratio <= 0.50) canvas.pen_width(2);
            else if (centre_ratio <= 0.75) canvas.pen_width(3);
            else if (centre_ratio <= 1.00) canvas.pen_width(4);

            unsigned int index = (unsigned int)(1000.0 * centre_ratio);

            canvas.pen_color(hsv_colormap[index]);

            canvas.line_segment(spiral[i].x, spiral[i].y, curr.x, curr.y);

            spiral[i] = curr;
        }
    }

    canvas.image().save_image("/Users/staff/Desktop/draw-archimedean-spirals.bmp");

    return 0;
}

圖片拼圖

image-shuffled.jpg

#include <cmath>
#include <cstdlib>
#include <vector>
#include "bitmap/bitmap_image.hpp"

void shuffle(unsigned int n, std::vector<unsigned int>& v)
{
    ::srand(0x13A1515A);
    for (unsigned int i = 0; i < n; ++i) v.push_back(i);
    for (unsigned int i = v.size() - 1; i > 0; --i)
    { std::swap(v[i], v[rand() % (i + 1)]); }
}

int main()
{
    bitmap_image image("/Users/staff/Documents/Cpp/image-demo-rgb-pixel/06-drawing-time-cpp/tiger.bmp");

    const unsigned int divisions    = 3;
    const unsigned int block_width  = image.width () / divisions;
    const unsigned int block_height = image.height() / divisions;

    std::vector<unsigned int> cell;

    shuffle(divisions * divisions, cell);

    bitmap_image shuffled(image.width(), image.height());
    bitmap_image region;

    shuffled.clear();

    for (std::size_t i = 0; i < cell.size(); ++i)
    {
        unsigned int x_offset = block_width  * (i % divisions);
        unsigned int y_offset = block_height * (i / divisions);

        // Copy region from original image
        image.region(x_offset, y_offset,
                     block_width, block_height, region);

        x_offset = block_width  * (cell[i] % divisions);
        y_offset = block_height * (cell[i] / divisions);

        // Paste region to new location in shuffled image
        shuffled.copy_from(region, x_offset, y_offset);
    }

    shuffled.save_image("/Users/staff/Desktop/draw-image-shuffled.bmp");

    return 0;
}

葉序螺旋

phyllotaxis-spiral.jpg

#include <cmath>
#include <cstdlib>
#include "bitmap/bitmap_image.hpp"

int main()
{
    const int canvas_width  = 600;
    const int canvas_height = 600;

    const double pi       = 3.1415926535897932384626433832795028841971;
    const double phi      = pi * (3.0 - std::sqrt(5.0));
    const double radius   = (std::min(canvas_width, canvas_height) / 2.0) - 5.0;
    const double N        = 1200.0;
    const double spread   = radius / std::sqrt(N);
    const double p_radius = std::floor(spread / 2.0);

    cartesian_canvas canvas(canvas_width,canvas_height);

    {
        // Render background using Plasma effect
        const double c1 = 0.9;
        const double c2 = 0.5;
        const double c3 = 0.3;
        const double c4 = 0.7;

        bitmap_image& image = canvas.image();

        ::srand(0xA5AA5AA5);

        plasma(image, 0, 0, image.width(), image.height(), c1, c2, c3, c4, 3.0, copper_colormap);
    }

    for (double i = 0.0; i < N; ++i)
    {
        const double theta = phi * i;
        const double d     = spread * std::sqrt(i);
        const double x     = d * std::cos(theta);
        const double y     = d * std::sin(theta);

        canvas.pen_color(hsv_colormap[static_cast<std::size_t>(1000.0 * (i  / N))]);
        canvas.fill_circle(x, y, p_radius);
    }

    canvas.image().save_image("/Users/staff/Desktop/draw-phyllotaxis-spiral.bmp");

    return 0;
}

點狀效果

pointissist-effect.jpg

#include <cstdlib>
#include "bitmap/bitmap_image.hpp"

int main()
{
    bitmap_image base("/Users/staff/Documents/Cpp/image-demo-rgb-pixel/06-drawing-time-cpp/sunflower.bmp");

    cartesian_canvas canvas(base.width(),base.height());
    canvas.image() = base;

    const int pixel_count  = base.width() * base.height();
    const int N            = static_cast<int>(pixel_count * 0.03); // 3% of pixels
    const double rnd_ratio = pixel_count / (1.0 + RAND_MAX);

    ::srand(0xA57A57A5);

    for (int i = 0; i < N; ++i)
    {
        const int    r  = static_cast<int>(rand() * rnd_ratio);
        const int    x  = (r % base.width());
        const int    y  = (r / base.width());
        const double cx = x - (base.width() / 2.0);
        const double cy = (base.height() / 2.0) - y;
        const double radius = 1.0 + (r % 7);

        canvas.pen_color(base.get_pixel(x, y));
        canvas.fill_circle(cx, cy, radius);
    }

    canvas.image().save_image("/Users/staff/Desktop/draw-pointillist-effect.bmp");

    return 0;
}

代碼:

06-drawing-time & 06-drawing-time-cpp

參考資料:

Simple Bitmap Library Usage Examples

內容有誤?聯繫作者:

聯繫作者


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章