效果
项目
模型信息
sam3_grounding_decoder.onnx
Model Properties
-------------------------
---------------------------------------------------------------
Inputs
-------------------------
name:feat0
tensor:Float[-1, 256, -1, -1]
name:feat1
tensor:Float[1, 256, 144, 144]
name:feat2
tensor:Float[1, 256, 72, 72]
name:vpe2
tensor:Float[1, 256, 72, 72]
name:lang_mask
tensor:Bool[-1, 32]
name:lang_feat
tensor:Float[32, -1, 256]
name:box_coords
tensor:Float[-1, -1, 4]
name:box_labels
tensor:Int64[-1, -1]
name:box_masks
tensor:Bool[-1, -1]
---------------------------------------------------------------
Outputs
-------------------------
name:boxes
tensor:Float[1, 200, 4]
name:scores
tensor:Float[-1, -1, 1]
name:masks
tensor:Float[1, 200, -1, -1]
name:presence
tensor:Float[1, 1]
---------------------------------------------------------------
sam3_grounding_encoder.onnx
Model Properties
-------------------------
---------------------------------------------------------------
Inputs
-------------------------
name:images
tensor:Float[1, 3, 1008, 1008]
---------------------------------------------------------------
Outputs
-------------------------
name:feat0
tensor:Float[1, 256, 288, 288]
name:feat1
tensor:Float[1, 256, 144, 144]
name:feat2
tensor:Float[1, 256, 72, 72]
name:vpe0
tensor:Float[1, 256, 288, 288]
name:vpe1
tensor:Float[1, 256, 144, 144]
name:vpe2
tensor:Float[1, 256, 72, 72]
---------------------------------------------------------------
sam3_language_encoder.onnx
Model Properties
-------------------------
---------------------------------------------------------------
Inputs
-------------------------
name:tokens
tensor:Int64[-1, 32]
---------------------------------------------------------------
Outputs
-------------------------
name:text_attention_mask
tensor:Bool[-1, 32]
name:text_memory
tensor:Float[32, -1, 256]
name:text_embeds
tensor:Float[32, -1, 1024]
---------------------------------------------------------------
代码
using OpenCvSharp;
using OpenCvSharp.Extensions;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
namespace Onnx_Demo
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
string fileFilter = "*.*|*.bmp;*.jpg;*.jpeg;*.tiff;*.tiff;*.png";
string image_path = "";
DateTime dt1 = DateTime.Now;
DateTime dt2 = DateTime.Now;
Mat image;
Sam3GroundingSession groundingSession;
private void button1_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = fileFilter;
if (ofd.ShowDialog() != DialogResult.OK) return;
pictureBox1.Image = null;
image_path = ofd.FileName;
pictureBox1.Image = new Bitmap(image_path);
textBox1.Text = "";
image = new Mat(image_path);
pictureBox3.Image = null;
image = new Mat(image_path);
pictureBox1.Image = new Bitmap(image_path);
textBox1.Text = "图片编码中……";
Application.DoEvents();
// 记录开始时间
DateTime startTime = DateTime.Now;
groundingSession.EncodeImg(image);
// 计算耗时(秒)
TimeSpan elapsed = DateTime.Now - startTime;
double seconds = elapsed.TotalSeconds;
textBox1.Text = $"图片编码完成,耗时 {seconds:F2} 秒";
}
private void Form1_Load(object sender, EventArgs e)
{
string modelDir = "model"; // 存放所有 onnx 和 vocab/merges 文件的目录
groundingSession = new Sam3GroundingSession(modelDir, useGpu: false);
textBox1.Text = "图片编码中……";
Application.DoEvents();
image_path = "test_img/i1.png";
image = new Mat(image_path);
pictureBox1.Image = new Bitmap(image_path);
// 记录开始时间
DateTime startTime = DateTime.Now;
groundingSession.EncodeImg(image);
// 计算耗时(秒)
TimeSpan elapsed = DateTime.Now - startTime;
double seconds = elapsed.TotalSeconds;
textBox1.Text = $"图片编码完成,耗时 {seconds:F2} 秒";
}
SaveFileDialog sdf = new SaveFileDialog();
private void button3_Click(object sender, EventArgs e)
{
if (pictureBox3.Image == null)
{
return;
}
Bitmap output = new Bitmap(pictureBox3.Image);
sdf.Title = "保存";
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";
if (sdf.ShowDialog() == DialogResult.OK)
{
switch (sdf.FilterIndex)
{
case 1:
{
output.Save(sdf.FileName, ImageFormat.Jpeg);
break;
}
case 2:
{
output.Save(sdf.FileName, ImageFormat.Png);
break;
}
case 3:
{
output.Save(sdf.FileName, ImageFormat.Bmp);
break;
}
case 4:
{
output.Save(sdf.FileName, ImageFormat.Emf);
break;
}
case 5:
{
output.Save(sdf.FileName, ImageFormat.Exif);
break;
}
case 6:
{
output.Save(sdf.FileName, ImageFormat.Gif);
break;
}
case 7:
{
output.Save(sdf.FileName, ImageFormat.Icon);
break;
}
case 8:
{
output.Save(sdf.FileName, ImageFormat.Tiff);
break;
}
case 9:
{
output.Save(sdf.FileName, ImageFormat.Wmf);
break;
}
}
MessageBox.Show("保存成功,位置:" + sdf.FileName);
}
}
/// <summary>
/// 在原图上半透明叠加掩码(红色,透明度 0.5)
/// </summary>
private Mat OverlayMask(Mat originalBgr, Mat binaryMask)
{
// 创建彩色覆盖层(红色)
Mat overlay = Mat.Zeros(originalBgr.Size(), MatType.CV_8UC3);
overlay.SetTo(new Scalar(0, 0, 255), binaryMask); // 红色
// 半透明混合
Mat result = new Mat();
Cv2.AddWeighted(originalBgr, 0.6, overlay, 0.4, 0, result);
return result;
}
/// <summary>
/// 将多个分割掩码用随机颜色填充并叠加到原图上
/// </summary>
/// <param name="original">原始 BGR 图像</param>
/// <param name="results">文本预测结果列表</param>
/// <returns>叠加后的图像(Mat 格式)</returns>
private Mat OverlayMasksWithColors(Mat original, List<GroundingResult> results)
{
// 创建彩色叠加层(初始全黑,CV_8UC3)
Mat colorOverlay = Mat.Zeros(original.Size(), MatType.CV_8UC3);
Random rand = new Random();
foreach (var res in results)
{
// 为每个实例生成随机颜色 (BGR)
Scalar color = new Scalar(rand.Next(0, 255), rand.Next(0, 255), rand.Next(0, 255));
// 将掩码区域填充为随机颜色(SetTo 高效)
colorOverlay.SetTo(color, res.Mask);
}
// 半透明混合:原图 60% + 彩色叠加层 40%
Mat blended = new Mat();
Cv2.AddWeighted(original, 0.6, colorOverlay, 0.4, 0, blended);
return blended;
}
private void button5_Click(object sender, EventArgs e)
{
if (image == null) return;
string prompt = textBoxPrompt.Text.Trim(); // 假设存在 textBoxPrompt 输入提示词
if (string.IsNullOrEmpty(prompt))
{
MessageBox.Show("请输入文本提示");
return;
}
button5.Enabled = false;
pictureBox3.Image = null;
textBox1.Text = "";
Application.DoEvents();
// 执行文本预测
// 记录开始时间
DateTime startTime = DateTime.Now;
var results = groundingSession.PredictText(prompt, threshold: 0.5f, maxDetections: 10);
// 计算耗时(秒)
TimeSpan elapsed = DateTime.Now - startTime;
double seconds = elapsed.TotalSeconds;
if (results.Count > 0)
{
// 1. 保存所有掩码到 mask 文件夹
for (int i = 0; i < results.Count; i++)
{
SaveMask(results[i].Mask, $"text_mask_{i}");
}
// 2. 生成彩色叠加效果
using (Mat displayImage = OverlayMasksWithColors(image, results))
{
pictureBox3.Image = BitmapConverter.ToBitmap(displayImage);
}
// 3. 更新状态栏信息
textBox1.Text = $"检测到 {results.Count} 个实例,最高得分: {results.Max(r => r.Score):F2}";
textBox1.Text += $"\r\n图片编码完成,耗时 {seconds:F2} 秒"; ;
}
else
{
textBox1.Text = "未检测到目标";
}
button5.Enabled = true;
}
/// <summary>
/// 保存掩码到文件(自动创建 mask 文件夹)
/// </summary>
private void SaveMask(Mat mask, string prefix)
{
string maskDir = Path.Combine(Application.StartupPath, "mask");
if (!Directory.Exists(maskDir))
Directory.CreateDirectory(maskDir);
string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss_fff");
string fileName = $"{prefix}_{timestamp}.png";
string fullPath = Path.Combine(maskDir, fileName);
Cv2.ImWrite(fullPath, mask);
}
}
}