IE盒子

搜索
查看: 141|回复: 1

11.8 字符画的自动生成 《C语言程序设计:一个小球的编程之 ...

[复制链接]

1

主题

4

帖子

3

积分

新手上路

Rank: 1

积分
3
发表于 2022-12-2 12:50:05 | 显示全部楼层 |阅读模式
这次课,我们实现一些漂亮的字符画:


1 图片的读取与显示

首先,可以找一些免费的图片,比如:
https://www.hippopx.com/zh/child-portrait-girl-model-young-beautiful-female-12439


利用EasyX,可以比较容易读取图片数据,在程序中显示图片:


#include <graphics.h>
#include <conio.h>

int main()
{
        IMAGE im; // 图像变量
        loadimage(&im, _T("pic1.jpg")); // 导入图像文件
        int width, height; //  图片的宽度、高度,也是屏幕的宽度、高度
        width = im.getwidth(); // 获得图像的宽度
        height = im.getheight(); // 获得图像的高度       
        initgraph(width, height); // 新开一个画面
        putimage(0, 0, &im);  //  显示图片
        _getch();
        return 0;
}
2 均匀采样的小球画

对图片的行、列进行均匀采样,在对应采样点,以图片的颜色,画一个小球:


#include <graphics.h>
#include <conio.h>

int main()
{
        IMAGE im; // 图像变量
        loadimage(&im, _T("pic1.jpg")); // 导入图像文件
        int width, height; //  图片的宽度、高度,也是屏幕的宽度、高度
        width = im.getwidth(); // 获得图像的宽度
        height = im.getheight(); // 获得图像的高度       
        DWORD* pMem = GetImageBuffer(&im); // 获得图像内容缓存

        int interval = 10;  // 图像行、列的采样间隔

        initgraph(width, height); // 新开一个画面
        setbkcolor(WHITE); // 设置背景颜色为白色
        cleardevice(); // 以背景颜色清屏

        for (int i = 0; i < height; i = i + interval)  // 当行数遍历
        {
                for (int j = 0; j < width; j = j + interval) // 当列数遍历
                {
                        DWORD c = pMem[i * width + j]; //  获得i行j列图像像素信息
                        COLORREF col = BGR(pMem[i * width + j]); // 获得i行j列像素的颜色
                        int R = GetRValue(col); // 红色分量
                        int G = GetGValue(col); // 绿色分量
                        int B = GetBValue(col); // 蓝色分量
                        setfillcolor(RGB(R, G, B)); // 设置填充、线条颜色
                        setlinecolor(RGB(R, G, B));

                        int bright = 0.299 * R + 0.587 * B + 0.114 * B; // 获得当前像素的亮度
                        // 将[0,255]范围的亮度bright,映射为[1,interval]的值,设为半径大小
                        float radius = interval + (1 - interval) * bright / 255.0;
                        fillcircle(j, i, 0.9*radius); // 在当前位置,画一个圆球
                }
        }

        _getch();
        return 0;
}
3 随机小球画

上一节的小球分布太均匀了,可以引入随机数,对采样点的位置进行随机偏移,生成随机采样的小球画:


#include <graphics.h>
#include <conio.h>
#include <time.h>

int main()
{
        srand(time(0)); // 初始化随机种子
        IMAGE im; // 图像变量
        loadimage(&im, _T("pic1.jpg")); // 导入图像文件
        int width, height; //  图片的宽度、高度,也是屏幕的宽度、高度
        width = im.getwidth(); // 获得图像的宽度
        height = im.getheight(); // 获得图像的高度       
        DWORD* pMem = GetImageBuffer(&im); // 获得图像内容缓存

        int interval = 8;  // 图像行、列的采样间隔

        initgraph(width, height); // 新开一个画面
        setbkcolor(WHITE); // 设置背景颜色为白色
        cleardevice(); // 以背景颜色清屏
       
        int i = 0, j; // 行、列循环变量
        while (i < height) // 当行数小于height时
        {
                j = 0; //  列数初始化为0

                while (j < width)  // 当列数小于width时
                {
                        DWORD c = pMem[i * width + j]; //  获得i行j列图像像素信息
                        COLORREF col = BGR(pMem[i * width + j]); // 获得i行j列像素的颜色
                        int R = GetRValue(col); // 红色分量
                        int G = GetGValue(col); // 绿色分量
                        int B = GetBValue(col); // 蓝色分量
                        setfillcolor(RGB(R, G, B)); // 设置填充、线条颜色
                        setlinecolor(RGB(R, G, B));

                        int bright = 0.299 * R + 0.587 * B + 0.114 * B; // 获得当前像素的亮度
                        // 将[0,255]范围的亮度bright,映射为[1,interval]的值,设为半径大小
                        float radius = interval + (1 - interval) * bright / 255.0;                       
                        fillcircle(j, i, radius); // 在当前位置,画一个圆球

                        j = j + 2* radius + rand() % 3; // 列号向右平移一定距离
                }
                i = i + 1.2 * interval + rand() % 2; // 行号向下,有一定随机性
        }

        _getch();
        return 0;
}
4 字符小球画

和这一章字符串的主题结合,将小球用一个字符'o'来替代,可以绘制出一个字符小球画:


#include <graphics.h>
#include <conio.h>
#include <time.h>

int main()
{
        srand(time(0)); // 初始化随机种子
        IMAGE im; // 图像变量
        loadimage(&im, _T("pic1.jpg")); // 导入图像文件
        int width, height; //  图片的宽度、高度,也是屏幕的宽度、高度
        width = im.getwidth(); // 获得图像的宽度
        height = im.getheight(); // 获得图像的高度       
        DWORD* pMem = GetImageBuffer(&im); // 获得图像内容缓存

        int interval = 6;  // 图像行、列的采样间隔

        initgraph(width, height); // 新开一个画面
        setbkcolor(WHITE); // 设置背景颜色为白色
        setbkmode(TRANSPARENT); // 文字字体透明
        cleardevice(); // 以背景颜色清屏

        char ch = 'o'; // 要显示的字符
        int i = 0, j; // 行、列循环变量
        while (i < height) // 当行数小于height时
        {
                j = 0; //  列数初始化为0

                while (j < width)  // 当列数小于width时
                {
                        DWORD c = pMem[i * width + j]; //  获得i行j列图像像素信息
                        COLORREF col = BGR(pMem[i * width + j]); // 获得i行j列像素的颜色
                        int R = GetRValue(col); // 红色分量
                        int G = GetGValue(col); // 绿色分量
                        int B = GetBValue(col); // 蓝色分量
                        int bright = 0.299 * R + 0.587 * B + 0.114 * B; // 获得当前像素的亮度
                        // 将[0,255]范围的亮度bright,映射为[1,2*interval]的值,设为文字大小
                        float chSize = 2 * interval + (1 - 2 * interval) * bright / 255.0;

                        settextcolor(RGB(R, G, B));// 设定文字颜色为当前位置的图像像素颜色
                        settextstyle(1.5 * chSize, 0, _T("Comic Sans MS")); // 设置文字大小、字体
                        outtextxy(j, i, ch); // 在当前位置,输出当前字符

                        j = j + textwidth(ch) + rand() % 2; // 列号向右平移当前字符的宽度
                }
                i = i + 1.2 * interval + rand() % 2; // 行号向下,有一定随机性
        }

        _getch();
        return 0;
}
5 任意字符串画

将单个字符扩展为字符串,比如"Learning C with a ball ",实现任意字符串画:


#include <graphics.h>
#include <conio.h>
#include <time.h>
#include <string.h>

int main()
{
        srand(time(0)); // 初始化随机种子
        IMAGE im; // 图像变量
        loadimage(&im, _T("pic1.jpg")); // 导入图像文件
        int width, height; //  图片的宽度、高度,也是屏幕的宽度、高度
        width = im.getwidth(); // 获得图像的宽度
        height = im.getheight(); // 获得图像的高度       
        DWORD* pMem = GetImageBuffer(&im); // 获得图像内容缓存

        char str[] = "Learning C with a ball "; // 要输出的字符串
        int strIndex = 0; // 从字符串中取字符的数组下标
        int interval = 8;  // 图像行、列的采样间隔

        initgraph(width, height); // 新开一个画面
        setbkcolor(WHITE); // 设置背景颜色为白色
        setbkmode(TRANSPARENT); // 文字字体透明
        cleardevice(); // 以背景颜色清屏
       
        int i = 0, j; // 行、列循环变量
        while (i < height) // 当行数小于height时
        {
                j = 0; //  列数初始化为0

                while (j < width)  // 当列数小于width时
                {
                        DWORD c = pMem[i * width + j]; //  获得i行j列图像像素信息
                        COLORREF col = BGR(pMem[i * width + j]); // 获得i行j列像素的颜色
                        int R = GetRValue(col); // 红色分量
                        int G = GetGValue(col); // 绿色分量
                        int B = GetBValue(col); // 蓝色分量
                        int bright = 0.299 * R + 0.587 * B + 0.114 * B; // 获得当前像素的亮度
                        // 将[0,255]范围的亮度bright,映射为[1,2*interval]的值,设为文字大小
                        float chSize = 2*interval + (1 - 2*interval) * bright / 255.0;
                       
                        char ch = str[strIndex]; // 获得字符串str第strIndex个字符
                        strIndex++; // 字符串序号加1
                        if (strIndex >= strlen(str)) // 到了字符串末尾后,序号归0
                                strIndex = 0;

                        settextcolor(RGB(R, G, B));// 设定文字颜色为当前位置的图像像素颜色
                        settextstyle(1.5 * chSize, 0, _T("Comic Sans MS")); // 设置文字大小、字体
                        outtextxy(j, i, ch); // 在当前位置,输出当前字符

                        j = j + textwidth(ch) ; // 列号向右平移当前字符的宽度
                        if (ch == ' ') // 如果是空格,列号额外增加1或2
                                j = j + 1 + rand() % 2;
                }
                i = i + 1.2 * interval + rand() % 2; // 行号向下,有一定随机性
        }

        _getch();
        return 0;
}
到这里,读者可以拿任意的图片,生成任意字符串画了。比如,也可以用“Stay hungry.  Stay foolish. ”生成一张乔布斯的画像:


视频教程在这:

字符画的自动生成 C语言
https://www.zhihu.com/video/1576129731170332672

更多趣味学编程教学,可以参考童老师的图书:
回复

使用道具 举报

3

主题

9

帖子

16

积分

新手上路

Rank: 1

积分
16
发表于 2022-12-2 12:50:52 | 显示全部楼层
哇,头图是谁啊
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表