你的位置:首页 > ASP.net教程

[ASP.net教程]AR创意分享:儿童涂鸦遇上程序绘图

第一节 临摹

  小明经常临摹同桌小美的画作。

  美术课上,老师表扬了小美的新作。

图1.1 小美的作品《蒙娜·毛虫的微笑》

  临,是照着原作画;摹,是用薄纸张蒙在原作上面画。

第二节 借画

  小明随后借来了小美的画。

  但他觉得这样摹着画甚是无趣。

图2.1 未完成的临摹

  一般地,临摹耐心与纸张透明度成正比。

第三节 涂鸦

  小明认为这只毛虫太孤单了。

  然后,他的涂鸦怪兽就蹦了出来。

图3.1 《蒙娜·毛虫与她的怪兽》

  涂鸦,随意地涂抹色彩与线条。

第四节 黑白

  小美的哥哥和小明是好朋友,他叫大美。

  大美有个AR程序,它可以计算图像的黑与白。

图4.1 黑白版《蒙娜·毛虫的微笑》

 

  黑白阈值划分可以基于RGB颜色空间也可以基于HSV颜色空间。

Public Class ImageProcessClass  ''' <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="gX"></param>  ''' <param name="gY"></param>  ''' <param name="gWidth"></param>  ''' <param name="gHeight"></param>  ''' <returns></returns>  Public Function GetScreenImage(ByVal gX As Integer, ByVal gY As Integer, ByVal gWidth As Integer, ByVal gHeight As Integer) As Bitmap    Dim ResultBitmap As New Bitmap(gWidth, gHeight)    Using pg As Graphics = Graphics.FromImage(ResultBitmap)      pg.CopyFromScreen(gX, gY, 0, 0, New Size(gWidth, gHeight))    End Using    Return ResultBitmap  End Function  ''' <summary>  ''' 返回指定文字生成的位图  ''' </summary>  ''' <param name="gString"></param>  ''' <param name="gFont"></param>  ''' <param name="gWidth"></param>  ''' <param name="gHeight"></param>  ''' <returns></returns>  Public Function GetTextImage(ByVal gString As String, ByVal gFont As Font, ByVal gWidth As Integer, ByVal gHeight As Integer) As Bitmap    Dim ResultBitmap As New Bitmap(gWidth, gHeight)    Using pg = Graphics.FromImage(ResultBitmap)      pg.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias '抗锯齿      pg.DrawString(gString, gFont, Brushes.Black, 0, 0)    End Using    Return ResultBitmap  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 FunctionEnd Class

VB.NET
using Microsoft.VisualBasic;using System;using System.Collections;using System.Collections.Generic;using System.Data;using System.Diagnostics;public class ImageProcessClass{  /// <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="gX"></param>  /// <param name="gY"></param>  /// <param name="gWidth"></param>  /// <param name="gHeight"></param>  /// <returns></returns>  public Bitmap GetScreenImage(int gX, int gY, int gWidth, int gHeight)  {    Bitmap ResultBitmap = new Bitmap(gWidth, gHeight);    using (Graphics pg = Graphics.FromImage(ResultBitmap)) {      pg.CopyFromScreen(gX, gY, 0, 0, new Size(gWidth, gHeight));    }    return ResultBitmap;  }  /// <summary>  /// 返回指定文字生成的位图  /// </summary>  /// <param name="gString"></param>  /// <param name="gFont"></param>  /// <param name="gWidth"></param>  /// <param name="gHeight"></param>  /// <returns></returns>  public Bitmap GetTextImage(string gString, Font gFont, int gWidth, int gHeight)  {    Bitmap ResultBitmap = new Bitmap(gWidth, gHeight);    using (pg == Graphics.FromImage(ResultBitmap)) {      pg.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias;      //抗锯齿      pg.DrawString(gString, gFont, Brushes.Black, 0, 0);    }    return ResultBitmap;  }  /// <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#

第五节 线条

  AR程序还可以计算图像组成的线条。

  参考线条序列,小明就不会不知道如何下笔了。

图5.1 程序实现自动线条

  定义一个SequenceManager类,它用以识别线条、并管理PointSequence类。

Public Class SequenceManagerClass  ''' <summary>  ''' 绘制序列的List  ''' </summary>  Public SequenceList As List(Of PointSequenceClass)  Public Sub New(BolArr(,) As Integer)    SequenceList = New List(Of PointSequenceClass)    CalculateSequence(BolArr)  End Sub  Private Sub CreateNewSequence()    SequenceList.Add(New PointSequenceClass)  End Sub  Private Sub AddPoint(aPoint As PointF)    SequenceList.Last.PointList.Add(aPoint)  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  Private Sub CheckMove(ByRef BolArr(,) As Integer, ByVal x As Integer, ByVal y As Integer, ByVal StepNum As Integer)    Application.DoEvents()    If StepNum > 200 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  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  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 ClassPublic Class PointSequenceClass  Public PointList As New List(Of PointF)End Class

VB.NET
using Microsoft.VisualBasic;using System;using System.Collections;using System.Collections.Generic;using System.Data;using System.Diagnostics;public class SequenceManagerClass{  /// <summary>  /// 绘制序列的List  /// </summary>  public List<PointSequenceClass> SequenceList;  public SequenceManagerClass(int[,] BolArr)  {    SequenceList = new List<PointSequenceClass>();    CalculateSequence(BolArr);  }  private void CreateNewSequence()  {    SequenceList.Add(new PointSequenceClass());  }  private void AddPoint(PointF aPoint)  {    SequenceList.Last.PointList.Add(aPoint);  }  int[] xArray = {    -1,    0,    1,    1,    1,    0,    -1,    -1  };  int[] yArray = {    -1,    -1,    -1,    0,    1,    1,    1,    0  };  bool NewStart;  private void CheckMove(ref int[,] BolArr, int x, int y, int StepNum)  {    Application.DoEvents();    if (StepNum > 200)      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;      }    }  }  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;        }      }    }  }  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;  }}public class PointSequenceClass{  public List<PointF> PointList = new List<PointF>();}

C#

第六节 投影

  最后,AR程序将计算后的图像投影到屏幕上。

  图像与现实影像真实镶嵌,小明就可以照着屏幕临摹。

图6.1 未经PS的AR演示

  事实上,小明若使用沉浸式AR眼镜,他会得到更佳的体验。

附录

  早期博客:程序实现自动绘图

  早期博客:更优秀的绘图程序

  开源链接:ExperDot.AutomaticDrawing