声明:本程序代码以国外Jason Antic的DeOldify程序C#代码为基础,做了适应VB.NET程序和语言的变动,免费共享给大家使用。本代码供具有一定VB.NET基础的爱好者学习研究使用,如果想学习基础图像操作知识,请见我的视频课程 《 【VB.NET】二维图形绘制》等系列课程。

我们本节将 DeOldify 里其他的辅助方法都填写完毕,首先在 类代码块内部上方添加上用到的类域变量成员

    Private Shared __Progress As SinglePublic Delegate Sub ProgressDelegate(Percent As Single)Public Shared Event Progress As ProgressDelegatePublic Shared Property Parameters As Dictionary(Of String, Tensor)

接着在类内添加其他方法成员

   Public Shared Function LoadTensor(reader As BinaryReader, ParamArray shape As Integer()) As TensorDim t As New Tensor(shape)Dim n As Integer = t.NumelDim ptr As IntPtr = t.DataFor i As Integer = 0 To n - 1Marshal.StructureToPtr(reader.ReadSingle(), ptr, False)ptr = IntPtr.Add(ptr, Marshal.SizeOf(GetType(Single)))NextReturn tEnd FunctionPublic Shared Function Image2Tensor(bmp As Bitmap) As TensorDim width As Integer = bmp.WidthDim height As Integer = bmp.HeightDim t As New Tensor(3, height, width)Dim ptr As IntPtr = t.DataDim size As Integer = Marshal.SizeOf(GetType(Single))Dim channel2Offset As Integer = height * width * sizeDim channel3Offset As Integer = 2 * height * width * sizeFor y As Integer = 0 To height - 1For x As Integer = 0 To width - 1Dim c As Color = bmp.GetPixel(x, y)Dim l As Double = (CDbl(c.R) + CDbl(c.G) + CDbl(c.B)) / 765.0Marshal.StructureToPtr(CSng((l - 0.485) / 0.229), ptr, False)Marshal.StructureToPtr(CSng((l - 0.456) / 0.224),IntPtr.Add(ptr, channel2Offset), False)Marshal.StructureToPtr(CSng((l - 0.406) / 0.225),IntPtr.Add(ptr, channel3Offset), False)ptr = IntPtr.Add(ptr, size)NextNextReturn tEnd FunctionPublic Shared Function Tensor2Image(t As Tensor) As BitmapDim width As Integer = Marshal.ReadInt32(IntPtr.Add(t.Shape, 2 * Marshal.SizeOf(GetType(Integer))))Dim height As Integer = Marshal.ReadInt32(IntPtr.Add(t.Shape, Marshal.SizeOf(GetType(Integer))))Dim bmp As New Bitmap(width, height)Dim size As Integer = Marshal.SizeOf(GetType(Single))Dim channel2Offset As Integer = height * width * sizeDim channel3Offset As Integer = 2 * height * width * sizeDim ptr As IntPtr = t.DataFor y As Integer = 0 To height - 1For x As Integer = 0 To width - 1Dim rVal As Single = Marshal.PtrToStructure(Of Single)(ptr)Dim gVal As Single = Marshal.PtrToStructure(Of Single)(IntPtr.Add(ptr, channel2Offset))Dim bVal As Single = Marshal.PtrToStructure(Of Single)(IntPtr.Add(ptr, channel3Offset))Dim v As New Vector4(rVal, gVal, bVal, 0)v = v * New Vector4(6.0F) - New Vector4(3.0F)v = v * New Vector4(0.229F, 0.224F, 0.225F, 0) + New Vector4(0.485F, 0.456F, 0.406F, 0)v = Vector4.Clamp(v * 255.0F, Vector4.Zero, New Vector4(255.0F))bmp.SetPixel(x, y, Color.FromArgb(CInt(v.X), CInt(v.Y), CInt(v.Z)))ptr = IntPtr.Add(ptr, size)NextNextReturn bmpEnd FunctionPublic Shared Function Mux(full_size As Bitmap, colorized As Bitmap) As BitmapDim colorized_ As New Bitmap(colorized, full_size.Width, full_size.Height)For y As Integer = 0 To colorized_.Height - 1For x As Integer = 0 To colorized_.Width - 1Dim bwc As Color = full_size.GetPixel(x, y)Dim rc As Color = colorized_.GetPixel(x, y)Dim bwy As Single = 0.299F * bwc.R + 0.587F * bwc.G + 0.114F * bwc.BDim ru As Single = -0.14713F * rc.R - 0.28886F * rc.G + 0.436F * rc.BDim rv As Single = 0.615F * rc.R - 0.51499F * rc.G - 0.10001F * rc.BDim newR As Integer = CInt(Math.Round(Math.Min(Math.Max(bwy + 1.13983738F * rv, 0.0F), 255.0F)))Dim newG As Integer = CInt(Math.Round(Math.Min(Math.Max(bwy - 0.3946517F * ru - 0.5805986F * rv, 0.0F), 255.0F)))Dim newB As Integer = CInt(Math.Round(Math.Min(Math.Max(bwy + 2.03211F * ru, 0.0F), 255.0F)))colorized_.SetPixel(x, y, Color.FromArgb(newR, newG, newB))NextNextReturn colorized_End Function   Public Shared Function Conv2d(x As Tensor, layer As String, ckpt As Dictionary(Of String, Tensor), Optional stride As Integer = 1, Optional padding As Integer = 1) As TensorDim y As Tensor = Functional.Conv2d(x,ckpt(layer & ".weight"),If(ckpt.ContainsKey(layer & ".bias"), ckpt(layer & ".bias"), Nothing),padding, padding, padding, padding,stride, stride, 1, 1, 1)__Progress += 100.0F / 121.0FRaiseEvent Progress(Math.Min(Math.Max(__Progress, 0.0F), 100.0F))Return yEnd FunctionPublic Shared Function BatchNorm2d(x As Tensor, layer As String, ckpt As Dictionary(Of String, Tensor)) As TensorReturn Functional.BatchNorm2d_(x,ckpt(layer & ".running_mean"),ckpt(layer & ".running_var"),ckpt(layer & ".weight"),ckpt(layer & ".bias"))End FunctionPublic Shared Function BasicBlock(x As Tensor, layer As String, ckpt As Dictionary(Of String, Tensor), Optional strided As Boolean = False) As TensorDim [out] As Tensor = Conv2d(x, layer & ".conv1", ckpt, 1, 0)[out] = BatchNorm2d([out], layer & ".bn1", ckpt)[out] = Functional.ReLU_([out])[out] = Conv2d([out], layer & ".conv2", ckpt, If(strided, 2, 1), 1)[out] = BatchNorm2d([out], layer & ".bn2", ckpt)[out] = Functional.ReLU_([out])[out] = Conv2d([out], layer & ".conv3", ckpt, 1, 0)[out] = BatchNorm2d([out], layer & ".bn3", ckpt)Dim outShape0 As Integer = Marshal.ReadInt32([out].Shape)Dim xShape0 As Integer = Marshal.ReadInt32(x.Shape)If (outShape0 <> xShape0) OrElse strided Thenx = BatchNorm2d(Conv2d(x, layer & ".downsample.0", ckpt, If(strided, 2, 1), 0),layer & ".downsample.1", ckpt)End IfReturn Functional.ReLU_(Functional.Plus_([out], x))End FunctionPublic Shared Function MiddleBlock(x As Tensor, layer As String, ckpt As Dictionary(Of String, Tensor)) As TensorReturn BatchNorm2d(Functional.ReLU_(Conv2d(BatchNorm2d(Functional.ReLU_(Conv2d(x, layer & ".0.0", ckpt)),layer & ".0.2", ckpt),layer & ".1.0", ckpt)),layer & ".1.2", ckpt)End FunctionPublic Shared Function CustomPixelShuffle(x As Tensor, layer As String, ckpt As Dictionary(Of String, Tensor)) As TensorReturn Functional.AvgPool2d(Functional.PixelShuffle(Functional.ReLU_(BatchNorm2d(Conv2d(x, layer & ".conv.0", ckpt, padding:=0),layer & ".conv.1", ckpt))),2, 2, 1, 1, 1, 1, 1, 1)End FunctionPublic Shared Function UnetBlockWide(up_in As Tensor, s As Tensor, layer As String, ckpt As Dictionary(Of String, Tensor), Optional self_attentional As Boolean = False) As TensorDim up_out As Tensor = CustomPixelShuffle(up_in, layer & ".shuf", ckpt)Dim sShape1 As Integer = Marshal.ReadInt32(IntPtr.Add(s.Shape, Marshal.SizeOf(GetType(Integer))))Dim sShape2 As Integer = Marshal.ReadInt32(IntPtr.Add(s.Shape, 2 * Marshal.SizeOf(GetType(Integer))))Dim up_outShape1 As Integer = Marshal.ReadInt32(IntPtr.Add(up_out.Shape, Marshal.SizeOf(GetType(Integer))))Dim up_outShape2 As Integer = Marshal.ReadInt32(IntPtr.Add(up_out.Shape, 2 * Marshal.SizeOf(GetType(Integer))))Dim h As Integer = Math.Min(sShape1, up_outShape1)Dim w As Integer = Math.Min(sShape2, up_outShape2)Dim cat_x As Tensor = Functional.ReLU_(Functional.RestrictedCat2d(up_out, BatchNorm2d(s, layer & ".bn", ckpt)))If self_attentional ThenDim bn_output As Tensor = BatchNorm2d(Functional.ReLU_(Conv2d(cat_x, layer & ".conv.0", ckpt)), layer & ".conv.2", ckpt)Return SelfAttention(bn_output, layer & ".conv.3", ckpt)End IfReturn BatchNorm2d(Functional.ReLU_(Conv2d(cat_x, layer & ".conv.0", ckpt)), layer & ".conv.2", ckpt)End FunctionPublic Shared Function SelfAttention(x As Tensor, layer As String, ckpt As Dictionary(Of String, Tensor)) As TensorDim gammaPtr As IntPtr = ckpt(layer & ".gamma").DataDim gamma As Single = Marshal.PtrToStructure(Of Single)(gammaPtr)Dim f As Tensor = Conv2d(x, layer & ".query", ckpt, padding:=0).Flat3d()Dim g As Tensor = Conv2d(x, layer & ".key", ckpt, padding:=0).Flat3d()Dim h As Tensor = Conv2d(x, layer & ".value", ckpt, padding:=0).Flat3d()Dim beta As Tensor = Functional.Softmax2d(Functional.MatMul(f.Transpose2d(), g))Dim xShape1 As Integer = Marshal.ReadInt32(IntPtr.Add(x.Shape, Marshal.SizeOf(GetType(Integer))))Dim xShape2 As Integer = Marshal.ReadInt32(IntPtr.Add(x.Shape, 2 * Marshal.SizeOf(GetType(Integer))))Dim result As Tensor = Functional.MatMul(h, beta)result = Functional.EltwiseMulScalar_(result, gamma)result = result.Unflat3d(xShape1, xShape2)Return Functional.Plus_(result, x)End FunctionPublic Shared Function PixelShuffle(x As Tensor, layer As String, ckpt As Dictionary(Of String, Tensor)) As TensorReturn Functional.AvgPool2d(Functional.ReLU_(Functional.PixelShuffle(Conv2d(x, layer & ".conv.0", ckpt, padding:=0))),2, 2, 1, 1, 1, 1, 1, 1)End FunctionPublic Shared Function ResBlock(x As Tensor, layer As String, ckpt As Dictionary(Of String, Tensor)) As TensorDim [out] As Tensor = Conv2d(x, layer & ".layers.0.0", ckpt)[out] = Functional.ReLU_([out])[out] = Conv2d([out], layer & ".layers.1.0", ckpt)[out] = Functional.ReLU_([out])Return Functional.Plus_([out], x)End Function