玩转你画笔者猜,自动绘图AI

By admin in 4858.com on 2019年5月2日

说明

  本文揭穿时间较早,内容或许不圆满或已不合时宜,查看最新动态请关怀GitHub 项目。(201八 年 7 月 注)

准备

  IDE:Visual Studio

  Language:VB.NET/C#

  GitHub:AutomaticDrawing

  程序落成自动画画,今后玩你画本身猜再也不用顾忌被戏弄啦~\(≧▽≦)/~。

说明

  本文为那一个类别较早时候揭橥的小说,内容也许不周全或已不合时宜,仅供参考。 style=”color: #88888八;”>(二零一八年二月 注)

玩转你画笔者猜,自动绘图AI。准备

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

  IDE:VisualStudio

  Language:VB.NET / C#

  Graphics:EDGameEngine

第一节 位图

  若要程序画画,首先得导入一张图纸作为模板。

  图像格式

  大家选用选用位图,它是由像素数据定义的图像格式

  WinForm下行使封装了GDI+位图的System.Drawing.Bitmap.aspx)对象

  UWP下能够运用CanvasBitmap目的(需求安装Win2D的Nuget包)

  导入格局

  当三步跳件:

  • 直白导入本地图像能源
  • 详情见System.Drawing.Bitmap.aspx)构造函数

      显示屏截图:

  • 先用搜索引擎搜图,然后直接截屏
  • System.Drawing.Graphics.aspx)对象提供从显示器到Graphics的位块传输

  动态合成:

  • 譬如说合成文本可能图案到钦定的图像上
  • System.Drawing.Graphics.aspx)对象提供壹密密麻麻的GDI+绘图命令

4858.com 14858.com 2

    ''' <summary>
    ''' 返回指定矩形区域的屏幕图像
    ''' </summary>
    ''' <param name="rect">指定的矩形区域</param>
    ''' <returns></returns>
    Public Function GetScreenImage(ByVal rect As Rectangle) As Bitmap
        Dim resultBmp As New Bitmap(rect.Width, rect.Height)
        Using pg As Graphics = Graphics.FromImage(resultBmp)
            pg.CopyFromScreen(rect.X, rect.Y, 0, 0, New Size(rect.Width, rect.Height))
        End Using
        Return resultBmp
    End Function

VB.NET-GetScreenImage

4858.com 34858.com 4

    ''' <summary>
    ''' 返回指定文字生成的位图
    ''' </summary>
    ''' <param name="text">文本</param>
    ''' <param name="font">字体</param>
    ''' <param name="width">位图宽度</param>
    ''' <param name="height">位图高度</param>
    ''' <returns></returns>
    Public Function GetTextImage(ByVal text As String, ByVal font As Font, ByVal width As Integer, ByVal height As Integer) As Bitmap
        Dim resultBmp As New Bitmap(width, height)
        Using pg = Graphics.FromImage(resultBmp)
            pg.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias '抗锯齿
            pg.DrawString(text, font, Brushes.Black, 0, 0)
        End Using
        Return resultBmp
    End Function

VB.NET-GetTextImage

4858.com 54858.com 6

/// <summary>
/// 返回指定矩形区域的屏幕图像
/// </summary>
/// <param name="rect">指定的矩形区域</param>
/// <returns></returns>
public Bitmap GetScreenImage(Rectangle rect)
{
    Bitmap resultBmp = new Bitmap(rect.Width, rect.Height);
    using (Graphics pg = Graphics.FromImage(resultBmp)) {
        pg.CopyFromScreen(rect.X, rect.Y, 0, 0, new Size(rect.Width, rect.Height));
    }
    return resultBmp;
}

C#-GetScreenImage

4858.com 74858.com 8

/// <summary>
/// 返回指定文字生成的位图
/// </summary>
/// <param name="text">文本</param>
/// <param name="font">字体</param>
/// <param name="width">位图宽度</param>
/// <param name="height">位图高度</param>
/// <returns></returns>
public Bitmap GetTextImage(string text, Font font, int width, int height)
{
    Bitmap resultBmp = new Bitmap(width, height);
    using (pg == Graphics.FromImage(resultBmp)) {
        pg.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias;
        //抗锯齿
        pg.DrawString(text, font, Brushes.Black, 0, 0);
    }
    return resultBmp;
}

C#-GetTextImage

准备

  不再是墨迹的简易临摹,程序也能够画出主意感满满的图像。

  IDE:Visual Studio

  Language:VB.NET/C#

  GitHub:ExperDot.AutomaticDrawing

第一节 背景

  背景是画画里映衬主体育赛事物的风貌。

4858.com 9

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

  蓝天、白云和全球,程序最拿手那种颜色单一的涂抹了。

第二节 预处理

  接下来对模板图像进行拍卖,以便于下一步的轨道寻觅。

      二值化

  依赖一个阈值T,大于T的像素群设定为水晶色,小于T的像素群设定为高粱红

  也正是将全方位图像呈现出鲜明的唯有黑和白的视觉效果

4858.com 10

图2-一 全局二值化

 

      细化

*  *将粗线条细化为细线条(线条宽度常常为一像素)

*  *细化算法是为了搜索图像的概貌,对分裂图像的成效不一样

4858.com 11

图2-2 轮廓化

 

4858.com 124858.com 13

''' <summary>
''' 提供对位图图像和颜色的一系列操作的对象
''' </summary>
Public Class ImageProcess
    ''' <summary> 
    ''' 基于RGB根据指定阈值判断两个颜色是否相近
    ''' </summary> 
    Public Function CompareRGB(ByVal Color1 As Color, ByVal Color2 As Color, ByVal Distance As Single) As Boolean
        Dim r As Integer = Int(Color1.R) - Int(Color2.R)
        Dim g As Integer = Int(Color1.G) - Int(Color2.G)
        Dim b As Integer = Int(Color1.B) - Int(Color2.B)
        Dim absDis As Integer = Math.Sqrt(r * r + g * g + b * b)
        If absDis < Distance Then
            Return True
        Else
            Return False
        End If
    End Function
    ''' <summary> 
    ''' 基于HSB根据指定阈值判断两个颜色是否相近
    ''' </summary> 
    Public Function CompareHSB(ByVal Color1 As Color, ByVal Color2 As Color, ByVal Distance As Single) As Boolean
        '向量距离
        'Dim h As Single = (Color1.GetHue - Color2.GetHue) / 360
        'Dim s As Single = Color1.GetSaturation - Color2.GetSaturation
        'Dim b As Single = Color1.GetBrightness - Color2.GetBrightness
        'Dim absDis As Single = Math.Sqrt(h * h + s * s + b * b)
        'If absDis < Distance Then
        '    Return True
        'Else
        '    Return False
        'End If
        '向量夹角
        Dim h1 As Single = Color1.GetHue / 360
        Dim s1 As Single = Color1.GetSaturation
        Dim b1 As Single = Color1.GetBrightness
        Dim h2 As Single = Color2.GetHue / 360
        Dim s2 As Single = Color2.GetSaturation
        Dim b2 As Single = Color2.GetBrightness
        Dim absDis As Single = (h1 * h2 + s1 * s2 + b1 * b2) / (Math.Sqrt(h1 * h1 + s1 * s1 + b1 * b1) * Math.Sqrt(h2 * h2 + s2 * s2 + b2 * b2))
        If absDis > Distance / 5 + 0.8 Then
            Return True
        Else
            Return False
        End If
    End Function
    ''' <summary> 
    ''' 返回指定颜色的中值
    ''' </summary> 
    Public Function gethHD(ByVal color1 As Color)
        Dim HD, r, g, b As Integer
        r = color1.R
        g = color1.G
        b = color1.B
        HD = (r + g + b) / 3
        Return HD
    End Function
    ''' <summary>
    ''' 返回指定位图的颜色数组
    ''' </summary>
    ''' <param name="gBitmap"></param>
    ''' <returns></returns>
    Public Function GetColorArr(ByRef gBitmap As Bitmap) As Color(,)
        Dim TempArr(gBitmap.Width - 1, gBitmap.Height - 1) As Color
        For i = 0 To gBitmap.Width - 1
            For j = 0 To gBitmap.Height - 1
                TempArr(i, j) = gBitmap.GetPixel(i, j)
            Next
        Next
        Return TempArr
    End Function
    ''' <summary>
    ''' 返回指定矩形区域的屏幕图像
    ''' </summary>
    ''' <param name="rect">指定的矩形区域</param>
    ''' <returns></returns>
    Public Function GetScreenImage(ByVal rect As Rectangle) As Bitmap
        Dim resultBmp As New Bitmap(rect.Width, rect.Height)
        Using pg As Graphics = Graphics.FromImage(resultBmp)
            pg.CopyFromScreen(rect.X, rect.Y, 0, 0, New Size(rect.Width, rect.Height))
        End Using
        Return resultBmp
    End Function
    ''' <summary>
    ''' 返回指定文字生成的位图
    ''' </summary>
    ''' <param name="text">文本</param>
    ''' <param name="font">字体</param>
    ''' <param name="width">位图宽度</param>
    ''' <param name="height">位图高度</param>
    ''' <returns></returns>
    Public Function GetTextImage(ByVal text As String, ByVal font As Font, ByVal width As Integer, ByVal height As Integer) As Bitmap
        Dim resultBmp As New Bitmap(width, height)
        Using pg = Graphics.FromImage(resultBmp)
            pg.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias '抗锯齿
            pg.DrawString(text, font, Brushes.Black, 0, 0)
        End Using
        Return resultBmp
    End Function
    ''' <summary>
    ''' 返回指定图位图的二值化图像
    ''' </summary>
    ''' <param name="gBitmap"></param>
    ''' <param name="gSplitNum"></param>
    ''' <returns></returns>
    Public Function GetThresholdImage(ByVal gBitmap As Bitmap, ByVal gSplitNum As Single, Optional IsHSB As Boolean = False) As Bitmap
        Dim ResultBitmap As New Bitmap(gBitmap.Width, gBitmap.Height)
        Dim ColorArr(,) = GetColorArr(gBitmap)
        Dim TempHD As Integer
        Dim IsOverThreshold = Function(ByVal C1 As Color, ByVal gNum As Single)
                                  TempHD = gethHD(C1)
                                  Return (If(IsHSB, (C1.GetHue / 360 + C1.GetSaturation + C1.GetBrightness) / 3 < gNum,
                                  TempHD < gNum))
                              End Function
        For i = 0 To gBitmap.Width - 1
            For j = 0 To gBitmap.Height - 1
                ResultBitmap.SetPixel(i, j, If(IsOverThreshold(ColorArr(i, j), gSplitNum), Color.Black, Color.White))
            Next
        Next

        Return ResultBitmap
    End Function
    ''' <summary>
    ''' 返回指定位图的轮廓图像
    ''' </summary>
    ''' <param name="gBitmap"></param>
    ''' <param name="gDistance"></param>
    ''' <returns></returns>
    Public Function GetOutLineImage(ByVal gBitmap As Bitmap, ByVal gDistance As Single, Optional IsHSB As Boolean = False) As Bitmap
        Dim xArray2() As Short = {0, 1, 0, -1}
        Dim yArray2() As Short = {-1, 0, 1, 0}
        'Dim ResultBitmap As New Bitmap(gBitmap) '在原图的基础上绘图
        Dim ResultBitmap As New Bitmap(gBitmap.Width, gBitmap.Height)
        Dim Color1, Color2 As Color
        Dim CompareColor = Function(ByVal C1 As Color, ByVal C2 As Color, ByVal Distance As Single)
                               Return If(IsHSB,
                               CompareHSB(Color1, Color2, Distance),
                               CompareRGB(Color1, Color2, Distance))
                           End Function
        Dim CompareColorExtra = Function(ByVal C1 As Color, ByVal C2 As Color)
                                    Return If(IsHSB,
                                    Color1.GetBrightness - Color2.GetBrightness > 0,
                                    gethHD(Color1) - gethHD(Color2) > 0)
                                End Function
        Dim ColorArr(,) = GetColorArr(gBitmap)
        For i = 1 To gBitmap.Width - 2
            For j = 1 To gBitmap.Height - 2
                ResultBitmap.SetPixel(i, j, Color.White)
                Color1 = ColorArr(i, j)
                For p = 0 To 3
                    Color2 = ColorArr(i + xArray2(p), j + yArray2(p))
                    If Not CompareColor(Color1, Color2, gDistance) And CompareColorExtra(Color1, Color2) Then
                        ResultBitmap.SetPixel(i, j, Color.Black)
                        ' ResultBitmap.SetPixel(i, j, ColorArr(i, j))
                    End If
                Next
            Next
        Next
        Return ResultBitmap
    End Function
    ''' <summary>
    ''' 返回指定位图的空心图像
    ''' </summary>
    ''' <param name="gBitmap"></param>
    ''' <returns></returns>
    Public Function GetAroundImage(gBitmap As Bitmap)
        Dim ResultBitmap As New Bitmap(gBitmap.Width, gBitmap.Height)
        Dim ImageBolArr(,) As Integer = GetImageBol(gBitmap)
        For i = 0 To gBitmap.Width - 1
            For j = 0 To gBitmap.Height - 1
                If ImageBolArr(i, j) = 1 AndAlso CheckPointAround(ImageBolArr, i, j) = False Then
                    ResultBitmap.SetPixel(i, j, Color.Black)
                Else
                    ResultBitmap.SetPixel(i, j, Color.White)
                End If
            Next
        Next
        Return ResultBitmap
    End Function
    ''' <summary>
    ''' 返回指定位图的反相图像
    ''' </summary>
    ''' <param name="gBitmap"></param>
    ''' <returns></returns>
    Public Function GetInvertImage(gBitmap As Bitmap)
        Dim ResultBitmap As New Bitmap(gBitmap.Width, gBitmap.Height)
        Dim ImageBolArr(,) As Integer = GetImageBol(gBitmap)
        For i = 0 To gBitmap.Width - 1
            For j = 0 To gBitmap.Height - 1
                If ImageBolArr(i, j) = 1 Then
                    ResultBitmap.SetPixel(i, j, Color.White)
                Else
                    ResultBitmap.SetPixel(i, j, Color.Black)
                End If
            Next
        Next
        Return ResultBitmap
    End Function
    ''' <summary>
    ''' 返回指定位图的色块图像
    ''' </summary>
    ''' <param name="gBitmap"></param>
    ''' <returns></returns>
    Public Function GetLumpImage(gBitmap As Bitmap, Optional Range As Integer = 10)
        Dim ResultBitmap As New Bitmap(gBitmap.Width, gBitmap.Height)
        Dim ColorArr(,) = GetColorArr(gBitmap)
        Dim R, G, B As Integer
        For i = 0 To gBitmap.Width - 1
            For j = 0 To gBitmap.Height - 1
                R = Int(ColorArr(i, j).R / Range) * Range
                G = Int(ColorArr(i, j).G / Range) * Range
                B = Int(ColorArr(i, j).B / Range) * Range
                ResultBitmap.SetPixel(i, j, Color.FromArgb(R, G, B))
            Next
        Next
        Return ResultBitmap
    End Function
    ''' <summary>
    ''' 返回指定位图的二值化数据
    ''' </summary>
    ''' <param name="gBitmap"></param>
    ''' <returns></returns>
    Private Function GetImageBol(ByVal gBitmap As Bitmap) As Integer(,)
        Dim ResultArr(gBitmap.Width - 1, gBitmap.Height - 1) As Integer
        For i = 0 To gBitmap.Width - 1
            For j = 0 To gBitmap.Height - 1
                If Not gBitmap.GetPixel(i, j).Equals(Color.FromArgb(255, 255, 255)) Then
                    ResultArr(i, j) = 1
                Else
                    ResultArr(i, j) = 0
                End If
            Next
        Next
        Return ResultArr
    End Function
    ''' <summary>
    ''' 检查一个点是否被包围
    ''' </summary>
    ''' <param name="BolArr"></param>
    ''' <param name="x"></param>
    ''' <param name="y"></param>
    ''' <returns></returns>
    Private Function CheckPointAround(BolArr As Integer(,), ByVal x As Integer, ByVal y As Integer) As Boolean
        If Not (x > 0 And y > 0 And x < BolArr.GetUpperBound(0) And y < BolArr.GetUpperBound(1)) Then Return True
        If BolArr(x - 1, y) = 1 And BolArr(x + 1, y) = 1 And BolArr(x, y - 1) = 1 And BolArr(x, y + 1) = 1 Then
            Return True '当前点为实体内部
        Else
            Return False '当前点为实体边缘
        End If
    End Function
End Class

VB.NET-ImageProcess

4858.com 144858.com 15

using System;
using System.Drawing;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
/// <summary>
/// 提供对位图图像和颜色的一系列操作的对象
/// </summary>
public class ImageProcess
{
    /// <summary> 
    /// 基于RGB根据指定阈值判断两个颜色是否相近
    /// </summary> 
    public bool CompareRGB(Color Color1, Color Color2, float Distance)
    {
        int r = Conversion.Int(Color1.R) - Conversion.Int(Color2.R);
        int g = Conversion.Int(Color1.G) - Conversion.Int(Color2.G);
        int b = Conversion.Int(Color1.B) - Conversion.Int(Color2.B);
        int absDis = Math.Sqrt(r * r + g * g + b * b);
        if (absDis < Distance) {
            return true;
        } else {
            return false;
        }
    }
    /// <summary> 
    /// 基于HSB根据指定阈值判断两个颜色是否相近
    /// </summary> 
    public bool CompareHSB(Color Color1, Color Color2, float Distance)
    {
        //向量距离
        //Dim h As Single = (Color1.GetHue - Color2.GetHue) / 360
        //Dim s As Single = Color1.GetSaturation - Color2.GetSaturation
        //Dim b As Single = Color1.GetBrightness - Color2.GetBrightness
        //Dim absDis As Single = Math.Sqrt(h * h + s * s + b * b)
        //If absDis < Distance Then
        //    Return True
        //Else
        //    Return False
        //End If
        //向量夹角
        float h1 = Color1.GetHue / 360;
        float s1 = Color1.GetSaturation;
        float b1 = Color1.GetBrightness;
        float h2 = Color2.GetHue / 360;
        float s2 = Color2.GetSaturation;
        float b2 = Color2.GetBrightness;
        float absDis = (h1 * h2 + s1 * s2 + b1 * b2) / (Math.Sqrt(h1 * h1 + s1 * s1 + b1 * b1) * Math.Sqrt(h2 * h2 + s2 * s2 + b2 * b2));
        if (absDis > Distance / 5 + 0.8) {
            return true;
        } else {
            return false;
        }
    }
    /// <summary> 
    /// 返回指定颜色的中值
    /// </summary> 
    public object gethHD(Color color1)
    {
        int HD = 0;
        int r = 0;
        int g = 0;
        int b = 0;
        r = color1.R;
        g = color1.G;
        b = color1.B;
        HD = (r + g + b) / 3;
        return HD;
    }
    /// <summary>
    /// 返回指定位图的颜色数组
    /// </summary>
    /// <param name="gBitmap"></param>
    /// <returns></returns>
    public Color[,] GetColorArr(ref Bitmap gBitmap)
    {
        Color[,] TempArr = new Color[gBitmap.Width, gBitmap.Height];
        for (i = 0; i <= gBitmap.Width - 1; i++) {
            for (j = 0; j <= gBitmap.Height - 1; j++) {
                TempArr(i, j) = gBitmap.GetPixel(i, j);
            }
        }
        return TempArr;
    }
    /// <summary>
    /// 返回指定矩形区域的屏幕图像
    /// </summary>
    /// <param name="rect">指定的矩形区域</param>
    /// <returns></returns>
    public Bitmap GetScreenImage(Rectangle rect)
    {
        Bitmap resultBmp = new Bitmap(rect.Width, rect.Height);
        using (Graphics pg = Graphics.FromImage(resultBmp)) {
            pg.CopyFromScreen(rect.X, rect.Y, 0, 0, new Size(rect.Width, rect.Height));
        }
        return resultBmp;
    }
    /// <summary>
    /// 返回指定文字生成的位图
    /// </summary>
    /// <param name="text">文本</param>
    /// <param name="font">字体</param>
    /// <param name="width">位图宽度</param>
    /// <param name="height">位图高度</param>
    /// <returns></returns>
    public Bitmap GetTextImage(string text, Font font, int width, int height)
    {
        Bitmap resultBmp = new Bitmap(width, height);
        using (pg == Graphics.FromImage(resultBmp)) {
            pg.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias;
            //抗锯齿
            pg.DrawString(text, font, Brushes.Black, 0, 0);
        }
        return resultBmp;
    }
    /// <summary>
    /// 返回指定图位图的二值化图像
    /// </summary>
    /// <param name="gBitmap"></param>
    /// <param name="gSplitNum"></param>
    /// <returns></returns>
    public Bitmap GetThresholdImage(Bitmap gBitmap, float gSplitNum, bool IsHSB = false)
    {
        Bitmap ResultBitmap = new Bitmap(gBitmap.Width, gBitmap.Height);
        [,] ColorArr = GetColorArr(ref gBitmap);
        int TempHD = 0;
        dynamic IsOverThreshold = (Color C1, float gNum) =>
        {
            TempHD = gethHD(C1);
            return (IsHSB ? (C1.GetHue / 360 + C1.GetSaturation + C1.GetBrightness) / 3 < gNum : TempHD < gNum);
        };
        for (i = 0; i <= gBitmap.Width - 1; i++) {
            for (j = 0; j <= gBitmap.Height - 1; j++) {
                ResultBitmap.SetPixel(i, j, IsOverThreshold(ColorArr(i, j), gSplitNum) ? Color.Black : Color.White);
            }
        }

        return ResultBitmap;
    }
    /// <summary>
    /// 返回指定位图的轮廓图像
    /// </summary>
    /// <param name="gBitmap"></param>
    /// <param name="gDistance"></param>
    /// <returns></returns>
    public Bitmap GetOutLineImage(Bitmap gBitmap, float gDistance, bool IsHSB = false)
    {
        short[] xArray2 = {
            0,
            1,
            0,
            -1
        };
        short[] yArray2 = {
            -1,
            0,
            1,
            0
        };
        //Dim ResultBitmap As New Bitmap(gBitmap) '在原图的基础上绘图
        Bitmap ResultBitmap = new Bitmap(gBitmap.Width, gBitmap.Height);
        Color Color1 = default(Color);
        Color Color2 = default(Color);
        dynamic CompareColor = (Color C1, Color C2, float Distance) => { return IsHSB ? CompareHSB(Color1, Color2, Distance) : CompareRGB(Color1, Color2, Distance); };
        dynamic CompareColorExtra = (Color C1, Color C2) => { return IsHSB ? Color1.GetBrightness - Color2.GetBrightness > 0 : gethHD(Color1) - gethHD(Color2) > 0; };
        [,] ColorArr = GetColorArr(ref gBitmap);
        for (i = 1; i <= gBitmap.Width - 2; i++) {
            for (j = 1; j <= gBitmap.Height - 2; j++) {
                ResultBitmap.SetPixel(i, j, Color.White);
                Color1 = ColorArr(i, j);
                for (p = 0; p <= 3; p++) {
                    Color2 = ColorArr(i + xArray2[p], j + yArray2[p]);
                    if (!CompareColor(Color1, Color2, gDistance) & CompareColorExtra(Color1, Color2)) {
                        ResultBitmap.SetPixel(i, j, Color.Black);
                        // ResultBitmap.SetPixel(i, j, ColorArr(i, j))
                    }
                }
            }
        }
        return ResultBitmap;
    }
    /// <summary>
    /// 返回指定位图的空心图像
    /// </summary>
    /// <param name="gBitmap"></param>
    /// <returns></returns>
    public object GetAroundImage(Bitmap gBitmap)
    {
        Bitmap ResultBitmap = new Bitmap(gBitmap.Width, gBitmap.Height);
        int[,] ImageBolArr = GetImageBol(gBitmap);
        for (i = 0; i <= gBitmap.Width - 1; i++) {
            for (j = 0; j <= gBitmap.Height - 1; j++) {
                if (ImageBolArr[i, j] == 1 && CheckPointAround(ImageBolArr, i, j) == false) {
                    ResultBitmap.SetPixel(i, j, Color.Black);
                } else {
                    ResultBitmap.SetPixel(i, j, Color.White);
                }
            }
        }
        return ResultBitmap;
    }
    /// <summary>
    /// 返回指定位图的反相图像
    /// </summary>
    /// <param name="gBitmap"></param>
    /// <returns></returns>
    public object GetInvertImage(Bitmap gBitmap)
    {
        Bitmap ResultBitmap = new Bitmap(gBitmap.Width, gBitmap.Height);
        int[,] ImageBolArr = GetImageBol(gBitmap);
        for (i = 0; i <= gBitmap.Width - 1; i++) {
            for (j = 0; j <= gBitmap.Height - 1; j++) {
                if (ImageBolArr[i, j] == 1) {
                    ResultBitmap.SetPixel(i, j, Color.White);
                } else {
                    ResultBitmap.SetPixel(i, j, Color.Black);
                }
            }
        }
        return ResultBitmap;
    }
    /// <summary>
    /// 返回指定位图的色块图像
    /// </summary>
    /// <param name="gBitmap"></param>
    /// <returns></returns>
    public object GetLumpImage(Bitmap gBitmap, int Range = 10)
    {
        Bitmap ResultBitmap = new Bitmap(gBitmap.Width, gBitmap.Height);
        [,] ColorArr = GetColorArr(ref gBitmap);
        int R = 0;
        int G = 0;
        int B = 0;
        for (i = 0; i <= gBitmap.Width - 1; i++) {
            for (j = 0; j <= gBitmap.Height - 1; j++) {
                R = Conversion.Int(ColorArr(i, j).R / Range) * Range;
                G = Conversion.Int(ColorArr(i, j).G / Range) * Range;
                B = Conversion.Int(ColorArr(i, j).B / Range) * Range;
                ResultBitmap.SetPixel(i, j, Color.FromArgb(R, G, B));
            }
        }
        return ResultBitmap;
    }
    /// <summary>
    /// 返回指定位图的二值化数据
    /// </summary>
    /// <param name="gBitmap"></param>
    /// <returns></returns>
    private int[,] GetImageBol(Bitmap gBitmap)
    {
        int[,] ResultArr = new int[gBitmap.Width, gBitmap.Height];
        for (i = 0; i <= gBitmap.Width - 1; i++) {
            for (j = 0; j <= gBitmap.Height - 1; j++) {
                if (!gBitmap.GetPixel(i, j).Equals(Color.FromArgb(255, 255, 255))) {
                    ResultArr[i, j] = 1;
                } else {
                    ResultArr[i, j] = 0;
                }
            }
        }
        return ResultArr;
    }
    /// <summary>
    /// 检查一个点是否被包围
    /// </summary>
    /// <param name="BolArr"></param>
    /// <param name="x"></param>
    /// <param name="y"></param>
    /// <returns></returns>
    private bool CheckPointAround(int[,] BolArr, int x, int y)
    {
        if (!(x > 0 & y > 0 & x < BolArr.GetUpperBound(0) & y < BolArr.GetUpperBound(1)))
            return true;
        if (BolArr[x - 1, y] == 1 & BolArr[x + 1, y] == 1 & BolArr[x, y - 1] == 1 & BolArr[x, y + 1] == 1) {
            return true;
            //当前点为实体内部
        } else {
            return false;
            //当前点为实体边缘
        }
    }
}

C#-ImageProcess

首先节 扫描方式

  1幅画是由一条条线条组成,线条绘制的先后顺序决定着视觉的完整表现效果。

  由内向外,适合全体

4858.com 16

  由左至右,适合文字

4858.com 17

第二节 轮廓

  轮廓是实体的外周或图表的外框。

4858.com 18

图2-2 勾勒人物和时装概况

  现在 AI 要调整笔触大小和颜料,让图像的关键性显现出来。

第三节 循迹

  从非黑即白的像素数量中总计出轨道。

      递归循迹

  首先将图像的二值化数据保存在一个贰维数组里

  程序绘图时仅绘制值为一的成分所对应的职分

  然后查找画笔初始地点,依次检查各类地方,当对应值为一时该点即为源点

  最终递归检查每一个邻居点,同步模拟鼠标操作

      中空轨迹

  只要某像素地方的左右左右岗位均为一即以为该点在实行业内部部

  绘制时跳过该像素即可完成空心(重要用来空心字体的绘图)

4858.com 194858.com 20

''' <summary>
''' 提供由图像循迹生成绘图序列的对象
''' </summary>
Public Class SequenceManager
    ''' <summary>
    ''' 绘制序列的集合
    ''' </summary>
    Public SequenceList As List(Of PointSequence)

    Public Sub New(BolArr(,) As Integer)
        SequenceList = New List(Of PointSequence)
        CalculateSequence(BolArr)
    End Sub
    ''' <summary>
    ''' 创建新的序列
    ''' </summary>
    Private Sub CreateNewSequence()
        SequenceList.Add(New PointSequence)
    End Sub
    ''' <summary>
    ''' 添加新的位置
    ''' </summary>
    Private Sub AddPoint(point As PointF)
        SequenceList.Last.PointList.Add(point)
    End Sub
    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>
    ''' 递归循迹
    ''' </summary>
    Private Sub CheckMove(ByRef BolArr(,) As Integer, ByVal x As Integer, ByVal y As Integer, ByVal StepNum As Integer)
        Application.DoEvents() '处理主线程消息
        If StepNum > 10000 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 PointF(dx, dy))
                    NewStart = False
                Else
                    Me.AddPoint(New PointF(dx, dy))
                End If
                CheckMove(BolArr, dx, dy, StepNum + 1)
                NewStart = True
            End If
        Next
    End Sub
    ''' <summary>
    ''' 计算序列
    ''' </summary>
    Private Sub CalculateSequence(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 = CP.X + R * Math.Cos(Theat)
                Dim dy As Integer = 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 PointF(dx, dy))
                    CheckMove(BolArr, dx, dy, 0)
                    NewStart = True
                End If
            Next
        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

VB.NET-SequenceManager

4858.com 214858.com 22

''' <summary>
''' 表示一条画图曲线的绘制序列
''' </summary>
Public Class PointSequence
    Public PointList As New List(Of PointF)
End Class

VB.NET-PointSequence

4858.com 234858.com 24

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
/// <summary>
/// 提供由图像循迹生成绘图序列的对象
/// </summary>
public class SequenceManager
{
    /// <summary>
    /// 绘制序列的集合
    /// </summary>

    public List<PointSequence> SequenceList;
    public SequenceManager(int[,] BolArr)
    {
        SequenceList = new List<PointSequence>();
        CalculateSequence(BolArr);
    }
    /// <summary>
    /// 创建新的序列
    /// </summary>
    private void CreateNewSequence()
    {
        SequenceList.Add(new PointSequence());
    }
    /// <summary>
    /// 添加新的位置
    /// </summary>
    private void AddPoint(PointF point)
    {
        SequenceList.Last.PointList.Add(point);
    }
    int[] xArray = {
        -1,
        0,
        1,
        1,
        1,
        0,
        -1,
        -1
    };
    int[] yArray = {
        -1,
        -1,
        -1,
        0,
        1,
        1,
        1,
        0
    };
    bool NewStart;
    /// <summary>
    /// 递归循迹
    /// </summary>
    private void CheckMove(ref int[,] BolArr, int x, int y, int StepNum)
    {
        Application.DoEvents();
        //处理主线程消息
        if (StepNum > 10000)
            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 && AroundValue < 8) {
            return;
        }
        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 PointF(dx, dy));
                    NewStart = false;
                } else {
                    this.AddPoint(new PointF(dx, dy));
                }
                CheckMove(ref BolArr, dx, dy, StepNum + 1);
                NewStart = true;
            }
        }
    }
    /// <summary>
    /// 计算序列
    /// </summary>
    private void CalculateSequence(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 = CP.X + R * Math.Cos(Theat);
                int dy = 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 PointF(dx, dy));
                    CheckMove(ref BolArr, dx, dy, 0);
                    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;
    }
}

C#-SequenceManager

4858.com 254858.com 26

using System;
using System.Collections.Generic;
/// <summary>
/// 表示一条画图曲线的绘制序列
/// </summary>
public class PointSequence
{
    public List<PointF> PointList = new List<PointF>();
}

C#-PointSequence

其次节 循迹优化

  前述为线条在哪发轫,同样地,大家还供给掌握线条在哪断开。

  末端断开

4858.com 27

  分叉断开

4858.com 28

第三节 光影

  光影是实体在光的照射下显现出明与暗的涉嫌。

4858.com 29

图三-一 光影提高画面材料

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

第四节 绘图

  最后,调整光标在画板上相继画出线条类别即可。

  光标开关调整

*  *调用user32.dll库下的mouse_event(),它提供综合的光标击键和光标动作模拟

    光标指针移动

  System.Windows.Forms.Cursor.aspx)对象提供对系统光标的拜访

  直接对Cursor.Position赋值就会说了算指针坐标

  也足以调用user3二.dll库下的SetCursorPos()落成模拟光标移动

  Windows画板的局限性

  迄今,你的先后已经足以因此垄断(monopoly)光标在Windows画板上落到实处自动绘图

  但出于画板长时间内不能够响应过多的音讯,导致画图速度无法过快

  同时程序也很难调整画笔的思绪大小与色彩

4858.com 304858.com 31

     Private Declare Sub mouse_event Lib "user32" (ByVal dwFlags As Int32, ByVal dx As Int32, ByVal dy As Int32, ByVal cButtons As Int32, ByVal dwExtraInfo As Int32)
    Private Declare Function SetCursorPos Lib "user32" (ByVal x As Integer, ByVal y As Integer) As Integer
    ''' <summary>
    ''' 模拟鼠标左键按下或弹起
    ''' </summary>
    ''' <param name="dx"></param>
    ''' <param name="dy"></param>
    ''' <param name="type"></param>
    Private Sub MouseDownUp(ByVal dx As Integer, ByVal dy As Integer, ByVal type As Boolean)
        If type Then '按下
            mouse_event(&H2, 0, 0, 0, IntPtr.Zero)
        Else '弹起
            mouse_event(&H4, 0, 0, 0, IntPtr.Zero)
        End If
    End Sub
    ''' <summary>
    ''' 模拟鼠标移动
    ''' </summary>
    ''' <param name="dx"></param>
    ''' <param name="dy"></param>
    Private Sub MouseMove(ByVal dx As Integer, ByVal dy As Integer)
        Cursor.Position = New Point(dx, dy)
    End Sub

VB.NET-MouseControl

4858.com 324858.com 33

using System.Runtime.InteropServices;
        [DllImport("user32")]
        public static extern void mouse_event(int dwFlags, int dx, int dy, int dwData, int dwExtraInfo);
private void MouseDownUp(int dx, int dy, bool type)
{
    //按下
    if (type) {
        mouse_event(0x2, 0, 0, 0, IntPtr.Zero);
    //弹起
    } else {
        mouse_event(0x4, 0, 0, 0, IntPtr.Zero);
    }
}
/// <summary>
/// 模拟鼠标移动
/// </summary>
/// <param name="dx"></param>
/// <param name="dy"></param>
private void MouseMove(int dx, int dy)
{
    Cursor.Position = new Point(dx, dy);
}

C#-MouseControl

其3节 笔触大小

  相比于宽度恒定的画笔,收放自如的思路更能显示线条的振奋。

  头部粗,尾部细

4858.com 34

  两头细,中部粗

4858.com 35

第四节 润色

  润色是加多物体本人及其相近的情调。

4858.com 36

图4-一 画面润色

  这是不可缺少一步,AI需求将遗失的颜色细节补缺回来。

视频

  演示录制:黑白线条画  style=”color: #888888;”>(Bilibili)

  演示录像:古典人物画  style=”color: #888888;”>(Bilibili)

第陆节 笔触色彩

  黑白两色表现过于单壹,而A奥迪Q7GB颜色能够让画面呈现丰盛的色彩。

  Alpha渐变——黑白

4858.com 37

  Alpha渐变——色彩

4858.com 38

第五节 成型

  水到渠成!前边全体的步骤都认为这一步铺垫。

4858.com 39

图伍-一 人物曾经绘声绘色啦

  事实上 AI 只举行这一步也能够画出完整的图像,但并未有过渡会显得生硬。

附录

4858.com ,  后续作品:更美貌的自动绘图程序

  后续小说:小朋友涂鸦遇上先后绘图

  后续文章:次第怎样画动漫美少女

第陆节 示例效果

  首先总结图像的概况,然后分割线条,总结每段线条的思路大小与色彩,依次画出就可以。

  原图

4858.com 40

  绘制

4858.com 41

第六节 算法

  算法思路很简短,总结画笔轨迹后一回遍重绘,认为上是全人类画手的效果。 

  不再是二值化

  因为今后要绘制全彩图像,将图像划分为唯有黑和白的成效已经未有怎么意义,贰值化不再适用

  适用的章程是将 HavalGB
颜色空间划分为多少个颜色子空间,然后千家万户管理一幅图像中属于某些子空间的区域

  电动循迹

  循迹算法未有大的更改,仍是早前博客里贴出的代码

  彩色图像线条很短,能够不再计算点周围的权值用来刹车轨迹

  重绘

  程序先选拔思路非常大、颜色淡的画笔绘制2遍,然后在那基础上日渐减小思绪并深化色彩

  直接依照专门的学问笔触能够二次成型,但会显示突兀和平板,究竟那一个AI不是确实在图谋怎样画一幅图像

4858.com 424858.com 43

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 Function
End Class

''' <summary>
''' 线条扫描方式
''' </summary>
Public Enum ScanMode
    ''' <summary>
    ''' 矩形扫描
    ''' </summary>
    Rect
    ''' <summary>
    ''' 圆形扫描
    ''' </summary>
    Circle
End Enum

VB.NET-SequenceAI

4858.com 444858.com 45

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 Sub
End Class

VB.NET-PointSequence

4858.com 464858.com 47

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

4858.com 484858.com 49

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

视频

  演示录制:黑白线条画  style=”color: #888888;”>(Bilibili)

  演示摄像:古典人物画  style=”color: #888888;”>(Bilibili)

视频

  演示录像:黑白线条画  style=”color: #888888;”>(Bilibili)

  演示录制:掌故人物画  style=”color: #888888;”>(Bilibili)

附录

  早期博客:程序怎么样兑现自动绘图

  后续小说:先后如何画动漫美少女

  创意分享:孩子涂鸦遇上先后绘图

附录

  GitHub:EDGameEngine.AutoDraw

  早期博客:次第如何兑现自动绘图 

  早期博客:更优质的自动绘图程序

  创新意识分享:幼童涂鸦遇上先后绘图 

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 美高梅手机版4858 版权所有