/// <summary> /// This function reads the output probabilities from finalLayer to CPU, sorts them and gets the label with heighest probability /// </summary> /// <param name="finalLayer">output image of the network this has probabilities of each digit</param> /// <returns>Guess of the network as to what the digit is as uint</returns> public uint GetLabel(MPSImage finalLayer) { // even though we have 10 labels outputed the MTLTexture format used is RGBAFloat16 thus 3 slices will have 3*4 = 12 outputs var resultHalfArray = Enumerable.Repeat((ushort)6, 12).ToArray(); var resultHalfArrayHandle = GCHandle.Alloc(resultHalfArray, GCHandleType.Pinned); var resultHalfArrayPtr = resultHalfArrayHandle.AddrOfPinnedObject(); var resultFloatArray = Enumerable.Repeat(0.3f, 10).ToArray(); var resultFloatArrayHandle = GCHandle.Alloc(resultFloatArray, GCHandleType.Pinned); var resultFloatArrayPtr = resultFloatArrayHandle.AddrOfPinnedObject(); for (uint i = 0; i <= 2; i++) { finalLayer.Texture.GetBytes(resultHalfArrayPtr + 4 * (int)i * sizeof(ushort), sizeof(ushort) * 1 * 4, sizeof(ushort) * 1 * 1 * 4, new MTLRegion(new MTLOrigin(0, 0, 0), new MTLSize(1, 1, 1)), 0, i); } // we use vImage to convert our data to float16, Metal GPUs use float16 and swift float is 32-bit var fullResultVImagebuf = new vImageBuffer { Data = resultFloatArrayPtr, Height = 1, Width = 10, BytesPerRow = 10 * 4 }; var halfResultVImagebuf = new vImageBuffer { Data = resultHalfArrayPtr, Height = 1, Width = 10, BytesPerRow = 10 * 2 }; if (Planar16FtoPlanarF(ref halfResultVImagebuf, ref fullResultVImagebuf, 0) != vImageError.NoError) { Console.WriteLine("Error in vImage"); } // poll all labels for probability and choose the one with max probability to return float max = 0f; uint mostProbableDigit = 10; for (uint i = 0; i <= 9; i++) { if (max < resultFloatArray [i]) { max = resultFloatArray [i]; mostProbableDigit = i; } } resultHalfArrayHandle.Free(); resultFloatArrayHandle.Free(); return(mostProbableDigit); }
public unsafe static UIImage ApplyBlur(UIImage image, float blurRadius, UIColor tintColor, float saturationDeltaFactor, UIImage maskImage) { if (image.Size.Width < 1 || image.Size.Height < 1) { Debug.WriteLine(@"*** error: invalid size: ({0} x {1}). Both dimensions must be >= 1: {2}", image.Size.Width, image.Size.Height, image); return(null); } if (image.CGImage == null) { Debug.WriteLine(@"*** error: image must be backed by a CGImage: {0}", image); return(null); } if (maskImage != null && maskImage.CGImage == null) { Debug.WriteLine(@"*** error: maskImage must be backed by a CGImage: {0}", maskImage); return(null); } var imageRect = new RectangleF(PointF.Empty, image.Size); var effectImage = image; bool hasBlur = blurRadius > float.Epsilon; bool hasSaturationChange = Math.Abs(saturationDeltaFactor - 1) > float.Epsilon; if (hasBlur || hasSaturationChange) { UIGraphics.BeginImageContextWithOptions(image.Size, false, UIScreen.MainScreen.Scale); var contextIn = UIGraphics.GetCurrentContext(); contextIn.ScaleCTM(1.0f, -1.0f); contextIn.TranslateCTM(0, -image.Size.Height); contextIn.DrawImage(imageRect, image.CGImage); var effectInContext = contextIn.AsBitmapContext() as CGBitmapContext; var effectInBuffer = new vImageBuffer() { Data = effectInContext.Data, Width = effectInContext.Width, Height = effectInContext.Height, BytesPerRow = effectInContext.BytesPerRow }; UIGraphics.BeginImageContextWithOptions(image.Size, false, UIScreen.MainScreen.Scale); var effectOutContext = UIGraphics.GetCurrentContext().AsBitmapContext() as CGBitmapContext; var effectOutBuffer = new vImageBuffer() { Data = effectOutContext.Data, Width = effectOutContext.Width, Height = effectOutContext.Height, BytesPerRow = effectOutContext.BytesPerRow }; if (hasBlur) { var inputRadius = blurRadius * UIScreen.MainScreen.Scale; uint radius = (uint)(Math.Floor(inputRadius * 3 * Math.Sqrt(2 * Math.PI) / 4 + 0.5)); if ((radius % 2) != 1) { radius += 1; } vImage.BoxConvolveARGB8888(ref effectInBuffer, ref effectOutBuffer, IntPtr.Zero, 0, 0, radius, radius, Pixel8888.Zero, vImageFlags.EdgeExtend); vImage.BoxConvolveARGB8888(ref effectOutBuffer, ref effectInBuffer, IntPtr.Zero, 0, 0, radius, radius, Pixel8888.Zero, vImageFlags.EdgeExtend); vImage.BoxConvolveARGB8888(ref effectInBuffer, ref effectOutBuffer, IntPtr.Zero, 0, 0, radius, radius, Pixel8888.Zero, vImageFlags.EdgeExtend); } bool effectImageBuffersAreSwapped = false; if (hasSaturationChange) { var s = saturationDeltaFactor; var floatingPointSaturationMatrix = new float [] { 0.0722f + 0.9278f * s, 0.0722f - 0.0722f * s, 0.0722f - 0.0722f * s, 0, 0.7152f - 0.7152f * s, 0.7152f + 0.2848f * s, 0.7152f - 0.7152f * s, 0, 0.2126f - 0.2126f * s, 0.2126f - 0.2126f * s, 0.2126f + 0.7873f * s, 0, 0, 0, 0, 1, }; const int divisor = 256; var saturationMatrix = new short [floatingPointSaturationMatrix.Length]; for (int i = 0; i < saturationMatrix.Length; i++) { saturationMatrix [i] = (short)Math.Round(floatingPointSaturationMatrix [i] * divisor); } if (hasBlur) { vImage.MatrixMultiplyARGB8888(ref effectOutBuffer, ref effectInBuffer, saturationMatrix, divisor, null, null, vImageFlags.NoFlags); effectImageBuffersAreSwapped = true; } else { vImage.MatrixMultiplyARGB8888(ref effectInBuffer, ref effectOutBuffer, saturationMatrix, divisor, null, null, vImageFlags.NoFlags); } } if (!effectImageBuffersAreSwapped) { effectImage = UIGraphics.GetImageFromCurrentImageContext(); } UIGraphics.EndImageContext(); if (effectImageBuffersAreSwapped) { effectImage = UIGraphics.GetImageFromCurrentImageContext(); } UIGraphics.EndImageContext(); } // Setup up output context UIGraphics.BeginImageContextWithOptions(image.Size, false, UIScreen.MainScreen.Scale); var outputContext = UIGraphics.GetCurrentContext(); outputContext.ScaleCTM(1, -1); outputContext.TranslateCTM(0, -image.Size.Height); // Draw base image if (hasBlur) { outputContext.SaveState(); if (maskImage != null) { outputContext.ClipToMask(imageRect, maskImage.CGImage); } outputContext.DrawImage(imageRect, effectImage.CGImage); outputContext.RestoreState(); } if (tintColor != null) { outputContext.SaveState(); outputContext.SetFillColor(tintColor.CGColor); outputContext.FillRect(imageRect); outputContext.RestoreState(); } var outputImage = UIGraphics.GetImageFromCurrentImageContext(); UIGraphics.EndImageContext(); return(outputImage); }
public unsafe static UIImage ApplyBlur (UIImage image, float blurRadius, UIColor tintColor, float saturationDeltaFactor, UIImage maskImage) { if (image.Size.Width < 1 || image.Size.Height < 1) { Debug.WriteLine (@"*** error: invalid size: ({0} x {1}). Both dimensions must be >= 1: {2}", image.Size.Width, image.Size.Height, image); return null; } if (image.CGImage == null) { Debug.WriteLine (@"*** error: image must be backed by a CGImage: {0}", image); return null; } if (maskImage != null && maskImage.CGImage == null) { Debug.WriteLine (@"*** error: maskImage must be backed by a CGImage: {0}", maskImage); return null; } var imageRect = new RectangleF (PointF.Empty, image.Size); var effectImage = image; bool hasBlur = blurRadius > float.Epsilon; bool hasSaturationChange = Math.Abs (saturationDeltaFactor - 1) > float.Epsilon; if (hasBlur || hasSaturationChange) { UIGraphics.BeginImageContextWithOptions (image.Size, false, UIScreen.MainScreen.Scale); var contextIn = UIGraphics.GetCurrentContext (); contextIn.ScaleCTM (1.0f, -1.0f); contextIn.TranslateCTM (0, -image.Size.Height); contextIn.DrawImage (imageRect, image.CGImage); var effectInContext = contextIn.AsBitmapContext () as CGBitmapContext; var effectInBuffer = new vImageBuffer () { Data = effectInContext.Data, Width = effectInContext.Width, Height = effectInContext.Height, BytesPerRow = effectInContext.BytesPerRow }; UIGraphics.BeginImageContextWithOptions (image.Size, false, UIScreen.MainScreen.Scale); var effectOutContext = UIGraphics.GetCurrentContext ().AsBitmapContext () as CGBitmapContext; var effectOutBuffer = new vImageBuffer () { Data = effectOutContext.Data, Width = effectOutContext.Width, Height = effectOutContext.Height, BytesPerRow = effectOutContext.BytesPerRow }; if (hasBlur) { var inputRadius = blurRadius * UIScreen.MainScreen.Scale; uint radius = (uint)(Math.Floor (inputRadius * 3 * Math.Sqrt (2 * Math.PI) / 4 + 0.5)); if ((radius % 2) != 1) radius += 1; vImage.BoxConvolveARGB8888 (ref effectInBuffer, ref effectOutBuffer, IntPtr.Zero, 0, 0, radius, radius, Pixel8888.Zero, vImageFlags.EdgeExtend); vImage.BoxConvolveARGB8888 (ref effectOutBuffer, ref effectInBuffer, IntPtr.Zero, 0, 0, radius, radius, Pixel8888.Zero, vImageFlags.EdgeExtend); vImage.BoxConvolveARGB8888 (ref effectInBuffer, ref effectOutBuffer, IntPtr.Zero, 0, 0, radius, radius, Pixel8888.Zero, vImageFlags.EdgeExtend); } bool effectImageBuffersAreSwapped = false; if (hasSaturationChange) { var s = saturationDeltaFactor; var floatingPointSaturationMatrix = new float [] { 0.0722f + 0.9278f * s, 0.0722f - 0.0722f * s, 0.0722f - 0.0722f * s, 0, 0.7152f - 0.7152f * s, 0.7152f + 0.2848f * s, 0.7152f - 0.7152f * s, 0, 0.2126f - 0.2126f * s, 0.2126f - 0.2126f * s, 0.2126f + 0.7873f * s, 0, 0, 0, 0, 1, }; const int divisor = 256; var saturationMatrix = new short [floatingPointSaturationMatrix.Length]; for (int i = 0; i < saturationMatrix.Length; i++) saturationMatrix [i] = (short)Math.Round (floatingPointSaturationMatrix [i] * divisor); if (hasBlur) { vImage.MatrixMultiplyARGB8888 (ref effectOutBuffer, ref effectInBuffer, saturationMatrix, divisor, null, null, vImageFlags.NoFlags); effectImageBuffersAreSwapped = true; } else vImage.MatrixMultiplyARGB8888 (ref effectInBuffer, ref effectOutBuffer, saturationMatrix, divisor, null, null, vImageFlags.NoFlags); } if (!effectImageBuffersAreSwapped) effectImage = UIGraphics.GetImageFromCurrentImageContext (); UIGraphics.EndImageContext (); if (effectImageBuffersAreSwapped) effectImage = UIGraphics.GetImageFromCurrentImageContext (); UIGraphics.EndImageContext (); } // Setup up output context UIGraphics.BeginImageContextWithOptions (image.Size, false, UIScreen.MainScreen.Scale); var outputContext = UIGraphics.GetCurrentContext (); outputContext.ScaleCTM (1, -1); outputContext.TranslateCTM (0, -image.Size.Height); // Draw base image if (hasBlur) { outputContext.SaveState (); if (maskImage != null) outputContext.ClipToMask (imageRect, maskImage.CGImage); outputContext.DrawImage (imageRect, effectImage.CGImage); outputContext.RestoreState (); } if (tintColor != null) { outputContext.SaveState (); outputContext.SetFillColor (tintColor.CGColor); outputContext.FillRect (imageRect); outputContext.RestoreState (); } var outputImage = UIGraphics.GetImageFromCurrentImageContext (); UIGraphics.EndImageContext (); return outputImage; }
unsafe public static vImageError Planar16FtoPlanarF(ref vImageBuffer src, ref vImageBuffer dest, vImageFlags flags) { return((vImageError)(long)vImageConvert_Planar16FtoPlanarF(ref src, ref dest, flags)); }
extern static nint vImageConvert_Planar16FtoPlanarF(ref vImageBuffer src, ref vImageBuffer dest, vImageFlags flags);
/// <summary> /// Internal method to create a blurred image since this has to run on the main thread. /// </summary> /// <returns>The blurred image.</returns> /// <param name="image">Image to be blurred.</param> /// <param name="blurRadius">Blur radius.</param> /// <remarks> /// Originally from: https://github.com/xamarin/ios-samples/blob/master/UIImageEffects/UIImageEffects.cs /// </remarks> private static UIImage InternalCreateBlurredImage(UIImage image, float blurRadius) { var imageRect = new CGRect(CGPoint.Empty, image.Size); var effectImage = image; UIGraphics.BeginImageContextWithOptions(image.Size, false, UIScreen.MainScreen.Scale); var contextIn = UIGraphics.GetCurrentContext(); contextIn.ScaleCTM(1.0f, -1.0f); contextIn.TranslateCTM(0, -image.Size.Height); contextIn.DrawImage(imageRect, image.CGImage); var effectInContext = contextIn.AsBitmapContext() as CGBitmapContext; var effectInBuffer = new vImageBuffer() { Data = effectInContext.Data, Width = ( int )effectInContext.Width, Height = ( int )effectInContext.Height, BytesPerRow = ( int )effectInContext.BytesPerRow }; UIGraphics.BeginImageContextWithOptions(image.Size, false, UIScreen.MainScreen.Scale); var effectOutContext = UIGraphics.GetCurrentContext().AsBitmapContext() as CGBitmapContext; var effectOutBuffer = new vImageBuffer() { Data = effectOutContext.Data, Width = ( int )effectOutContext.Width, Height = ( int )effectOutContext.Height, BytesPerRow = ( int )effectOutContext.BytesPerRow }; var inputRadius = blurRadius * UIScreen.MainScreen.Scale / 2.0f; uint radius = ( uint )(Math.Floor(inputRadius * 3 * Math.Sqrt(2 * Math.PI) / 4 + 0.5)); if ((radius % 2) != 1) { radius += 1; } vImage.BoxConvolveARGB8888(ref effectInBuffer, ref effectOutBuffer, IntPtr.Zero, 0, 0, radius, radius, Pixel8888.Zero, vImageFlags.EdgeExtend); vImage.BoxConvolveARGB8888(ref effectOutBuffer, ref effectInBuffer, IntPtr.Zero, 0, 0, radius, radius, Pixel8888.Zero, vImageFlags.EdgeExtend); vImage.BoxConvolveARGB8888(ref effectInBuffer, ref effectOutBuffer, IntPtr.Zero, 0, 0, radius, radius, Pixel8888.Zero, vImageFlags.EdgeExtend); effectImage = UIGraphics.GetImageFromCurrentImageContext(); UIGraphics.EndImageContext(); UIGraphics.EndImageContext(); // Setup up output context UIGraphics.BeginImageContextWithOptions(image.Size, false, UIScreen.MainScreen.Scale); var outputContext = UIGraphics.GetCurrentContext(); outputContext.ScaleCTM(1, -1); outputContext.TranslateCTM(0, -image.Size.Height); // Draw base image outputContext.SaveState(); outputContext.DrawImage(imageRect, effectImage.CGImage); outputContext.RestoreState(); var outputImage = UIGraphics.GetImageFromCurrentImageContext(); UIGraphics.EndImageContext(); return(outputImage); }
/// <summary> /// Applies the blur with radius. /// </summary> /// <returns>The blur with radius.</returns> /// <param name="target">Target.</param> /// <param name="blurRadius">Blur radius.</param> /// <param name="tintColor">Tint color.</param> /// <param name="saturationDeltaFactor">Saturation delta factor.</param> /// <param name="maskImage">Mask image.</param> public static UIImage ApplyBlurWithRadius(this UIImage target, nfloat blurRadius, UIColor tintColor, nfloat saturationDeltaFactor, UIImage maskImage) { // Check pre-conditions. if (target.Size.Width < 1 || target.Size.Height < 1) { throw new Exception(String.Format(@"*** error: invalid size: (%.2 x %.2f). Both dimensions must be >= 1: %@", target.Size.Width, target.Size.Height, target)); } if (target.CGImage == null) { throw new Exception(String.Format(@"*** error: image must be backed by a CGImage: %@", target)); } if (maskImage != null && maskImage.CGImage == null) { throw new Exception(String.Format(@"*** error: maskImage must be backed by a CGImage: %@", maskImage)); } // var imageRect = new CGRect(CGPoint.Empty, target.Size); var effectImage = target; // bool hasBlur = blurRadius > float.Epsilon; bool hasSaturationChange = Math.Abs(saturationDeltaFactor - 1d) > float.Epsilon; if (hasBlur || hasSaturationChange) { UIGraphics.BeginImageContextWithOptions(target.Size, false, UIScreen.MainScreen.Scale); var effectInContext = UIGraphics.GetCurrentContext(); effectInContext.ScaleCTM(1.0f, -1.0f); effectInContext.TranslateCTM(0, -target.Size.Height); effectInContext.DrawImage(imageRect, target.CGImage); var gctx = effectInContext.AsBitmapContext(); vImageBuffer effectInBuffer = new vImageBuffer(); effectInBuffer.Data = gctx.Data; effectInBuffer.Width = (int)gctx.Width; effectInBuffer.Height = (int)gctx.Height; effectInBuffer.BytesPerRow = (int)gctx.BytesPerRow; UIGraphics.BeginImageContextWithOptions(target.Size, false, UIScreen.MainScreen.Scale); var effectOutContext = UIGraphics.GetCurrentContext(); var gctxOut = effectOutContext.AsBitmapContext(); vImageBuffer effectOutBuffer = new vImageBuffer(); effectOutBuffer.Data = gctxOut.Data; effectOutBuffer.Width = (int)gctxOut.Width; effectOutBuffer.Height = (int)gctxOut.Height; effectOutBuffer.BytesPerRow = (int)gctxOut.BytesPerRow; if (hasBlur) { // A description of how to compute the box kernel width from the Gaussian // radius (aka standard deviation) appears in the SVG spec: // http://www.w3.org/TR/SVG/filters.html#feGaussianBlurElement // // For larger values of 's' (s >= 2.0), an approximation can be used: Three // successive box-blurs build a piece-wise quadratic convolution kernel, which // approximates the Gaussian kernel to within roughly 3%. // // let d = floor(s * 3*sqrt(2*pi)/4 + 0.5) // // ... if d is odd, use three box-blurs of size 'd', centered on the output pixel. // var inputRadius = blurRadius * UIScreen.MainScreen.Scale; var radius = (uint)Math.Floor(inputRadius * 3f * Math.Sqrt(2 * Math.PI) / 4 + 0.5); if (radius % 2 != 1) { radius += 1; // force radius to be odd so that the three box-blur methodology works. } vImage.BoxConvolveARGB8888(ref effectInBuffer, ref effectOutBuffer, IntPtr.Zero, 0, 0, radius, radius, Pixel8888.Zero, vImageFlags.EdgeExtend); vImage.BoxConvolveARGB8888(ref effectOutBuffer, ref effectInBuffer, IntPtr.Zero, 0, 0, radius, radius, Pixel8888.Zero, vImageFlags.EdgeExtend); vImage.BoxConvolveARGB8888(ref effectInBuffer, ref effectOutBuffer, IntPtr.Zero, 0, 0, radius, radius, Pixel8888.Zero, vImageFlags.EdgeExtend); } bool effectImageBuffersAreSwapped = false; if (hasSaturationChange) { var s = saturationDeltaFactor; var floatingPointSaturationMatrix = new nfloat[] { 0.0722f + 0.9278f * s, 0.0722f - 0.0722f * s, 0.0722f - 0.0722f * s, 0f, 0.7152f - 0.7152f * s, 0.7152f + 0.2848f * s, 0.7152f - 0.7152f * s, 0f, 0.2126f - 0.2126f * s, 0.2126f - 0.2126f * s, 0.2126f + 0.7873f * s, 0f, 0f, 0f, 0f, 1f, }; var divisor = 256; var matrixSize = floatingPointSaturationMatrix.Length / sizeof(float); var saturationMatrix = new short[matrixSize]; for (int i = 0; i < matrixSize; ++i) { saturationMatrix[i] = (short)Math.Round(floatingPointSaturationMatrix[i] * divisor); } if (hasBlur) { vImage.MatrixMultiplyARGB8888(ref effectOutBuffer, ref effectInBuffer, saturationMatrix, divisor, null, null, vImageFlags.NoFlags); effectImageBuffersAreSwapped = true; } else { vImage.MatrixMultiplyARGB8888(ref effectInBuffer, ref effectOutBuffer, saturationMatrix, divisor, null, null, vImageFlags.NoFlags); } } if (!effectImageBuffersAreSwapped) { effectImage = UIGraphics.GetImageFromCurrentImageContext(); } UIGraphics.EndImageContext(); if (effectImageBuffersAreSwapped) { effectImage = UIGraphics.GetImageFromCurrentImageContext(); } UIGraphics.EndImageContext(); } // Set up output context. UIGraphics.BeginImageContextWithOptions(target.Size, false, UIScreen.MainScreen.Scale); var outputContext = UIGraphics.GetCurrentContext(); outputContext.ScaleCTM(1.0f, -1.0f); outputContext.TranslateCTM(0, -target.Size.Height); // Draw base image. outputContext.DrawImage(imageRect, target.CGImage); // Draw effect image. if (hasBlur) { outputContext.SaveState(); if (maskImage != null) { outputContext.ClipToMask(imageRect, maskImage.CGImage); } outputContext.DrawImage(imageRect, effectImage.CGImage); outputContext.RestoreState(); } // Add in color tint. if (tintColor != null) { outputContext.SaveState(); outputContext.SetFillColor(tintColor.CGColor); outputContext.FillRect(imageRect); outputContext.RestoreState(); } UIImage outputImage = UIGraphics.GetImageFromCurrentImageContext(); UIGraphics.EndImageContext(); // return(outputImage); }
unsafe public static vImageError Planar16FtoPlanarF (ref vImageBuffer src, ref vImageBuffer dest, vImageFlags flags) { return (vImageError)(long)vImageConvert_Planar16FtoPlanarF (ref src, ref dest, flags); }
extern static nint vImageConvert_Planar16FtoPlanarF (ref vImageBuffer src, ref vImageBuffer dest, vImageFlags flags);
/// <summary> /// This function reads the output probabilities from finalLayer to CPU, sorts them and gets the label with heighest probability /// </summary> /// <param name="finalLayer">output image of the network this has probabilities of each digit</param> /// <returns>Guess of the network as to what the digit is as uint</returns> public uint GetLabel (MPSImage finalLayer) { // even though we have 10 labels outputed the MTLTexture format used is RGBAFloat16 thus 3 slices will have 3*4 = 12 outputs var resultHalfArray = Enumerable.Repeat ((ushort)6, 12).ToArray (); var resultHalfArrayHandle = GCHandle.Alloc (resultHalfArray, GCHandleType.Pinned); var resultHalfArrayPtr = resultHalfArrayHandle.AddrOfPinnedObject (); var resultFloatArray = Enumerable.Repeat (0.3f, 10).ToArray (); var resultFloatArrayHandle = GCHandle.Alloc (resultFloatArray, GCHandleType.Pinned); var resultFloatArrayPtr = resultFloatArrayHandle.AddrOfPinnedObject (); for (uint i = 0; i <= 2; i++) { finalLayer.Texture.GetBytes (resultHalfArrayPtr + 4 * (int)i * sizeof (ushort), sizeof (ushort) * 1 * 4, sizeof (ushort) * 1 * 1 * 4, new MTLRegion (new MTLOrigin (0, 0, 0), new MTLSize (1, 1, 1)), 0, i); } // we use vImage to convert our data to float16, Metal GPUs use float16 and swift float is 32-bit var fullResultVImagebuf = new vImageBuffer { Data = resultFloatArrayPtr, Height = 1, Width = 10, BytesPerRow = 10 * 4 }; var halfResultVImagebuf = new vImageBuffer { Data = resultHalfArrayPtr, Height = 1, Width = 10, BytesPerRow = 10 * 2 }; if (Planar16FtoPlanarF (ref halfResultVImagebuf, ref fullResultVImagebuf, 0) != vImageError.NoError) Console.WriteLine ("Error in vImage"); // poll all labels for probability and choose the one with max probability to return float max = 0f; uint mostProbableDigit = 10; for (uint i = 0; i <= 9; i++) { if (max < resultFloatArray [i]) { max = resultFloatArray [i]; mostProbableDigit = i; } } resultHalfArrayHandle.Free (); resultFloatArrayHandle.Free (); return mostProbableDigit; }