使用onnxruntime、opencvsharp
onnxruntime利用animegan2 onnx(512x512 体积约8M)训练好的机器学习模型进行本机计算
同时使用opencv(opencvsharp)的L0smooth替代原来的nuget插件包
---
dotnet add package AnimeGANv2_Onnx_Sharp --version 1.0.0
源代码:
songshizhao/AnimeGANv2_Sharp (github.com)
-----------
代码参考:
public class OnnxHelper { private static InferenceSession _session; private static SessionOptions _option; private static List<NamedOnnxValue> container = new List<NamedOnnxValue>(); public static async Task Init() { var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(@"ms-appx:///face_paint_512_v2_0.onnx")); var buffer = await FileIO.ReadBufferAsync(file); _option = new SessionOptions { LogSeverityLevel = OrtLoggingLevel.ORT_LOGGING_LEVEL_ERROR }; _option.AppendExecutionProvider_CPU(0); //_option.AppendExecutionProvider_CoreML(); _session = new InferenceSession(buffer.ToArray(), _option); } public static async Task Init2() { var file = await StorageFile.GetFileFromApplicationUriAsync(new Uri(@"ms-appx:///face_paint_512_v2_0.onnx")); var buffer = await FileIO.ReadBufferAsync(file); _option = new SessionOptions { LogSeverityLevel = OrtLoggingLevel.ORT_LOGGING_LEVEL_ERROR }; _option.AppendExecutionProvider_CPU(0); //_option.AppendExecutionProvider_CoreML(); _session = new InferenceSession(buffer.ToArray(), _option); } private static DenseTensor<float> PreInput(Mat mat) { var mat512 = new Mat(); Cv2.Resize(mat, mat512, new Size(512, 512)); Mat m512 = new Mat(); Cv2.CvtColor(mat512, m512, ColorConversionCodes.BGR2RGB); //输入Tensor DenseTensor<float> input_tensor = new DenseTensor<float>(new[] { 1, 3, 512, 512 }); // 输入Tensor for (int y = 0; y < m512.Height; y++) { for (int x = 0; x < m512.Width; x++) { input_tensor[0, 0, y, x] = (mat512.At<Vec3b>(y, x)[0] / 255f - 0.5f) / 0.5f; input_tensor[0, 1, y, x] = (mat512.At<Vec3b>(y, x)[1] / 255f - 0.5f) / 0.5f; input_tensor[0, 2, y, x] = (mat512.At<Vec3b>(y, x)[2] / 255f - 0.5f) / 0.5f; } } return input_tensor; } public static async Task<Mat> Smooth(Mat sourceMat, double lambda = 2e-2, double kappa = 2.0) { Mat output = new Mat();//sourceMat.Width,sourceMat.Height,MatType.CV_8UC4 sourceMat = sourceMat.CvtColor(ColorConversionCodes.BGRA2BGR, 3); await Task.Run(() => { OpenCvSharp.XImgProc.CvXImgProc.L0Smooth(sourceMat, output, lambda, kappa); }); return output; } // public static Mat Bytes2Mat8UC3(int w, int h, byte[] bytes) { Mat mat = new Mat(h, w, MatType.CV_8UC4, bytes); mat = mat.CvtColor(ColorConversionCodes.BGRA2BGR, 3); return mat; } public static byte[] Mat2Bytes(Mat mat) { return mat.ToBytes(); } public static async Task<Mat> RunB2M(int w, int h, byte[] bytes) { Mat mat = Bytes2Mat8UC3(w, h, bytes); var inputTensor = PreInput(mat);//DenseTensor<float> inputTensor Mat result_mat = new Mat(); await Task.Run(() => { container.Clear(); container.Add(NamedOnnxValue.CreateFromTensor<float>("input_image", inputTensor)); var results = _session.Run(container); var resultArrays = results.ToArray(); var result_tensors = results[0].AsTensor<float>(); var result_array = result_tensors.ToArray(); float[] temp_r = new float[512 * 512]; float[] temp_g = new float[512 * 512]; float[] temp_b = new float[512 * 512]; Array.Copy(result_array, temp_r, 512 * 512); Array.Copy(result_array, 512 * 512, temp_g, 0, 512 * 512); Array.Copy(result_array, 512 * 512 * 2, temp_b, 0, 512 * 512); Mat rmat = new Mat(512, 512, MatType.CV_32FC1, temp_r); Mat gmat = new Mat(512, 512, MatType.CV_32FC1, temp_g); Mat bmat = new Mat(512, 512, MatType.CV_32FC1, temp_b); rmat = (rmat + 1f) * 127.5f; gmat = (gmat + 1f) * 127.5f; bmat = (bmat + 1f) * 127.5f; Cv2.Merge(new Mat[] { rmat, gmat, bmat }, result_mat); }); return result_mat; } public static async Task<byte[]> RunB2B(int w, int h, byte[] bytes) { Mat result_mat = new Mat(); await Task.Run(() => { Mat mat = Bytes2Mat8UC3(w, h, bytes); var inputTensor = PreInput(mat); container.Clear(); container.Add(NamedOnnxValue.CreateFromTensor<float>("input_image", inputTensor)); var results = _session.Run(container); var resultArrays = results.ToArray(); var result_tensors = results[0].AsTensor<float>(); var result_array = result_tensors.ToArray(); float[] temp_r = new float[512 * 512]; float[] temp_g = new float[512 * 512]; float[] temp_b = new float[512 * 512]; Array.Copy(result_array, temp_r, 512 * 512); Array.Copy(result_array, 512 * 512, temp_g, 0, 512 * 512); Array.Copy(result_array, 512 * 512 * 2, temp_b, 0, 512 * 512); Mat rmat = new Mat(512, 512, MatType.CV_32FC1, temp_r); Mat gmat = new Mat(512, 512, MatType.CV_32FC1, temp_g); Mat bmat = new Mat(512, 512, MatType.CV_32FC1, temp_b); rmat = (rmat + 1f) * 127.5f; gmat = (gmat + 1f) * 127.5f; bmat = (bmat + 1f) * 127.5f; Cv2.Merge(new Mat[] { rmat, gmat, bmat }, result_mat); }); return result_mat.ToBytes(); } public static async Task<Mat> RunM2M(Mat mat) { var inputTensor = PreInput(mat);//DenseTensor<float> inputTensor Mat result_mat = new Mat(); await Task.Run(() => { container.Clear(); container.Add(NamedOnnxValue.CreateFromTensor<float>("input_image", inputTensor)); var results = _session.Run(container); var resultArrays = results.ToArray(); var result_tensors = results[0].AsTensor<float>(); var result_array = result_tensors.ToArray(); float[] temp_r = new float[512 * 512]; float[] temp_g = new float[512 * 512]; float[] temp_b = new float[512 * 512]; Array.Copy(result_array, temp_r, 512 * 512); Array.Copy(result_array, 512 * 512, temp_g, 0, 512 * 512); Array.Copy(result_array, 512 * 512 * 2, temp_b, 0, 512 * 512); Mat rmat = new Mat(512, 512, MatType.CV_32FC1, temp_r); Mat gmat = new Mat(512, 512, MatType.CV_32FC1, temp_g); Mat bmat = new Mat(512, 512, MatType.CV_32FC1, temp_b); rmat = (rmat + 1f) * 127.5f; gmat = (gmat + 1f) * 127.5f; bmat = (bmat + 1f) * 127.5f; Cv2.Merge(new Mat[] { rmat, gmat, bmat }, result_mat); }); return result_mat; } }
-----------
点评:
opencv自带L0smooth的功能,可比我自己C#手写的无速度优化版本速度快多了,完全替代了我写的垃圾nuget