C语言实现绘制绕线画的示例代码

目录
  • 绕线画简介
  • 算法简介
  • 示例

绕线画简介

简单点来说,就是在木板上钉一圈钉子,通过绕线进行构图,最终呈现出一幅图像。

算法简介

可以总结概括一下,

首先需要有一张图,可以是彩色的,但是必须颜色比较分明。

对图像进行灰度处理。

随机生成 n 组数,就是每两个钉子的组合。

计算 n 组数据连线所过图像像素的平均数,求出最小的一组。

连接该组钉子,并对这条线经过的像素值分别加 m。

重复前面步骤 3 到步骤 5 直到绘制 z 条线结束循环。

示例

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

// 以下数据可以自己调节
#define PointNum 288    // 圆圈分的数量(一圈钉子的数量)
#define LineNum 3000    // 循环绘制线的数量
#define RandNum 120      // 设置每次随机生成连接的数量
#define AddColor 52      // 增加的值 0 到 255 值越小越线越集中,越大越分散
#define SIZE 800      // 图像大小

// 以下参数不用调节
#define PI acos(-1.0)    // 圆周率
#define R (SIZE / 2 - 10)    // 半径

struct PointS
{
  int p;
  int x;
  int y;
};

struct LineS
{
  int StarP;        // 起点
  int EndP;        // 终点
};

PointS points[PointNum];
LineS lines[RandNum];

// 为了判断两点是否连线定义的一维数组
bool LineXY[(1 + PointNum) * PointNum / 2] = { false };
bool Line_Rand[(1 + PointNum) * PointNum / 2] = { false };

// 两条线是否连接
bool IsLineKed_Rand(int p1, int p2)
{
  if (p1 >= p2)
    return Line_Rand[(1 + p1) * p1 / 2 + p2];
  else
    return Line_Rand[(1 + p2) * p2 / 2 + p1];
}

// 储存已经绘制过的线
void Link_Rand(int p1, int p2)
{
  if (p1 >= p2)
    Line_Rand[(1 + p1) * p1 / 2 + p2] = true;
  else
    Line_Rand[(1 + p2) * p2 / 2 + p1] = true;
}

// 将随机生成的进行初始化
void Line2False()
{
  for (int i = 0; i < (1 + PointNum) * PointNum / 2; i++)
  {
    Line_Rand[i] = false;
  }
}

// 判断这两个点是否连线
bool IsLinked(int p1, int p2)
{
  if (p1 >= p2)
    return LineXY[(1 + p1) * p1 / 2 + p2];
  else
    return LineXY[(1 + p2) * p2 / 2 + p1];
}

// 储存已经绘制过的线
void Link(int p1, int p2)
{
  if (p1 >= p2)
    LineXY[(1 + p1) * p1 / 2 + p2] = true;
  else
    LineXY[(1 + p2) * p2 / 2 + p1] = true;
}

int Round(float x);                // 取整
void InitPoints();                // 初始化点
void ColorToGray(IMAGE *pimg);          // 彩色图像转换为灰度图像
void Random();                  // 产生随机数
LineS Getline(IMAGE *pimg);            // 获取照片颜色
void ToColor(IMAGE *oriPic, IMAGE *linePic);  // 给绕线图赋予颜色

int main()
{
  initgraph(SIZE, SIZE);
  setbkcolor(WHITE);
  cleardevice();
  IMAGE imgpolt;                  // 加载原图
  IMAGE oriPic;                  // 储存原图
  IMAGE linePic;                  // 线图
  loadimage(&imgpolt, _T("TG.jpeg"), SIZE, SIZE);  // 加载原图
  oriPic = imgpolt;                // 原图
  ColorToGray(&imgpolt);              // 将图片转换为灰度
  InitPoints();                  // 初始化点
  srand((unsigned)time(NULL));          // 生成随机种子

  for (int i = 0; i < LineNum; i++)
  {
    Random();                  // 随机生成 80
    LineS myline = Getline(&imgpolt);      // 计算 80 组点中平均值最小的
    Link(myline.StarP, myline.EndP);      // 记录绘制过的线防止重复绘制
    line(points[myline.StarP].x, points[myline.StarP].y, points[myline.EndP].x, points[myline.EndP].y);
  }
  _getch();

  // /*该部分是给线条加上颜色*/
  // saveimage(_T("test.png"));            // 保存一下绕线图
  // loadimage(&linePic, _T("test.png"), SIZE, SIZE); // 重新加载绕线图
  // ToColor(&oriPic, &linePic);            // 用原图将绕线图的颜色替换
  // putimage(0, 0, &oriPic);
  // _getch();
  return 0;
}

// 初始化点(想创新可以生成椭圆的位置坐标)
void InitPoints()
{
  for (int i = 0; i < PointNum; i++)
  {
    double a = i * PI * 2 / PointNum;
    points[i].p = i;
    points[i].x = int(SIZE / 2.0 + R * cos(a));
    points[i].y = int(SIZE / 2.0 - R * sin(a));
    setlinecolor(BLACK);
    circle(points[i].x, points[i].y, 3);
  }
}

// 彩色图像转换为灰度图像
void ColorToGray(IMAGE *pimg)
{
  DWORD *p = GetImageBuffer(pimg);  // 获取显示缓冲区指针
  COLORREF c;
  for (int i = pimg->getwidth() * pimg->getheight() - 1; i >= 0; i--)
  {
    c = BGR(p[i]);
    c = (GetRValue(c) * 299 + GetGValue(c) * 587 + GetBValue(c) * 114 + 500) / 1000;
    p[i] = RGB(c, c, c);
  }
}

// 随机生成线
void Random()
{
  for (int i = 0; i < RandNum; i++)
  {
    int starP;
    int endP;
    while (true)
    {
      starP = rand() % PointNum;
      endP = rand() % PointNum;
      if (IsLinked(starP, endP) == false
        && IsLineKed_Rand(starP, endP) == false)
      {
        break;
      }
    }
    lines[i].StarP = starP;
    lines[i].EndP = endP;
    Link_Rand(starP, endP);    // 记录随机生成的线
  }
  Line2False();          // 初始化线值
}

// 四舍五入
int Round(float x)
{
  return (int)(x < 0 ? x - 0.5 : x + 0.5);
}

// 获取颜色最深的那一条线
LineS Getline(IMAGE *pimg)
{
  LineS mylines;
  mylines.StarP = 0;
  mylines.EndP = 0;
  DWORD*  p_data = GetImageBuffer(pimg);
  int width = pimg->getwidth();
  double MaxNum = 255;
  int MYsteps;
  float X, Y;
  float CX, CY;
  for (int i = 0; i<RandNum; i++)
  {
    int SUMDN = 0;
    int x1 = points[lines[i].StarP].x;
    int y1 = points[lines[i].StarP].y;
    int x2 = points[lines[i].EndP].x;
    int y2 = points[lines[i].EndP].y;
    int steps = abs(x2 - x1) > abs(y2 - y1) ? abs(x2 - x1) : abs(y2 - y1);
    float x = (float)x1;
    float y = (float)y1;
    float cx = (float)(x2 - x1) / steps;
    float cy = (float)(y2 - y1) / steps;

    for (int j = 0; j < steps; j++)
    {
      int XIA = width * Round(y) + Round(x);
      SUMDN += GetRValue(p_data[XIA]);
      x += cx;
      y += cy;
    }
    double Aver = SUMDN / (steps * 1.0);

    if (Aver < MaxNum)
    {
      MaxNum = Aver;
      mylines = lines[i];
      MYsteps = steps;
      X = (float)x1;
      Y = (float)y1;
      CX = cx;
      CY = cy;
    }
  }
  if (MaxNum == 255)
  {
    return mylines;
  }
  for (int j = 0; j < MYsteps; j++)
  {
    int XIA = width* Round(Y) + Round(X);
    int c = GetRValue(p_data[XIA]) + AddColor > 255 ? 255 : GetRValue(p_data[XIA]) + AddColor;
    p_data[XIA] = RGB(c, c, c);
    X += CX;
    Y += CY;
  }
  return mylines;
}

// 给线图上色
void ToColor(IMAGE *oriPic, IMAGE *linePic)
{
  DWORD*  ori_data = GetImageBuffer(oriPic);
  DWORD* line_data = GetImageBuffer(linePic);
  for (int i = oriPic->getwidth() * oriPic->getheight() - 1; i >= 0; i--)
  {
    int oriR = GetRValue(ori_data[i]);
    int oriG = GetGValue(ori_data[i]);
    int oriB = GetBValue(ori_data[i]);
    int lineR = GetRValue(line_data[i]);
    int lineG = GetGValue(line_data[i]);
    int lineB = GetBValue(line_data[i]);
    int newPicR = (int)(255 - (255 - lineR)*(255 - oriR) / 255.0);
    int newPicG = (int)(255 - (255 - lineG)*(255 - oriG) / 255.0);
    int newPicB = (int)(255 - (255 - lineB)*(255 - oriB) / 255.0);
    ori_data[i] = RGB(newPicR, newPicG, newPicB);
  }
}

到此这篇关于C语言实现绘制绕线画的示例代码的文章就介绍到这了,更多相关C语言绕线画内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言实现弹跳小球动画

    目录 一.项目描述和最终成果展示 二.实现一个移动的球 三.弹跳一个小球 四.弹跳一个小球(改进版) 五.多个球碰撞 六.多个球碰撞(升级版) 本文实例为大家分享了C语言实现弹跳小球动画的具体代码,供大家参考,具体内容如下 一.项目描述和最终成果展示 项目描述:  一个球来回的跳动 效果图如下: 二.实现一个移动的球 代码如下: #include<graphics.h> #include<conio.h> int main(void) {     int x;     initgr

  • 用C语言画一个圆

    目录 一.概念说明 1.1圆 1.2圆的图样 二.问题呈现 1.问题描述 2.输入输出 3.测试样例 三.源码实现(+注释) 四.输出结果图示 五.简要解释 1.实现关键 2.小说明 总结 一.概念说明 1.1圆 在一个平面内,围绕一个点并以一定长度为距离旋转一周所形成的封闭曲线叫做圆(Circle). 圆的表达式:(x - a)² +(y - b)² = r²a=0,b=0的情况下: x² + y² = r² 1.2圆的图样 仅供参考理解: 二.问题呈现 1.问题描述 Problem Desc

  • 利用C语言编辑画图程序的实现方法(推荐)

    不知道大家在进行开发县级电网调度自动化系统的时候,是否都会遇到一个问题就是:要绘制一个电力系统一次接线图.大家都应该知道其实电力系统的一次接线图是较为复杂的,如果想要使用一般的编程方法来进行绘制的话,基本上就是行不通的.那么我们应该怎样才可以更加的高效直接呢?今天小编就会给大家介绍一个方法,那就是:利用C语言编辑画图程序的实现方法.希望这篇教程对于大家有所帮助. 一.实现方法 在教程开始之前,小编先为大家介绍一下在编程程序里面早已定义了几个特殊按钮.为什么小编要为大家介绍这几个特殊按钮呢?那是因

  • 如何用C语言画一个“圣诞树”

    如何用C语言画一个"圣诞树",我使用了左右镜像的Sierpinski triangle,每层减去上方一小块,再用符号点缀.可生成不同层数的「圣诞树」,如下图是5层的结果 #include <stdlib.h> int main(int argc, char* argv[]) { int n = argc > 1 ? atoi(argv[1]) : 4; for (int j = 1; j <= n; j++) { int s = 1 << j, k

  • C语言实现绘制绕线画的示例代码

    目录 绕线画简介 算法简介 示例 绕线画简介 简单点来说,就是在木板上钉一圈钉子,通过绕线进行构图,最终呈现出一幅图像. 算法简介 可以总结概括一下, 首先需要有一张图,可以是彩色的,但是必须颜色比较分明. 对图像进行灰度处理. 随机生成 n 组数,就是每两个钉子的组合. 计算 n 组数据连线所过图像像素的平均数,求出最小的一组. 连接该组钉子,并对这条线经过的像素值分别加 m. 重复前面步骤 3 到步骤 5 直到绘制 z 条线结束循环. 示例 #include<graphics.h> #in

  • C语言实现六边形扫雷游戏的示例代码

    目录 程序简介 程序运行展示 完整源代码 程序简介 六边形扫雷,寻宝模式,稍稍介绍一下. 他也是要把所有安全的地方点出来. 他没有扫雷模式的消零算法.每一个安全的点都需要单独挖出来,一次显示一个格子. 添加了生命值的概念,也就是说存在一定的容错. 显示的数字有别于扫雷模式.点击宝藏点,会显示周围宝藏点数量,绿色:点击地雷,会显示周围地雷数量,黑色.注意,这个数字不包括自己,显示的范围自然就是 0~6 了.点击地雷会减生命值,生命值归零则结束. 所以雷和宝藏都是有价值的,都是能给准确信息的. 我能

  • 利用Matlab绘制有趣图像的示例代码

    目录 1.随机樱花树 2.苹果绘制 3.南瓜绘制 4.一堆三角形绘制 5.月饼绘制 6.大钻石绘制 7.有趣曲线1 8.有趣曲线2 9.有趣曲线3——蝴蝶曲线 10.有趣曲线4——心形曲线 11.有趣曲线5 12.会害羞的含羞草 13.随机雪景 1.随机樱花树 function sakura % @author:slandarer % 随机形状二叉树樱花树绘制 hold on,axis equal axis(0.5+[-10,50,0,50]) set(gca,'xtick',[],'ytick

  • Qt实现绘制网格背景的示例代码

    目录 现有功能 运行结果 源码 window.h window.cpp main.cpp 现有功能 使用滚轮缩放. 缩放到达一定阈值后恢复网格大小. 窗口大小调整时网格背景也自动调整重绘. 运行结果 源码 window.h #ifndef WINDOW_H #define WINDOW_H #include <QWidget> #include <QPen> #include <QPainter> #include <QPaintEvent> class W

  • 利用Go语言实现流量回放工具的示例代码

    目录 前言 goreplay介绍与安装 使用示例 流量放大.缩小 流量写入到ElastichSearch goreplay基本实现原理 总结 前言 哈喽,大家好,我是asong. 今天给大家推荐一款使用Go语言编写的流量回放工具 -- goreplay:工作中你一定遇到过需要在服务器上抓包的场景,有了这个工具就可以助你一臂之力,goreplay的功能十分强大,支持流量的放大.缩小,并且集成了ElasticSearch,将流量存入ES进行实时分析: 废话不多,我们接下来来看一看这个工具: gore

  • WPF实现绘制扇形统计图的示例代码

    扇形统计图 绘制一个扇形原理也是基于Canvas进行绘制; ArcSegment[1]绘制弧形; 绘制指示线: 绘制文本: 鼠标移入动画: 显示详情Popup: 源码Github[2] Gitee[3] 示例代码 1)SectorChart.cs代码如下; using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Win

  • 基于Matlab实现绘制3D足球的示例代码

    目录 绘制讲解 数据来源及说明 硬算顶点连接情况 三角剖分 正交变换 充气 完整代码 世界杯教你用MATLAB画个超逼真的足球, 需要准备Partial Differential Equation Toolbox工具箱,同时因为用到了polyshape类所以至少需要R2017b版本. 绘制讲解 数据来源及说明 我是真的不想写注释了太麻烦了,给大家讲一下我的思路希望能够看懂,首先足球的数据点是通过: [B,XYZ]=bucky; 导入的,但是导入的只有边链接信息,并没有给出哪几个点构成正五边形哪几

  • python使用matplotlib绘制折线图的示例代码

    示例代码如下: #!/usr/bin/python #-*- coding: utf-8 -*- import matplotlib.pyplot as plt # figsize - 图像尺寸(figsize=(10,10)) # facecolor - 背景色(facecolor="blue") # dpi - 分辨率(dpi=72) fig = plt.figure(figsize=(10,10),facecolor="blue") #figsize默认为4,

  • C语言实现无头单向链表的示例代码

    目录 一.易错的接口实现 1.1 新节点开辟函数 1.2 尾插 1.3 尾删 二.常见简单接口 2.1 打印链表 2.2 节点计数器 2.3 判断是否为空链表 2.4 通过值查找节点 2.5 头插 2.6 头删 2.7 在任意节点后插入节点 2.8 在任意节点后删除节点 2.9 销毁链表 三.头文件相关内容 3.1 引用的库函数 3.2 结构体声明 一.易错的接口实现 1.1 新节点开辟函数 由于创建一个新节点是频繁的操作,所以封装为一个接口最佳. 链表节点的属性有:(1)数值.(2)指向下一个

  • C语言编程入门必背的示例代码整理大全

    目录 一.C语言必背代码前言 二.一部分C语言必背代码 一.C语言必背代码前言 对于c语言来说,要记得东西其实不多,基本就是几个常用语句加一些关键字而已.你所看到的那些几千甚至上万行的代码,都是用这些语句和关键词来重复编写的.只是他们逻辑功能不一样,那如何快速的上手C语言代码,建议多看多写,下面是小编整理的C语言必背代码. 二.一部分C语言必背代码 1.输出9*9成法口诀,共9行9列,i控制行,j控制列. #include "stdio.h" main() {int i,j,resul

随机推荐