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

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

  IDE:VisualStudio

  Language:VB.NET / C#

  Graphics:AutoPaint.NET

第一节 背景

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

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

图1-1 先画个蓝蓝的天空

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

第二节 轮廓

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

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

图2-2 勾勒人物和衣饰轮廓

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

第三节 光影

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

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

图3-1 光影提升画面质感

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

第四节 润色

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

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

图4-1 画面润色

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

第五节 成型

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

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

图5-1 人物已经栩栩如生啦

  事实上 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></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></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 Function End Class \'\'\' <summary> \'\'\' 线条扫描方式 \'\'\' </summary> Public Enum ScanMode \'\'\' <summary> \'\'\' 矩形扫描 \'\'\' </summary> Rect \'\'\' <summary> \'\'\' 圆形扫描 \'\'\' </summary> Circle End Enum

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zggjsd.html