星空网 > 软件开发 > ASP.net

自动绘图AI:程序如何画出动漫美少女

  全新的图形引擎与AI算法,高效流畅地绘出任何一副美丽的图像。

  IDE:VisualStudio 2015

  Language:VB.NET/C#

  Graphics:EDGameEngine

第一节 背景

  背景是图画里衬托主体事物的景象。

自动绘图AI:程序如何画出动漫美少女

图1.1 先画个蓝蓝的天空

  蓝天、白云和大地,程序最擅长这种色调单一的涂抹了

第二节 轮廓

  轮廓是物体的外周或图形的外框。

自动绘图AI:程序如何画出动漫美少女

图2.2 勾勒人物和衣饰轮廓

  现在AI要控制笔触大小和颜色,让图像的主体显现出来

第三节 光影

  光影是物体在光的照射下呈现出明与暗的关系。

自动绘图AI:程序如何画出动漫美少女

图3.1 光影提升画面质感

  AI可不懂什么是光影,在上一步的基础上优化细节即可

第四节 润色

  润色是增加物体本身及其周围的色彩。

自动绘图AI:程序如何画出动漫美少女

图4.1 画面润色

  这是关键一步,AI需要将丢失的颜色细节补缺回来

第五节 成型

  大功告成!前面所有的步骤都是为这一步铺垫。

自动绘图AI:程序如何画出动漫美少女

图5.1 人物已经栩栩如生啦

  事实上AI只进行这一步也可以画出完整的图像,但没有过渡会显得生硬

第六节 算法

  上文的图片是程序画的,文字是笔者瞎编的。

  AI只会计算画笔轨迹,然后一遍遍重绘,感觉上是人类画手的效果

  不再是二值化

  • 因为现在要绘制全彩图像,将图像划分为只有黑和白的效果已经没有什么意义,二值化不再适用
  • 适用的方法是将RGB颜色空间划分为若干个颜色子空间,然后逐个处理一幅图像中属于某个子空间的区域

  自动循迹

  • 循迹算法没有大的变动,仍是早前博客里贴出的代码
  • 彩色图像线条较短,可以不再计算点周围的权值用来中断轨迹

  重绘

  • 程序先选择笔触较大、颜色淡的画笔绘制一遍,然后在这基础上逐步减小笔触并加深色彩
  • 直接按照标准笔触可以一遍成型,但会显得突兀和生硬,毕竟这个AI不是真的在思考如何画一幅图像
自动绘图AI:程序如何画出动漫美少女自动绘图AI:程序如何画出动漫美少女
Imports System.Numerics''' <summary>''' 表示自动循迹并生成绘制序列的AI''' </summary>Public Class SequenceAI  ''' <summary>  ''' 线条序列List  ''' </summary>  ''' <returns></returns>  Public Property Sequences As List(Of PointSequence)  ''' <summary>  ''' 扫描方式  ''' </summary>  Public Property ScanMode As ScanMode = ScanMode.Rect  Dim xArray() As Integer = {-1, 0, 1, 1, 1, 0, -1, -1}  Dim yArray() As Integer = {-1, -1, -1, 0, 1, 1, 1, 0}  Dim NewStart As Boolean  ''' <summary>  ''' 创建并初始化一个可自动生成绘制序列AI的实例  ''' </summary>  Public Sub New(BolArr(,) As Integer)    Sequences = New List(Of PointSequence)    CalculateSequence(BolArr)    For Each SubItem In Sequences      SubItem.CalcSize()    Next  End Sub  ''' <summary>  ''' 新增一个序列  ''' </summary>  Private Sub CreateNewSequence()    Sequences.Add(New PointSequence)  End Sub  ''' <summary>  ''' 在序列List末尾项新增一个点  ''' </summary>  Private Sub AddPoint(point As Vector2)    Sequences.Last.Points.Add(point)  End Sub  ''' <summary>  ''' 计算序列  ''' </summary>  Private Sub CalculateSequence(BolArr(,) As Integer)    If ScanMode = ScanMode.Rect Then      ScanRect(BolArr)    Else      ScanCircle(BolArr)    End If  End Sub  ''' <summary>  ''' 圆形扫描  ''' </summary>  ''' <param name="BolArr"></param>  Private Sub ScanCircle(BolArr(,) As Integer)    Dim xCount As Integer = BolArr.GetUpperBound(0)    Dim yCount As Integer = BolArr.GetUpperBound(1)    Dim CP As New Point(xCount / 2, yCount / 2)    Dim R As Integer = 0    For R = 0 To If(xCount > yCount, xCount, yCount)      For Theat = 0 To Math.PI * 2 Step 1 / R        Dim dx As Integer = CInt(CP.X + R * Math.Cos(Theat))        Dim dy As Integer = CInt(CP.Y + R * Math.Sin(Theat))        If Not (dx > 0 And dy > 0 And dx < xCount And dy < yCount) Then Continue For        If BolArr(dx, dy) = 1 Then          BolArr(dx, dy) = 0          Me.CreateNewSequence()          Me.AddPoint(New Vector2(dx, dy))          CheckMove(BolArr, dx, dy, 0)          NewStart = True        End If      Next    Next  End Sub  ''' <summary>  ''' 矩形扫描  ''' </summary>  ''' <param name="BolArr"></param>  Private Sub ScanRect(BolArr(,) As Integer)    Dim xCount As Integer = BolArr.GetUpperBound(0)    Dim yCount As Integer = BolArr.GetUpperBound(1)    For i = 0 To xCount - 1      For j = 0 To yCount - 1        Dim dx As Integer = i        Dim dy As Integer = j        If Not (dx > 0 And dy > 0 And dx < xCount And dy < yCount) Then Continue For        If BolArr(dx, dy) = 1 Then          BolArr(dx, dy) = 0          Me.CreateNewSequence()          Me.AddPoint(New Vector2(dx, dy))          CheckMove(BolArr, dx, dy, 0)          NewStart = True        End If      Next    Next  End Sub  ''' <summary>  ''' 递归循迹算法  ''' </summary>  Private Sub CheckMove(ByRef bolArr(,) As Integer, ByVal x As Integer, ByVal y As Integer, ByVal StepNum As Integer)    If StepNum > 1000 Then Return    Dim xBound As Integer = bolArr.GetUpperBound(0)    Dim yBound As Integer = bolArr.GetUpperBound(1)    Dim dx, dy As Integer    Dim AroundValue As Integer = GetAroundValue(bolArr, x, y)    '根据点权值轨迹将在当前点断开    'If AroundValue > 2 AndAlso AroundValue < 8 Then    'Return    'End If    For i = 0 To 7      dx = x + xArray(i)      dy = y + yArray(i)      If Not (dx > 0 And dy > 0 And dx < xBound And dy < yBound) Then        Return      ElseIf bolArr(dx, dy) = 1 Then        bolArr(dx, dy) = 0        If NewStart = True Then          Me.CreateNewSequence()          Me.AddPoint(New Vector2(dx, dy))          NewStart = False        Else          Me.AddPoint(New Vector2(dx, dy))        End If        CheckMove(bolArr, dx, dy, StepNum + 1)        NewStart = True      End If    Next  End Sub  ''' <summary>  ''' 返回点权值  ''' </summary>  Private Function GetAroundValue(ByRef BolArr(,) As Integer, ByVal x As Integer, ByVal y As Integer) As Integer    Dim dx, dy, ResultValue As Integer    Dim xBound As Integer = BolArr.GetUpperBound(0)    Dim yBound As Integer = BolArr.GetUpperBound(1)    For i = 0 To 7      dx = x + xArray(i)      dy = y + yArray(i)      If dx > 0 And dy > 0 And dx < xBound And dy < yBound Then        If BolArr(dx, dy) = 1 Then          ResultValue += 1        End If      End If    Next    Return ResultValue  End FunctionEnd Class''' <summary>''' 线条扫描方式''' </summary>Public Enum ScanMode  ''' <summary>  ''' 矩形扫描  ''' </summary>  Rect  ''' <summary>  ''' 圆形扫描  ''' </summary>  CircleEnd Enum

VB.NET-SequenceAI
自动绘图AI:程序如何画出动漫美少女自动绘图AI:程序如何画出动漫美少女
Imports System.Numerics''' <summary>''' 表示由一系列点向量组成的线条''' </summary>Public Class PointSequence  Public Property Points As New List(Of Vector2)  Public Property Sizes As Single()  ''' <summary>  ''' 计算画笔大小  ''' </summary>  Public Sub CalcSize()    If Points.Count < 1 Then Exit Sub    Static Mid, PenSize As Single    ReDim Sizes(Points.Count - 1)    For i = 0 To Points.Count - 1      Mid = CSng(Math.Abs(i - Points.Count / 2))      PenSize = 1 - Mid / Points.Count * 2      Sizes(i) = PenSize    Next  End SubEnd Class

VB.NET-PointSequence
自动绘图AI:程序如何画出动漫美少女自动绘图AI:程序如何画出动漫美少女
using System;using System.Collections;using System.Collections.Generic;using System.Data;using System.Diagnostics;using System.Numerics;/// <summary>/// 表示自动循迹并生成绘制序列的AI/// </summary>public class SequenceAI{  /// <summary>  /// 线条序列List  /// </summary>  /// <returns></returns>  public List<PointSequence> Sequences { get; set; }  /// <summary>  /// 扫描方式  /// </summary>  public ScanMode ScanMode { get; set; }  int[] xArray = {    -1,    0,    1,    1,    1,    0,    -1,    -1  };  int[] yArray = {    -1,    -1,    -1,    0,    1,    1,    1,    0  };  bool NewStart;  /// <summary>  /// 创建并初始化一个可自动生成绘制序列AI的实例  /// </summary>  public SequenceAI(int[,] BolArr)  {    Sequences = new List<PointSequence>();    CalculateSequence(BolArr);    foreach (object SubItem_loopVariable in Sequences) {      SubItem = SubItem_loopVariable;      SubItem.CalcSize();    }  }  /// <summary>  /// 新增一个序列  /// </summary>  private void CreateNewSequence()  {    Sequences.Add(new PointSequence());  }  /// <summary>  /// 在序列List末尾项新增一个点  /// </summary>  private void AddPoint(Vector2 point)  {    Sequences.Last.Points.Add(point);  }  /// <summary>  /// 计算序列  /// </summary>  private void CalculateSequence(int[,] BolArr)  {    if (ScanMode == ScanMode.Rect) {      ScanRect(BolArr);    } else {      ScanCircle(BolArr);    }  }  /// <summary>  /// 圆形扫描  /// </summary>  /// <param name="BolArr"></param>  private void ScanCircle(int[,] BolArr)  {    int xCount = BolArr.GetUpperBound(0);    int yCount = BolArr.GetUpperBound(1);    Point CP = new Point(xCount / 2, yCount / 2);    int R = 0;    for (R = 0; R <= xCount > yCount ? xCount : yCount; R++) {      for (Theat = 0; Theat <= Math.PI * 2; Theat += 1 / R) {        int dx = Convert.ToInt32(CP.X + R * Math.Cos(Theat));        int dy = Convert.ToInt32(CP.Y + R * Math.Sin(Theat));        if (!(dx > 0 & dy > 0 & dx < xCount & dy < yCount))          continue;        if (BolArr[dx, dy] == 1) {          BolArr[dx, dy] = 0;          this.CreateNewSequence();          this.AddPoint(new Vector2(dx, dy));          CheckMove(ref BolArr, dx, dy, 0);          NewStart = true;        }      }    }  }  /// <summary>  /// 矩形扫描  /// </summary>  /// <param name="BolArr"></param>  private void ScanRect(int[,] BolArr)  {    int xCount = BolArr.GetUpperBound(0);    int yCount = BolArr.GetUpperBound(1);    for (i = 0; i <= xCount - 1; i++) {      for (j = 0; j <= yCount - 1; j++) {        int dx = i;        int dy = j;        if (!(dx > 0 & dy > 0 & dx < xCount & dy < yCount))          continue;        if (BolArr[dx, dy] == 1) {          BolArr[dx, dy] = 0;          this.CreateNewSequence();          this.AddPoint(new Vector2(dx, dy));          CheckMove(ref BolArr, dx, dy, 0);          NewStart = true;        }      }    }  }  /// <summary>  /// 递归循迹算法  /// </summary>  private void CheckMove(ref int[,] bolArr, int x, int y, int StepNum)  {    if (StepNum > 1000)      return;    int xBound = bolArr.GetUpperBound(0);    int yBound = bolArr.GetUpperBound(1);    int dx = 0;    int dy = 0;    int AroundValue = GetAroundValue(ref bolArr, x, y);    //根据点权值轨迹将在当前点断开    //If AroundValue > 2 AndAlso AroundValue < 8 Then    //Return    //End If    for (i = 0; i <= 7; i++) {      dx = x + xArray[i];      dy = y + yArray[i];      if (!(dx > 0 & dy > 0 & dx < xBound & dy < yBound)) {        return;      } else if (bolArr[dx, dy] == 1) {        bolArr[dx, dy] = 0;        if (NewStart == true) {          this.CreateNewSequence();          this.AddPoint(new Vector2(dx, dy));          NewStart = false;        } else {          this.AddPoint(new Vector2(dx, dy));        }        CheckMove(ref bolArr, dx, dy, StepNum + 1);        NewStart = true;      }    }  }  /// <summary>  /// 返回点权值  /// </summary>  private int GetAroundValue(ref int[,] BolArr, int x, int y)  {    int dx = 0;    int dy = 0;    int ResultValue = 0;    int xBound = BolArr.GetUpperBound(0);    int yBound = BolArr.GetUpperBound(1);    for (i = 0; i <= 7; i++) {      dx = x + xArray[i];      dy = y + yArray[i];      if (dx > 0 & dy > 0 & dx < xBound & dy < yBound) {        if (BolArr[dx, dy] == 1) {          ResultValue += 1;        }      }    }    return ResultValue;  }}/// <summary>/// 线条扫描方式/// </summary>public enum ScanMode{  /// <summary>  /// 矩形扫描  /// </summary>  Rect,  /// <summary>  /// 圆形扫描  /// </summary>  Circle}

C#-SequenceAI
自动绘图AI:程序如何画出动漫美少女自动绘图AI:程序如何画出动漫美少女
using System;using System.Collections;using System.Collections.Generic;using System.Data;using System.Diagnostics;using System.Numerics;/// <summary>/// 表示由一系列点向量组成的线条/// </summary>public class PointSequence{  public List<Vector2> Points { get; set; }  public float[] Sizes { get; set; }  float static_CalcSize_Mid;  /// <summary>  /// 计算画笔大小  /// </summary>  float static_CalcSize_PenSize;  public void CalcSize()  {    if (Points.Count < 1)      return;    Sizes = new float[Points.Count];    for (i = 0; i <= Points.Count - 1; i++) {      static_CalcSize_Mid = Convert.ToSingle(Math.Abs(i - Points.Count / 2));      static_CalcSize_PenSize = 1 - static_CalcSize_Mid / Points.Count * 2;      Sizes[i] = static_CalcSize_PenSize;    }  }}

C#-PointSequence

附录

  相关链接

  Demo视频:AutomaticDrawing_人民 (上文的视频暂不上传\(^o^)/)

  Demo开源:EDGameEngine.Visuals.AutoDraw

  相关博客

  玩转你画我猜(一):程序实现自动绘图 

  玩转你画我猜(二):更优秀的自动绘图程序 

  AR创意分享:儿童涂鸦遇上程序绘图 




原标题:自动绘图AI:程序如何画出动漫美少女

关键词:

*特别声明:以上内容来自于网络收集,著作权属原作者所有,如有侵权,请联系我们: admin#shaoqun.com (#换成@)。

亚马逊因疫情放宽对第三方卖家的送货速度要求:https://www.ikjzd.com/articles/139578
亚马逊卖家怎样提升FBA发货数量?:https://www.ikjzd.com/articles/139579
特朗普将QQ支付宝微信支付等8个中国APP列入黑名单:https://www.ikjzd.com/articles/139580
儿童两步凳---美国专利侵权预警:https://www.ikjzd.com/articles/139581
沙特阿拉伯物流市场规模达180亿美元:https://www.ikjzd.com/articles/139582
在新加坡注册离岸公司的优势有哪些?:https://www.ikjzd.com/articles/139583
无锡旅游景点竹海 - 无锡的竹海:https://www.vstour.cn/a/363178.html
5月贾汪好玩的地方 贾汪哪有好玩的地方:https://www.vstour.cn/a/363179.html
相关文章
我的浏览记录
最新相关资讯
海外公司注册 | 跨境电商服务平台 | 深圳旅行社 | 东南亚物流