C# winform部署SAM2的onnx模型
【效果演示】【测试环境】vs2019net framework4.8.0opencvsharp4.13.0onnxruntime1.24.3【界面代码】using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using OpenCvSharp; using OpenCvSharp.Extensions; using System.IO; using System.Drawing.Imaging; namespace FIRC { public partial class Form1 : Form { private Mat originalImage; private bool isDragging; private System.Drawing.Point startPoint; private System.Drawing.Rectangle selectionRect; private Bitmap originalBitmap; private OpenCvSharp.Rect roi; private SamInferenceSession samSession; private Mat samMask; private bool isSamInitialized false; Mat displayImage new Mat(); public Form1() { InitializeComponent(); isDragging false; } private void btnLoadImage_Click(object sender, EventArgs e) { OpenFileDialog openFileDialog new OpenFileDialog(); openFileDialog.Filter Image files (*.jpg, *.jpeg, *.png)|*.jpg;*.jpeg;*.png; if (openFileDialog.ShowDialog() DialogResult.OK) { string imagePath openFileDialog.FileName; originalImage Cv2.ImRead(imagePath); if (originalImage.Empty()) { lblStatus.Text 状态图片加载失败; return; } // 转换为Bitmap并显示 originalBitmap BitmapConverter.ToBitmap(originalImage); picOriginal.Image originalBitmap; picRectangle.Image null; picResult.Image null; lblStatus.Text 状态图片加载成功请在图片上绘制矩形; } } private void picOriginal_MouseDown(object sender, MouseEventArgs e) { if (originalImage null || originalBitmap null) return; isDragging true; startPoint e.Location; selectionRect new System.Drawing.Rectangle(startPoint, new System.Drawing.Size(0, 0)); UpdateSelection(); } private void picOriginal_MouseMove(object sender, MouseEventArgs e) { if (!isDragging || originalImage null || originalBitmap null) return; selectionRect new System.Drawing.Rectangle( Math.Min(startPoint.X, e.X), Math.Min(startPoint.Y, e.Y), Math.Abs(e.X - startPoint.X), Math.Abs(e.Y - startPoint.Y) ); UpdateSelection(); } private void picOriginal_MouseUp(object sender, MouseEventArgs e) { if (!isDragging || originalImage null || originalBitmap null) return; isDragging false; UpdateSelection(); // 确保矩形有一定大小 if (selectionRect.Width 10 selectionRect.Height 10) { // 计算实际图像上的矩形坐标 // 考虑图片在PictureBox中的实际显示位置和大小 RectangleF imageRect GetImageDisplayRect(); float scaleX (float)originalImage.Cols / imageRect.Width; float scaleY (float)originalImage.Rows / imageRect.Height; // 计算相对于图片显示区域的坐标 int x (int)((selectionRect.X - imageRect.X) * scaleX); int y (int)((selectionRect.Y - imageRect.Y) * scaleY); int width (int)(selectionRect.Width * scaleX); int height (int)(selectionRect.Height * scaleY); // 确保坐标在图像范围内 x Math.Max(0, x); y Math.Max(0, y); width Math.Min(width, originalImage.Cols - x); height Math.Min(height, originalImage.Rows - y); // 设置ROI roi new OpenCvSharp.Rect(x, y, width, height); // 显示矩形区域 // 截取矩形区域 Mat roiMat new Mat(originalImage, roi); Bitmap roiBitmap BitmapConverter.ToBitmap(roiMat); picRectangle.Image roiBitmap; // 运行SAM分割 RunSamSegmentation(); } } private RectangleF GetImageDisplayRect() { if (originalImage null || originalBitmap null) return RectangleF.Empty; // 计算图片在PictureBox中的实际显示位置和大小 float imageAspectRatio (float)originalImage.Width / originalImage.Height; float pictureBoxAspectRatio (float)picOriginal.Width / picOriginal.Height; float displayWidth, displayHeight, x, y; if (imageAspectRatio pictureBoxAspectRatio) { // 图片比PictureBox更宽按宽度缩放 displayWidth picOriginal.Width; displayHeight displayWidth / imageAspectRatio; x 0; y (picOriginal.Height - displayHeight) / 2; } else { // 图片比PictureBox更高按高度缩放 displayHeight picOriginal.Height; displayWidth displayHeight * imageAspectRatio; x (picOriginal.Width - displayWidth) / 2; y 0; } return new RectangleF(x, y, displayWidth, displayHeight); } private void UpdateSelection() { if (originalBitmap null) return; // 创建一个新的位图避免修改原始位图 Bitmap temp new Bitmap(picOriginal.Width, picOriginal.Height); using (Graphics g Graphics.FromImage(temp)) { // 绘制原始图像考虑缩放和居中 RectangleF imageRect GetImageDisplayRect(); g.DrawImage(originalBitmap, imageRect); // 绘制选择矩形 using (Pen pen new Pen(Color.Red, 2)) { g.DrawRectangle(pen, selectionRect); } } picOriginal.Image temp; } private void ShowRectangleArea() { if (originalImage null || roi.Width 0 || roi.Height 0) return; // 截取矩形区域 Mat roiMat new Mat(originalImage, roi); Bitmap roiBitmap BitmapConverter.ToBitmap(roiMat); picRectangle.Image roiBitmap; } private void RunSamSegmentation() { if (!isSamInitialized || originalImage null || samSession null) { lblStatus.Text 状态SAM模型未初始化或图像未加载; return; } try { lblStatus.Text 状态正在进行SAM分割...; Application.DoEvents(); // 获取SAM输入尺寸 OpenCvSharp.Size inputSize samSession.GetInputSize(); // 编码图像 var encoding samSession.Encode(originalImage); // 创建提示标记使用ROI var marks new ListSamInferenceSession.PromptMark { new SamInferenceSession.PromptMark { Type SamInferenceSession.MarkType.Rectangle, Data new float[] { roi.X, roi.Y, roi.X roi.Width, roi.Y roi.Height }, Label 2 } }; // 运行推理获取掩码 samMask samSession.PredictMasks(encoding, marks); double iou 1.0; // 将掩码调整回原始图像尺寸 Mat resizedMask new Mat(); Cv2.Resize(samMask, resizedMask, new OpenCvSharp.Size(originalImage.Cols, originalImage.Rows)); // 创建结果显示原图掩码叠加 //displayImage originalImage.Clone(); // 创建彩色掩码 Mat colorMask new Mat(originalImage.Size(), MatType.CV_8UC3, new Scalar(0, 0, 255)); Mat maskedColor new Mat(); colorMask.CopyTo(maskedColor, resizedMask); //// 叠加掩码到原图 //Cv2.AddWeighted(displayImage, 1.0, maskedColor, 0.5, 0, displayImage); //// 绘制ROI矩形 //Cv2.Rectangle(displayImage, roi, new Scalar(0, 255, 0), 2); // 显示结果 picResult.Image BitmapConverter.ToBitmap(maskedColor); lblStatus.Text string.Format(状态SAM分割完成 (IOU: {0:F3}), iou); } catch (Exception ex) { lblStatus.Text 状态SAM分割失败 ex.Message; MessageBox.Show(ex.ToString(), 分割错误, MessageBoxButtons.OK, MessageBoxIcon.Error); } } /// summary /// 保存分割结果 /// /summary public void SaveSegmentationResult(string outputPath) { if (samMask null || samMask.Empty()) { throw new Exception(没有可保存的分割结果); } // 将掩码调整回原始图像尺寸 Mat resizedMask new Mat(); Cv2.Resize(samMask, resizedMask, new OpenCvSharp.Size(originalImage.Cols, originalImage.Rows)); // 保存掩码图像 Cv2.ImWrite(outputPath, resizedMask); } /// summary /// 获取分割后的对象带透明背景 /// /summary public Mat GetSegmentedObject() { if (samMask null || samMask.Empty() || originalImage null) { return null; } // 将掩码调整回原始图像尺寸 Mat resizedMask new Mat(); Cv2.Resize(samMask, resizedMask, new OpenCvSharp.Size(originalImage.Cols, originalImage.Rows)); // 创建RGBA输出图像 Mat result new Mat(originalImage.Size(), MatType.CV_8UC4); // 将原图转换为RGBA Mat originalRgba new Mat(); Cv2.CvtColor(originalImage, originalRgba, ColorConversionCodes.BGR2BGRA); // 应用掩码作为alpha通道 for (int i 0; i result.Rows; i) { for (int j 0; j result.Cols; j) { Vec4b pixel originalRgba.AtVec4b(i, j); byte maskValue resizedMask.Atbyte(i, j); result.AtVec4b(i, j) new Vec4b(pixel.Item0, pixel.Item1, pixel.Item2, maskValue); } } return result; } private void Form1_Load(object sender, EventArgs e) { try { // 加载模型 string encoderPath Path.Combine(AppDomain.CurrentDomain.BaseDirectory, models, sam2_hiera_tiny.encoder.onnx); string decoderPath Path.Combine(AppDomain.CurrentDomain.BaseDirectory, models, sam2_hiera_tiny.decoder.onnx); lblStatus.Text 状态正在初始化模型...; // 创建SAM推理会话 samSession new SamInferenceSession(encoderPath, decoderPath, 4); isSamInitialized true; lblStatus.Text 状态模型加载成功; } catch (Exception ex) { lblStatus.Text 状态模型加载失败 ex.Message; // 显示详细错误信息 MessageBox.Show(ex.ToString(), 错误, MessageBoxButtons.OK, MessageBoxIcon.Error); isSamInitialized false; } } } }【使用模型】sam2_hiera_tiny.decoder.onnxsam2_hiera_tiny.encoder.onnx【下载地址】【参考】gthub仓库X-anylabelIng标注工具里面sam2实现代码【注意事项】使用的sam2_hiera_tiny版本进行分割使用CPU推理速度比较快无需安装cudacudnn和带nvidia显卡
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2420066.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!