• AR


    AR

    第一节 临摹

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

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

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

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

    第二节 借画

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

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

    图2.1 未完成的临摹

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

    第三节 涂鸦

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

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

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

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

    第四节 黑白

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

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

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

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

     VB.NET

    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

     C#

    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,
    };
    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程序还可以计算图像组成的线条。

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

    图5.1 程序实现自动线条

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

     VB.NET

    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

     C#

    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,
    };
    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

  • 相关阅读:
    python3 day02 大纲
    python3 练习题 day02
    python3 练习题(购物车)
    python3 练习题(多级菜单)
    python3 day01 大纲
    python3 练习题 day01
    vuex 的基本使用
    jquery中Ajax使用Promise指定成功回调函数
    使用Promise 解决回调地狱
    Promise 概念及操作
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/5522149.html
Copyright © 2020-2023  润新知