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

时间: 2024-12-05 00:51:10

AR创意分享:儿童涂鸦遇上程序绘图的相关文章

当微信小程序遇上filter~

在微信小程序的开发过程中,当你想要实现不同页面间的数据绑定,却为此抓耳饶腮时,不妨让微信小程序与filter 来一场完美的邂逅,相信会给你带来别样的惊喜~ 前段时间被安利了一个很实用的公众号-前端早读课,它简洁.大方的页面和方便.实用的功能深深地吸引着我~(^U^)ノ 恰好这段时间学了小程序,就自己仿着写了个前端早读课的小程序. 实现的功能 不同页面间的数据绑定 随机显示数组里的元素 实时显示系统的日期 鼠标点击和页面跳转等基本功能 swiper组件和template样式模板的使用 使用easy

敏捷遇上UML-需求分析及软件设计最佳实践(郑州站 2014-6-7)

邀请函:尊敬的阁下:我们将在郑州为您奉献高端知识大餐,当敏捷遇上UML,会发生怎样的化学作用呢?首席专家张老师将会为您分享需求分析及软件设计方面的最佳实践,帮助您掌握敏捷.UML及两者相结合的实战技巧.时间:2014.06.07(周六),上午9:00-12:00,下午14:00-17:30(时长6.5小时)地点:郑州市畜牧路16号牧业经济学院实验楼B座2518(可乘坐B11.909.962.47路等公交车到老长途汽车北站下车畜牧路向东300米路北)软件知识原创基地www.umlonline.or

当肿瘤遇上VR眼镜,却只能乖乖滚蛋

<滚蛋吧!肿瘤君>由白百何.吴彦祖领衔主演,改编自漫画师熊顿的同名漫画.影片里,患癌女主是年轻的乐天派漫画家,她在人生最艰难的时刻笑对命运.近年来,恶性肿瘤发病率越来越高,人们谈"癌"色变.但是当肿瘤君遇上VR眼镜,却只能乖乖滚蛋. 虚拟现实(VR)已不再是虚无缥缈的概念,更不是戴上头显看看视频.打打游戏那么简单.其实,VR与大部分传统行业进行碰撞,都将产生摧枯拉朽般的变革.今天这个故事讲述的是虚拟现实与传统医疗交汇出的新世界. 肿瘤位置特殊,周围神经密布,切除难度大.戴上

当Spark遇上TensorFlow分布式深度学习框架原理和实践

近年来,机器学习和深度学习不断被炒热,tensorflow 作为谷歌发布的数值计算和神经网络的新框架也获得了诸多关注,spark和tensorflow深度学习框架的结合,使得tensorflow在现有的spark集群上就可以进行深度学习,而不需要为深度学习设置单独的集群,为了深入了解spark遇上tensorflow分布式深度学习框架的原理和实践,飞马网于4月10日晚,邀请到先后就职于百度.腾讯,负责过多个大数据研发工作的李曙鹏老师进行线上直播,主要向我们介绍spark和深度学习的基本原理.sp

当css遇上less

某种程度来讲,css不能称得上程序.虽然它也和其它语言一样,有自己的规范,也需要编码,但它的笨拙实在让我失望.不喜欢css是因为无论怎么优化代码,项目大到一定程序后,都会看上去一团乱.而且有时候一个bug的定位也要花去不少时间.直到我发现了less.突然感慨,css中的jquery大概就是它了. less允许传参数,允许定义变量,可以把层叠的样式组织得较为美观,可以少写许多重复代码--这一切的优势,让我毫不犹豫地要去把它加入接下来的项目. 举个例子: css要这样写: #header h1 {

当VB遇上C++

最近在学习VB.NET 这块的东西,自然而然就会想到VB.NET与VB6是什么关系? 宏观上来讲就是从基于对象变成了完全的面向对象,因此不能简单的说VB.NET是VB6.0的升级版本.在学习VB.NET之前,已经接触过C++和VB,所以在学习VB.NET的时候总能看到他们的影子,那种似曾相识的感觉让我不得不仰天长叹:这VB.NET简直就是混搭版本的程序设计语言啊! 在1991年Visual Basic1.0诞生以前,开发人员不得不使用C++和Windows系统本身的未成形的程序块,即所谓的Win

渗透场景篇--当XSS遇上CSRF

你是否有过这样的经历,你发现了一个xss,但是貌似只能叉自己,输出点只有自己可以看见.这个时候,你会觉得这个xss很鸡肋,当你就此忽略这个漏洞的时候,你可能丢掉一个发出组合技能的机会.    今天我们来介绍一个场景,当xss遇上csrf的时候,是否能打出一套漂亮的组合技能. 实验环境:     ZvulDirll[请用下面我简单修改过的版本]     下载地址:在文章最后面 一.安装:0x00:解压ZVulDrill压缩包,将其放在www目录下,也就是你的网站根目录.0x01.编辑ZVulDri

当数据库遇上云计算 网亿兴云解决方案

数据库遇上云计算 网亿兴云解决方案 [日期:2016-07-21] 来源: 中关村在线  作者: [字体:大 中 小] 人们对数据管理的需求由来已久.1950年,雷明顿兰德公司在"Univac I"计算机上推出了磁带驱动器,每秒可以输入数百条记录.六十年代,计算机开始广泛引用于数据管理,传统的文件系统已经不能满足人们的需要,能够统一管理和共享数据的数据库管理系统应运而生.如今,数据已经不再是简单的储存和管理,基于云的数据库正衍生出越来越多的玩法和应用场景. 数据库遇上云计算 网亿兴云解

当Azure遇上Docker

容器技术现在发展的如火如荼,包括微软也会在下一代操作系统中提供原生支持,个人认为微软的优势在于其拥有成熟的集群工作环境(Nano Server)以及成熟的管理平台(System Center),除此之外还有一系列围绕容器的生态链,比如自动化(PowerShell DSC),比如监控,比如生命周期管理等等.当然目前如果想在Win平台上体验容器的话,除了Docker提供的boot2docker,最"土"的办法就是在Hyper-V里创建一台Linux虚拟机,然后去部署并使用Docker环境.