• C# PortraitModeFilter (人物图片)背景模糊


    目录

    效果

    模型信息

    项目

    代码

    下载


    效果

    模型信息

    Inputs
    -------------------------
    name:ImageTensor:0
    tensor:UInt8[1, -1, -1, 3]
    ---------------------------------------------------------------

    Outputs
    -------------------------
    name:SemanticPredictions:0
    tensor:Int64[1, -1, -1]
    ---------------------------------------------------------------

    项目

    VS2022

    .net framework 4.8

    OpenCvSharp 4.8

    Microsoft.ML.OnnxRuntime 1.16.2

    代码

    图片缩放

    int oldwidth = image.Cols;
    int oldheight = image.Rows;
    int maxEdge = Math.Max(image.Rows, image.Cols);
    float ratio = 1.0f * modelSize / maxEdge;
    int newHeight = (int)(image.Rows * ratio);
    int newWidth = (int)(image.Cols * ratio);
    Mat resize_image = image.Resize(new OpenCvSharp.Size(newWidth, newHeight));

    创建Tensor

    input_tensor = new DenseTensor(new[] { 1, newHeight, newWidth, 3 });

    for (int y = 0; y < resize_image.Height; y++)
    {
        for (int x = 0; x < resize_image.Width; x++)
        {
            input_tensor[0, y, x, 2] = resize_image.At(y, x)[0];
            input_tensor[0, y, x, 1] = resize_image.At(y, x)[1];
            input_tensor[0, y, x, 0] = resize_image.At(y, x)[2];
        }
    }

    1. using Microsoft.ML.OnnxRuntime;
    2. using Microsoft.ML.OnnxRuntime.Tensors;
    3. using OpenCvSharp;
    4. using System;
    5. using System.Collections.Generic;
    6. using System.Drawing;
    7. using System.Drawing.Imaging;
    8. using System.Linq;
    9. using System.Windows.Forms;
    10. using UMapx.Core;
    11. using UMapx.Imaging;
    12. namespace PortraitModeFilter_模糊背景
    13. {
    14. public partial class frmMain : Form
    15. {
    16. public frmMain()
    17. {
    18. InitializeComponent();
    19. }
    20. string fileFilter = "*.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png";
    21. string image_path = "";
    22. string startupPath;
    23. DateTime dt1 = DateTime.Now;
    24. DateTime dt2 = DateTime.Now;
    25. string model_path;
    26. Mat image;
    27. Bitmap src;
    28. Bitmap mask;
    29. int modelSize = 512;
    30. SessionOptions options;
    31. InferenceSession onnx_session;
    32. Tensor<byte> input_tensor;
    33. List<NamedOnnxValue> input_ontainer;
    34. IDisposableReadOnlyCollection<DisposableNamedOnnxValue> result_infer;
    35. DisposableNamedOnnxValue[] results_onnxvalue;
    36. Tensor<long> result_tensors;
    37. long[] result_array;
    38. double strength = 1;// 01
    39. OpenFileDialog ofd;
    40. private void button1_Click(object sender, EventArgs e)
    41. {
    42. if (ofd.ShowDialog() != DialogResult.OK) return;
    43. pictureBox1.Image = null;
    44. image_path = ofd.FileName;
    45. src = new Bitmap(image_path);
    46. pictureBox1.Image = src;
    47. textBox1.Text = "";
    48. image = new Mat(image_path);
    49. pictureBox2.Image = null;
    50. trackBar1.Enabled = false;
    51. }
    52. private void Form2_Load(object sender, EventArgs e)
    53. {
    54. trackBar1.Enabled = false;
    55. startupPath = Application.StartupPath;
    56. ofd = new OpenFileDialog();
    57. ofd.Filter = fileFilter;
    58. model_path = startupPath + "\\deeplabv3_mnv2_pascal_train_aug.onnx";
    59. //创建输出会话,用于输出模型读取信息
    60. options = new SessionOptions();
    61. options.LogSeverityLevel = OrtLoggingLevel.ORT_LOGGING_LEVEL_INFO;
    62. // 设置为CPU上运行
    63. options.AppendExecutionProvider_CPU(0);
    64. // 创建推理模型类,读取本地模型文件
    65. onnx_session = new InferenceSession(model_path, options);
    66. // 创建输入容器
    67. input_ontainer = new List<NamedOnnxValue>();
    68. // 创建输入容器
    69. input_ontainer = new List<NamedOnnxValue>();
    70. }
    71. private void button2_Click(object sender, EventArgs e)
    72. {
    73. if (image_path == "")
    74. {
    75. return;
    76. }
    77. textBox1.Text = "生成中……";
    78. pictureBox2.Image = null;
    79. Application.DoEvents();
    80. //缩放图片大小
    81. int oldwidth = image.Cols;
    82. int oldheight = image.Rows;
    83. int maxEdge = Math.Max(image.Rows, image.Cols);
    84. float ratio = 1.0f * modelSize / maxEdge;
    85. int newHeight = (int)(image.Rows * ratio);
    86. int newWidth = (int)(image.Cols * ratio);
    87. Mat resize_image = image.Resize(new OpenCvSharp.Size(newWidth, newHeight));
    88. input_tensor = new DenseTensor<byte>(new[] { 1, newHeight, newWidth, 3 });
    89. // 输入Tensor
    90. for (int y = 0; y < resize_image.Height; y++)
    91. {
    92. for (int x = 0; x < resize_image.Width; x++)
    93. {
    94. input_tensor[0, y, x, 2] = resize_image.At<Vec3b>(y, x)[0];
    95. input_tensor[0, y, x, 1] = resize_image.At<Vec3b>(y, x)[1];
    96. input_tensor[0, y, x, 0] = resize_image.At<Vec3b>(y, x)[2];
    97. }
    98. }
    99. //input_tensor 放入一个输入参数的容器,并指定名称
    100. input_ontainer.Add(NamedOnnxValue.CreateFromTensor(onnx_session.InputNames[0].ToString(), input_tensor));
    101. dt1 = DateTime.Now;
    102. //运行 Inference 并获取结果
    103. result_infer = onnx_session.Run(input_ontainer);
    104. dt2 = DateTime.Now;
    105. //将输出结果转为DisposableNamedOnnxValue数组
    106. results_onnxvalue = result_infer.ToArray();
    107. //读取第一个节点输出并转为Tensor数据
    108. result_tensors = results_onnxvalue[0].AsTensor<Int64>();
    109. result_array = result_tensors.ToArray();
    110. //得到掩码图
    111. mask = SegmentationMap(result_array, newWidth, newHeight);
    112. mask = new Bitmap(mask, new System.Drawing.Size(oldwidth, oldheight));
    113. trackBar1.Enabled = true;
    114. //模糊背景
    115. pictureBox2.Image = Filter(src, mask);
    116. textBox1.Text = "推理耗时:" + (dt2 - dt1).TotalMilliseconds + "ms";
    117. }
    118. /// <summary>
    119. /// Converts an RGB tensor array to a color image.
    120. /// </summary>
    121. /// <param name="tensor">RGBA tensor array</param>
    122. /// <param name="width">Bitmap width</param>
    123. /// <param name="height">Bitmap height</param>
    124. public unsafe Bitmap SegmentationMap(long[] tensor, int width, int height)
    125. {
    126. Bitmap Data = new Bitmap(width, height);
    127. BitmapData bmData = Data.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
    128. int stride = bmData.Stride;
    129. byte* p = (byte*)bmData.Scan0.ToPointer();
    130. int pos = 0;
    131. for (int j = 0; j < height; j++)
    132. {
    133. int k, jstride = j * stride;
    134. for (int i = 0; i < width; i++, pos++)
    135. {
    136. k = jstride + i * 3;
    137. var z = (tensor[pos] == 15) ? (byte)255 : (byte)0;
    138. // rgb
    139. p[k + 2] = z;
    140. p[k + 1] = z;
    141. p[k + 0] = z;
    142. }
    143. }
    144. Data.UnlockBits(bmData);
    145. return Data;
    146. }
    147. private void button3_Click(object sender, EventArgs e)
    148. {
    149. if (pictureBox2.Image == null)
    150. {
    151. return;
    152. }
    153. Bitmap output = new Bitmap(pictureBox2.Image);
    154. var sdf = new SaveFileDialog();
    155. sdf.Title = "保存";
    156. sdf.Filter = "Images (*.jpg)|*.jpg|Images (*.png)|*.png|Images (*.bmp)|*.bmp|Images (*.emf)|*.emf|Images (*.exif)|*.exif|Images (*.gif)|*.gif|Images (*.ico)|*.ico|Images (*.tiff)|*.tiff|Images (*.wmf)|*.wmf";
    157. if (sdf.ShowDialog() == DialogResult.OK)
    158. {
    159. switch (sdf.FilterIndex)
    160. {
    161. case 1:
    162. {
    163. output.Save(sdf.FileName, ImageFormat.Jpeg);
    164. break;
    165. }
    166. case 2:
    167. {
    168. output.Save(sdf.FileName, ImageFormat.Png);
    169. break;
    170. }
    171. case 3:
    172. {
    173. output.Save(sdf.FileName, ImageFormat.Bmp);
    174. break;
    175. }
    176. case 4:
    177. {
    178. output.Save(sdf.FileName, ImageFormat.Emf);
    179. break;
    180. }
    181. case 5:
    182. {
    183. output.Save(sdf.FileName, ImageFormat.Exif);
    184. break;
    185. }
    186. case 6:
    187. {
    188. output.Save(sdf.FileName, ImageFormat.Gif);
    189. break;
    190. }
    191. case 7:
    192. {
    193. output.Save(sdf.FileName, ImageFormat.Icon);
    194. break;
    195. }
    196. case 8:
    197. {
    198. output.Save(sdf.FileName, ImageFormat.Tiff);
    199. break;
    200. }
    201. case 9:
    202. {
    203. output.Save(sdf.FileName, ImageFormat.Wmf);
    204. break;
    205. }
    206. }
    207. MessageBox.Show("保存成功,位置:" + sdf.FileName);
    208. }
    209. }
    210. private void trackBar1_Scroll(object sender, EventArgs e)
    211. {
    212. strength = trackBar1.Value / 100.0;
    213. label1.Text = $"Strenght: {strength}";
    214. pictureBox2.Image = Filter(src, mask);
    215. }
    216. BoxBlur _boxBlur = new BoxBlur();
    217. AlphaChannelFilter _alphaChannelFilter = new AlphaChannelFilter();
    218. Merge _merge = new Merge(0, 0, 255);
    219. Bitmap Filter(Bitmap image, Bitmap mask)
    220. {
    221. int radius = (int)(strength * 2 * ((Math.Max(image.Height, image.Width) / 100) + 1));
    222. // deep person lab
    223. var alphaMask = (Bitmap)src.Clone();
    224. var portrait = (Bitmap)src.Clone();
    225. var segmentantionMask = (Bitmap)mask.Clone();
    226. // gaussian blur approximation
    227. _boxBlur.Size = new SizeInt(radius, radius);
    228. _boxBlur.Apply(portrait);
    229. _boxBlur.Apply(segmentantionMask);
    230. _boxBlur.Size = new SizeInt(radius / 2, radius / 2);
    231. _boxBlur.Apply(portrait);
    232. _boxBlur.Apply(segmentantionMask);
    233. // merging images
    234. _alphaChannelFilter.Apply(alphaMask, segmentantionMask);
    235. _merge.Apply(portrait, alphaMask);
    236. alphaMask.Dispose();
    237. segmentantionMask.Dispose();
    238. return portrait;
    239. }
    240. }
    241. }

    下载

    可执行程序exe下载

    源码下载

  • 相关阅读:
    matlab做神经网络的步骤,用matlab实现神经网络
    【C语言刷LeetCode】453. 最小操作次数使数组元素相等(M)
    win11右键菜单改回win10教程(亲测可用-全流程截图)
    18.ROS编程:ROS中的时间c++
    bat备份mssql数据库,可设置服务器 ip等相关信息,和备份路径
    从20s优化到500ms,我用了这三招
    IF 19.865代谢组学高分文章,非靶标代谢流助力揭示18SrRNA中m6A控制肝癌机制!
    ACGAN
    redis的雪崩、穿透、击穿解析
    IonQ联合GE Research证实:量子计算在风险聚合上有巨大潜力
  • 原文地址:https://blog.csdn.net/lw112190/article/details/133831461