自动绘图AI:程序如何画出动漫美少女 您所在的位置:网站首页 美少女绘画卡通图片 自动绘图AI:程序如何画出动漫美少女

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

2024-02-02 04:11| 来源: 网络整理| 查看: 265

说明

  本文发布较早,了解最新动态,请查看 GitHub 项目。(2022 年 6 月 注)

准备

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

  IDE:VisualStudio

  Language:VB.NET / C#

  Graphics:AutoPaint.NET

第一节 背景

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

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

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

第二节 轮廓

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

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

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

第三节 光影

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

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

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

第四节 润色

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

图4-1 画面润色

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

第五节 成型

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

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

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

第六节 算法

  算法思路很简单,计算画笔轨迹后一遍遍重绘,感觉上是人类画手的效果。 

  不再是二值化

  因为现在要绘制全彩图像,将图像划分为只有黑和白的效果已经没有什么意义,二值化不再适用

  适用的方法是将 RGB 颜色空间划分为若干个颜色子空间,然后逐个处理一幅图像中属于某个子空间的区域

  自动循迹

  循迹算法没有大的变动,仍是早前博客里贴出的代码

  彩色图像线条较短,可以不再计算点周围的权值用来中断轨迹

  重绘

  程序先选择笔触较大、颜色淡的画笔绘制一遍,然后在这基础上逐步减小笔触并加深色彩

  直接按照标准笔触可以一遍成型,但会显得突兀和生硬,毕竟这个AI不是真的在思考如何画一幅图像

Imports System.Numerics ''' ''' 表示自动循迹并生成绘制序列的AI ''' Public Class SequenceAI ''' ''' 线条序列List ''' ''' Public Property Sequences As List(Of PointSequence) ''' ''' 扫描方式 ''' 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 ''' ''' 创建并初始化一个可自动生成绘制序列AI的实例 ''' Public Sub New(BolArr(,) As Integer) Sequences = New List(Of PointSequence) CalculateSequence(BolArr) For Each SubItem In Sequences SubItem.CalcSize() Next End Sub ''' ''' 新增一个序列 ''' Private Sub CreateNewSequence() Sequences.Add(New PointSequence) End Sub ''' ''' 在序列List末尾项新增一个点 ''' Private Sub AddPoint(point As Vector2) Sequences.Last.Points.Add(point) End Sub ''' ''' 计算序列 ''' Private Sub CalculateSequence(BolArr(,) As Integer) If ScanMode = ScanMode.Rect Then ScanRect(BolArr) Else ScanCircle(BolArr) End If End Sub ''' ''' 圆形扫描 ''' ''' 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 ''' ''' 矩形扫描 ''' ''' 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 ''' ''' 递归循迹算法 ''' 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 ''' ''' 返回点权值 ''' 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 ''' ''' 线条扫描方式 ''' Public Enum ScanMode ''' ''' 矩形扫描 ''' Rect ''' ''' 圆形扫描 ''' Circle End Enum VB.NET-SequenceAI Imports System.Numerics ''' ''' 表示由一系列点向量组成的线条 ''' Public Class PointSequence Public Property Points As New List(Of Vector2) Public Property Sizes As Single() ''' ''' 计算画笔大小 ''' 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 Sub End Class VB.NET-PointSequence using System; using System.Collections; using System.Collections.Generic; using System.Data; using System.Diagnostics; using System.Numerics; /// /// 表示自动循迹并生成绘制序列的AI /// public class SequenceAI { /// /// 线条序列List /// /// public List Sequences { get; set; } /// /// 扫描方式 /// 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; /// /// 创建并初始化一个可自动生成绘制序列AI的实例 /// public SequenceAI(int[,] BolArr) { Sequences = new List(); CalculateSequence(BolArr); foreach (object SubItem_loopVariable in Sequences) { SubItem = SubItem_loopVariable; SubItem.CalcSize(); } } /// /// 新增一个序列 /// private void CreateNewSequence() { Sequences.Add(new PointSequence()); } /// /// 在序列List末尾项新增一个点 /// private void AddPoint(Vector2 point) { Sequences.Last.Points.Add(point); } /// /// 计算序列 /// private void CalculateSequence(int[,] BolArr) { if (ScanMode == ScanMode.Rect) { ScanRect(BolArr); } else { ScanCircle(BolArr); } } /// /// 圆形扫描 /// /// 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 yCount ? xCount : yCount; R++) { for (Theat = 0; Theat 0 & dy > 0 & dx < xCount & dy 2 AndAlso AroundValue < 8 Then //Return //End If for (i = 0; i 0 & dy > 0 & dx < xBound & dy 0 & dx < xBound & dy


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有