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

C/C++
268
0
0
2023-06-12
目录
  • 绕线画简介
  • 算法简介
  • 示例

绕线画简介

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

算法简介

可以总结概括一下,

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

对图像进行灰度处理。

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

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

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

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

示例

#include<graphics.h>
#include<math.h>
#include<conio.h>
#include<time.h>
 
// 以下数据可以自己调节
#define PointNum    // 圆圈分的数量(一圈钉子的数量)
#define LineNum    // 循环绘制线的数量
#define RandNum      // 设置每次随机生成连接的数量
#define AddColor      // 增加的值 0 到 255 值越小越线越集中,越大越分散
#define SIZE      // 图像大小
 
// 以下参数不用调节
#define PI acos(-.0)    // 圆周率
#define R (SIZE / - 10)    // 半径
 
struct PointS
{
  int p;
  int x;
  int y;
};
 
struct LineS
{
  int StarP;        // 起点
  int EndP;        // 终点
};
 
PointS points[PointNum];
LineS lines[RandNum];
 
// 为了判断两点是否连线定义的一维数组
bool LineXY[( + PointNum) * PointNum / 2] = { false };
bool Line_Rand[( + PointNum) * PointNum / 2] = { false };
 
// 两条线是否连接
bool IsLineKed_Rand(int p, int p2)
{
  if (p >= p2)
    return Line_Rand[( + p1) * p1 / 2 + p2];
  else
    return Line_Rand[( + p2) * p2 / 2 + p1];
}
 
// 储存已经绘制过的线
void Link_Rand(int p, int p2)
{
  if (p >= p2)
    Line_Rand[( + p1) * p1 / 2 + p2] = true;
  else
    Line_Rand[( + p2) * p2 / 2 + p1] = true;
}
 
// 将随机生成的进行初始化
void LineFalse()
{
  for (int i =; i < (1 + PointNum) * PointNum / 2; i++)
  {
    Line_Rand[i] = false;
  }
}
 
// 判断这两个点是否连线
bool IsLinked(int p, int p2)
{
  if (p >= p2)
    return LineXY[( + p1) * p1 / 2 + p2];
  else
    return LineXY[( + p2) * p2 / 2 + p1];
}
 
// 储存已经绘制过的线
void Link(int p, int p2)
{
  if (p >= p2)
    LineXY[( + p1) * p1 / 2 + p2] = true;
  else
    LineXY[( + 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 =; i < LineNum; i++)
  {
    Random();                  // 随机生成
    LineS myline = Getline(&imgpolt);      // 计算 组点中平均值最小的
    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, &oriPic);
  // _getch();
  return;
}
 
// 初始化点(想创新可以生成椭圆的位置坐标)
void InitPoints()
{
  for (int i =; i < PointNum; i++)
  {
    double a = i * PI * / PointNum;
    points[i].p = i;
    points[i].x = int(SIZE /.0 + R * cos(a));
    points[i].y = int(SIZE /.0 - R * sin(a));
    setlinecolor(BLACK);
    circle(points[i].x, points[i].y,);
  }
}
 
// 彩色图像转换为灰度图像
void ColorToGray(IMAGE *pimg)
{
  DWORD *p = GetImageBuffer(pimg);  // 获取显示缓冲区指针
  COLORREF c;
  for (int i = pimg->getwidth() * pimg->getheight() -; i >= 0; i--)
  {
    c = BGR(p[i]);
    c = (GetRValue(c) * + GetGValue(c) * 587 + GetBValue(c) * 114 + 500) / 1000;
    p[i] = RGB(c, c, c);
  }
}
 
// 随机生成线
void Random()
{
  for (int i =; 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);    // 记录随机生成的线
  }
  LineFalse();          // 初始化线值
}
 
// 四舍五入
int Round(float x)
{
  return (int)(x < ? x - 0.5 : x + 0.5);
}
 
// 获取颜色最深的那一条线
LineS Getline(IMAGE *pimg)
{
  LineS mylines;
  mylines.StarP =;
  mylines.EndP =;
  DWORD*  p_data = GetImageBuffer(pimg);
  int width = pimg->getwidth();
  double MaxNum =;
  int MYsteps;
  float X, Y;
  float CX, CY;
  for (int i =; i<RandNum; i++)
  {
    int SUMDN =;
    int x = points[lines[i].StarP].x;
    int y = points[lines[i].StarP].y;
    int x = points[lines[i].EndP].x;
    int y = points[lines[i].EndP].y;
    int steps = abs(x - x1) > abs(y2 - y1) ? abs(x2 - x1) : abs(y2 - y1);
    float x = (float)x;
    float y = (float)y;
    float cx = (float)(x - x1) / steps;
    float cy = (float)(y - y1) / steps;
 
    for (int j =; j < steps; j++)
    {
      int XIA = width * Round(y) + Round(x);
      SUMDN += GetRValue(p_data[XIA]);
      x += cx;
      y += cy;
    }
    double Aver = SUMDN / (steps *.0);
 
    if (Aver < MaxNum)
    {
      MaxNum = Aver;
      mylines = lines[i];
      MYsteps = steps;
      X = (float)x;
      Y = (float)y;
      CX = cx;
      CY = cy;
    }
  }
  if (MaxNum ==)
  {
    return mylines;
  }
  for (int j =; j < MYsteps; j++)
  {
    int XIA = width* Round(Y) + Round(X);
    int c = GetRValue(p_data[XIA]) + AddColor > ? 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() -; 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 - lineR)*(255 - oriR) / 255.0);
    int newPicG = (int)( - (255 - lineG)*(255 - oriG) / 255.0);
    int newPicB = (int)( - (255 - lineB)*(255 - oriB) / 255.0);
    ori_data[i] = RGB(newPicR, newPicG, newPicB);
  }
}