
C# 相机Burst模式图像采集:使用相机内存配合OpenCvSharp和Halcon实现短时间的高速采集的方法
- [C# 相机Burst模式图像采集:使用相机内存配合OpenCvSharp和Halcon实现短时间的高速采集的方法](# 相机Burst模式图像采集:使用相机内存配合OpenCvSharp和Halcon实现短时间的高速采集的方法)
- 一、Burst模式到底是什么?
- 二、什么时候该用Burst?
- [三、怎么配置 Burst 模式?](#三、怎么配置 Burst 模式?)
-
- [Basler(pylon .NET API)](#Basler(pylon .NET API))
- [堡盟(BGAPI SDK)](#堡盟(BGAPI SDK))
- [海康(MVS SDK)](#海康(MVS SDK))
- 四、拿到缓存图像之后怎么处理?
-
- 生产者-消费者队列架构
- [OpenCvSharp 处理思路(零拷贝 + 批量处理)](#OpenCvSharp 处理思路(零拷贝 + 批量处理))
- [Halcon 处理思路(原生算子 + HDevEngine 集成)](#Halcon 处理思路(原生算子 + HDevEngine 集成))
- 性能对比与选型建议
- 五、几个容易踩的坑
- 六、什么时候该用,什么时候别用
- 七、核心优势
- 八、行业应用
- 九、选型建议速查
- 十、总结
C# 相机Burst模式图像采集:使用相机内存配合OpenCvSharp和Halcon实现短时间的高速采集的方法
做飞拍项目的时候,经常碰到一种情况:产品一瞬间过去了,相机拍到了,但千兆网带宽不够,图像传不出来,下一帧又来了,直接丢帧。后来换了带Burst模式的相机,问题才解决。
一、Burst模式到底是什么?
简单说就是先存后传。
普通模式下,相机拍到一帧就往电脑传一帧。千兆网一秒最多传100多MB,高分辨率高帧率一超,数据就在网口排队,直接丢帧。
Burst模式不一样。收到触发之后,相机不管你传不传得出去,先把一连串图像高速往自己内部内存里塞。塞完了,再从内存往外慢慢传给你。
相当于给相机装了个"临时仓库",先猛拍存起来,再慢慢往外搬。拍的时候不卡你速度,搬的时候不丢你数据。
内部缓存有多大?
不同品牌差异挺大。堡盟QX系列自带2GB图像内存,全分辨率下能缓存169张1200万像素的图。更高端的型号甚至有8GB内存。Basler的ace 2系列也支持高速Burst模式,可以绕过GigE的数据限制。
说白了就是:接口带宽不够,相机内存来凑。
二、什么时候该用Burst?
最典型的场景是高速飞拍。产品在传送带上嗖一下过去,曝光时间只有几十微秒。一帧拍完了,下一帧还不知道什么时候来。Burst模式拍完一批慢慢传,不影响下一批采集。
另一个场景是多相机同时触发。几台相机同时咔嚓一下,每台都往电脑传大图,千兆网瞬间塞满。Burst模式先把图存在各自相机里,再排队往外传,网络压力分散了。
如果相机持续30fps不停拍,Burst模式帮不上忙------内部缓存很快满,满了就只能等传输,最终还是被接口带宽卡住。Burst适合的是"短时间高速抓拍,然后慢慢传"的场景。
以下是丰富后的完整内容,适合发布到 CSDN:
三、怎么配置 Burst 模式?
Basler(pylon .NET API)
Basler 的 Burst 模式分两种:
| 模式 | 特点 | 适用场景 |
|---|---|---|
| Standard 模式 | 快速连拍,帧率略低,连拍间隔短 | 一般高速检测,需要较高 Duty Cycle |
| HighSpeed 模式 | 帧率拉到最高,每组连拍后有恢复间隔 | 极高速瞬态捕捉,如爆炸、冲击测试 |
csharp
using Basler.Pylon;
public class BaslerBurstConfig
{
/// <summary>
/// 配置 Basler 相机 Burst 模式(HighSpeed)
/// </summary>
public void ConfigureBurstMode(Camera camera, int burstFrameCount = 50)
{
// 1. 选择触发源为 Burst 起始触发
camera.Parameters[PLCamera.TriggerSelector].SetValue(
PLCamera.TriggerSelector.FrameBurstStart);
// 2. 开启触发模式
camera.Parameters[PLCamera.TriggerMode].SetValue(
PLCamera.TriggerMode.On);
// 3. 选择高速 Burst 模式(Standard 或 HighSpeed)
camera.Parameters[PLCamera.BslAcquisitionBurstMode].SetValue(
PLCamera.BslAcquisitionBurstModeEnum.HighSpeed);
// 4. 设置每次连拍帧数(相机内部缓存容量决定上限)
camera.Parameters[PLCamera.AcquisitionBurstFrameCount].SetValue(burstFrameCount);
// 5. 设置触发源(硬触发推荐 Line1,软触发用 Software)
camera.Parameters[PLCamera.TriggerSource].SetValue(
PLCamera.TriggerSource.Line1);
// 6. 可选:设置触发极性
camera.Parameters[PLCamera.TriggerActivation].SetValue(
PLCamera.TriggerActivation.RisingEdge);
Console.WriteLine($"Burst 模式已配置:每次触发连拍 {burstFrameCount} 帧");
}
/// <summary>
/// 开始采集并注册回调
/// </summary>
public void StartBurstAcquisition(Camera camera, int totalTriggerCount)
{
// 配置采集模式为 MultiFrame(总帧数 = 触发次数 × 每次 Burst 帧数)
int totalFrames = totalTriggerCount *
(int)camera.Parameters[PLCamera.AcquisitionBurstFrameCount].GetValue();
camera.Parameters[PLCamera.AcquisitionMode].SetValue(
PLCamera.AcquisitionMode.MultiFrame);
camera.Parameters[PLCamera.AcquisitionFrameCount].SetValue(totalFrames);
// 注册图像到达回调
camera.StreamGrabber.ImageGrabbed += OnImageGrabbed;
// 开始采集
camera.StreamGrabber.Start(totalFrames);
}
private void OnImageGrabbed(object sender, ImageGrabbedEventArgs e)
{
if (e.GrabResult.GrabSucceeded)
{
// 获取图像数据指针和参数
IntPtr buffer = e.GrabResult.GetBuffer();
int width = e.GrabResult.Width;
int height = e.GrabResult.Height;
PixelType pixelType = e.GrabResult.PixelType;
// 送入处理队列(非阻塞)
_imageQueue.Enqueue(new RawImageData
{
Buffer = buffer,
Width = width,
Height = height,
PixelType = pixelType,
Timestamp = e.GrabResult.TimeStamp
});
}
}
}
/// <summary>
/// 原始图像数据结构
/// </summary>
public class RawImageData
{
public IntPtr Buffer { get; set; }
public int Width { get; set; }
public int Height { get; set; }
public PixelType PixelType { get; set; }
public long Timestamp { get; set; }
}
关键注意点 :配置完
TriggerMode之后,每触发一次,相机就连拍 50 帧存在内部缓存里。如果相机缓存不足(如 200MB),而 50 帧 12MP 图像约 600MB,则必须边拍边取,不能等全部拍完再取。
堡盟(BGAPI SDK)
堡盟 QX 系列相机内置 2GB 高速内存 ,通过 MemoryMode 参数控制内存行为,这是其 Burst 模式的核心优势:
| MemoryMode 取值 | 说明 |
|---|---|
Off |
关闭内存缓存,实时传输 |
Active |
内存激活,用于帧缓冲 |
Burst |
连拍模式,触发后高速写入内存 |
Config |
配置模式,设置内存分区参数 |
csharp
using Baumer.BGAPI;
public class BaumerBurstConfig
{
private BGAPI.Device _curDevice;
/// <summary>
/// 配置堡盟 QX 系列 Burst 模式
/// </summary>
public void ConfigureBurstMode(int blockCount = 680)
{
// 1. 进入内存配置模式(必须先切到 Config 才能改参数)
_curDevice.RemoteNodeList["MemoryMode"].Value = "Config";
// 2. 设置分区模式:Once = 一次性填满后停止,Circular = 循环覆盖
_curDevice.RemoteNodeList["MemoryPartMode"].Value = "Once";
// 3. 设置缓存块数(QX 系列 2GB 内存,12MP 约可存 680 张)
// 计算公式:BlockCount = 总内存(Bytes) / (宽 × 高 × 像素深度)
_curDevice.RemoteNodeList["MemoryPartBlocks"].Value = blockCount.ToString();
// 4. 启用 Burst 模式
_curDevice.RemoteNodeList["MemoryMode"].Value = "Burst";
// 5. 配置触发(硬触发或软触发)
_curDevice.RemoteNodeList["TriggerMode"].Value = "On";
_curDevice.RemoteNodeList["TriggerSource"].Value = "Line0";
Console.WriteLine($"堡盟 Burst 模式已配置:缓存 {blockCount} 张图像");
}
/// <summary>
/// 从内存批量读取图像(Burst 拍完后执行)
/// </summary>
public void ReadBurstImagesFromMemory()
{
// 切到 Active 模式开始读取
_curDevice.RemoteNodeList["MemoryMode"].Value = "Active";
// 获取实际存储的图像数量
int storedCount = int.Parse(_curDevice.RemoteNodeList["MemoryPartBlocksFilled"].Value);
for (int i = 0; i < storedCount; i++)
{
// 设置读取索引
_curDevice.RemoteNodeList["MemoryReadIndex"].Value = i.ToString();
// 取图
BGAPI.Image image = _curDevice.GetImage(1000); // 1秒超时
if (image != null)
{
IntPtr buffer = image.Buffer;
int width = image.Width;
int height = image.Height;
// 送入处理队列
ProcessImage(buffer, width, height);
image.Release();
}
}
// 读取完成后重置
_curDevice.RemoteNodeList["MemoryMode"].Value = "Burst";
}
}
堡盟特色 :2GB 内置内存允许先全部拍完再慢慢取图,适合触发后无法实时处理的场景(如野外高速测试、无 PC 的独立采集)。
海康(MVS SDK)
海康 MVS SDK 中 Burst 功能叫触发帧计数 (AcquisitionBurstFrameCount),配合触发模式使用:
csharp
using MvCamCtrl.NET;
public class HikBurstConfig
{
private MyCamera _camera;
private MyCamera.MV_CC_DEVICE_INFO _deviceInfo;
/// <summary>
/// 配置海康相机 Burst 模式
/// </summary>
public int ConfigureBurstMode(uint burstFrameCount = 50)
{
int nRet;
// 1. 设置采集模式为 MultiFrame
nRet = _camera.MV_CC_SetEnumValue_NET("AcquisitionMode",
(uint)MyCamera.MV_CAM_ACQUISITION_MODE.MV_ACQ_MODE_MultiFrame);
if (MyCamera.MV_OK != nRet) return nRet;
// 2. 设置触发帧数(Burst 数量)
nRet = _camera.MV_CC_SetIntValue_NET("AcquisitionBurstFrameCount", burstFrameCount);
if (MyCamera.MV_OK != nRet) return nRet;
// 3. 开启触发模式
nRet = _camera.MV_CC_SetEnumValue_NET("TriggerMode",
(uint)MyCamera.MV_CAM_TRIGGER_MODE.MV_TRIGGER_MODE_ON);
if (MyCamera.MV_OK != nRet) return nRet;
// 4. 设置触发源(软触发或硬触发)
nRet = _camera.MV_CC_SetEnumValue_NET("TriggerSource",
(uint)MyCamera.MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_SOFTWARE);
if (MyCamera.MV_OK != nRet) return nRet;
// 5. 设置总帧数(触发次数 × Burst 帧数)
uint totalFrames = burstFrameCount * 10; // 计划触发 10 次
nRet = _camera.MV_CC_SetIntValue_NET("AcquisitionFrameCount", totalFrames);
Console.WriteLine($"海康 Burst 模式已配置:每次触发 {burstFrameCount} 帧");
return nRet;
}
/// <summary>
/// 执行软触发一次,连拍 50 张
/// </summary>
public int TriggerSoftwareBurst()
{
return _camera.MV_CC_SetCommandValue_NET("TriggerSoftware");
}
/// <summary>
/// 注册图像回调(取图)
/// </summary>
public int RegisterImageCallback(cbOutputExdelegate callback)
{
// 设置回调函数,Burst 模式下会连续触发回调
return _camera.MV_CC_RegisterImageCallBackEx_NET(callback, IntPtr.Zero);
}
}
海康注意点 :触发一次后连续出图,此时系统必须维持稳定的处理流水线。如果处理速度跟不上出图速度,SDK 内部缓冲区会溢出导致丢帧。建议配合大缓冲区 + 生产者-消费者队列使用。
四、拿到缓存图像之后怎么处理?
Burst 模式拍完一批图存在相机内部(或 SDK 缓冲区),应用程序需要持续从缓冲区取图。关键是不能阻塞取图线程,否则相机缓存满后会丢帧或停止采集。
生产者-消费者队列架构
csharp
using System.Collections.Concurrent;
using System.Threading;
/// <summary>
/// 线程安全的图像处理队列
/// </summary>
public class ImageProcessingPipeline : IDisposable
{
private readonly ConcurrentQueue<RawImageData> _imageQueue = new();
private readonly CancellationTokenSource _cts = new();
private Thread _consumerThread;
private int _processedCount = 0;
private int _droppedCount = 0;
// 队列长度限制(防止内存无限增长)
private const int MAX_QUEUE_SIZE = 100;
public void Start()
{
_consumerThread = new Thread(ConsumerLoop);
_consumerThread.IsBackground = true;
_consumerThread.Start();
}
/// <summary>
/// 生产者:相机回调中调用,快速入队
/// </summary>
public bool EnqueueImage(RawImageData image)
{
if (_imageQueue.Count >= MAX_QUEUE_SIZE)
{
// 队列满,丢弃最旧帧或当前帧(根据策略)
Interlocked.Increment(ref _droppedCount);
return false;
}
_imageQueue.Enqueue(image);
return true;
}
/// <summary>
/// 消费者:后台线程持续处理
/// </summary>
private void ConsumerLoop()
{
while (!_cts.Token.IsCancellationRequested)
{
if (_imageQueue.TryDequeue(out RawImageData image))
{
try
{
ProcessImage(image);
Interlocked.Increment(ref _processedCount);
}
finally
{
// 释放非托管内存
if (image.Buffer != IntPtr.Zero)
{
// 根据 SDK 要求释放
// Marshal.FreeHGlobal(image.Buffer);
}
}
}
else
{
// 队列为空,短暂休眠避免 CPU 空转
Thread.Sleep(1);
}
}
}
/// <summary>
/// 图像处理逻辑(可替换为 OpenCvSharp 或 Halcon)
/// </summary>
private void ProcessImage(RawImageData image)
{
// 根据像素格式选择处理方式
switch (image.PixelFormat)
{
case PixelType.Mono8:
ProcessMono8(image);
break;
case PixelType.BayerRG8:
ProcessBayerRG8(image);
break;
case PixelType.RGB8:
ProcessRGB8(image);
break;
}
}
private void ProcessMono8(RawImageData image)
{
// OpenCvSharp 零拷贝处理
using (Mat mat = new Mat(image.Height, image.Width, MatType.CV_8UC1, image.Buffer))
{
// 高斯滤波去噪
using Mat blurred = new Mat();
Cv2.GaussianBlur(mat, blurred, new Size(3, 3), 0);
// 边缘检测
using Mat edges = new Mat();
Cv2.Canny(blurred, edges, 50, 150);
// 保存结果
string filename = $"frame_{image.Timestamp}.png";
Cv2.ImWrite(filename, edges);
}
}
public void Stop()
{
_cts.Cancel();
_consumerThread?.Join(2000);
}
public void Dispose()
{
Stop();
_cts.Dispose();
}
public (int Processed, int Dropped) GetStatistics() =>
(_processedCount, _droppedCount);
}
OpenCvSharp 处理思路(零拷贝 + 批量处理)
csharp
using OpenCvSharp;
using System;
using System.IO;
public class OpenCvSharpBurstProcessor
{
private readonly string _outputDir;
public OpenCvSharpBurstProcessor(string outputDir)
{
_outputDir = outputDir;
Directory.CreateDirectory(outputDir);
}
/// <summary>
/// 处理 Burst 单帧(零拷贝包装)
/// </summary>
public void ProcessBurstFrame(IntPtr pData, int width, int height,
PixelType pixelType, long timestamp)
{
// 根据像素格式确定 MatType
MatType matType = ConvertPixelType(pixelType);
// 零拷贝包装(注意:pData 生命周期由相机 SDK 管理)
using (Mat mat = new Mat(height, width, matType, pData))
{
// 如果是 Bayer 格式,先转 RGB
if (pixelType == PixelType.BayerRG8)
{
using Mat rgb = new Mat();
Cv2.CvtColor(mat, rgb, ColorConversionCodes.BayerRG2BGR);
ProcessAndSave(rgb, timestamp);
}
else
{
ProcessAndSave(mat, timestamp);
}
}
}
private void ProcessAndSave(Mat image, long timestamp)
{
// 1. 预处理:灰度转换(如果是彩色图)
using Mat gray = image.Channels() == 3
? image.CvtColor(ColorConversionCodes.BGR2GRAY)
: image.Clone();
// 2. 滤波去噪
using Mat blurred = new Mat();
Cv2.GaussianBlur(gray, blurred, new Size(5, 5), 0);
// 3. 二值化
using Mat binary = new Mat();
Cv2.Threshold(blurred, binary, 0, 255, ThresholdTypes.Otsu);
// 4. 形态学操作
using Mat kernel = Cv2.GetStructuringElement(MorphShapes.Rect, new Size(3, 3));
using Mat morphed = new Mat();
Cv2.MorphologyEx(binary, morphed, MorphTypes.Open, kernel);
// 5. 轮廓提取与筛选
Cv2.FindContours(morphed, out Point[][] contours, out HierarchyIndex[] hierarchy,
RetrievalModes.External, ContourApproximationModes.Simple);
// 6. 绘制结果
using Mat result = image.Channels() == 1
? Cv2.CvtColor(image, null, ColorConversionCodes.GRAY2BGR)
: image.Clone();
foreach (var contour in contours)
{
double area = Cv2.ContourArea(contour);
if (area > 100) // 面积过滤
{
Rect rect = Cv2.BoundingRect(contour);
Cv2.Rectangle(result, rect, new Scalar(0, 255, 0), 2);
}
}
// 7. 保存结果
string path = Path.Combine(_outputDir, $"burst_{timestamp}.png");
Cv2.ImWrite(path, result);
}
/// <summary>
/// 批量处理 Burst 序列(适合事后分析)
/// </summary>
public void ProcessBurstSequence(IntPtr[] buffers, int width, int height,
PixelType pixelType, long[] timestamps)
{
// 使用 Parallel.For 多线程处理已缓存的 Burst 序列
Parallel.For(0, buffers.Length, i =>
{
ProcessBurstFrame(buffers[i], width, height, pixelType, timestamps[i]);
});
}
private MatType ConvertPixelType(PixelType pt)
{
return pt switch
{
PixelType.Mono8 => MatType.CV_8UC1,
PixelType.RGB8 => MatType.CV_8UC3,
PixelType.Mono16 => MatType.CV_16UC1,
_ => MatType.CV_8UC1
};
}
}
Halcon 处理思路(原生算子 + HDevEngine 集成)
csharp
using HalconDotNet;
public class HalconBurstProcessor : IDisposable
{
private readonly HWindow _window;
private readonly string _outputDir;
public HalconBurstProcessor(string outputDir)
{
_outputDir = outputDir;
_window = new HWindow();
System.IO.Directory.CreateDirectory(outputDir);
}
/// <summary>
/// 处理 Burst 单帧(从指针创建 HImage)
/// </summary>
public void ProcessBurstFrame(IntPtr pData, int width, int height,
string pixelType, long timestamp)
{
// 从原始指针创建 Halcon 图像(零拷贝或浅拷贝,取决于 SDK)
// 注意:Halcon 的 GenImage1Extern 需要管理内存生命周期
HImage image = new HImage(pixelType, width, height, pData);
try
{
// 1. 高斯滤波
HImage smoothed = image.GaussFilter(5.0);
// 2. 边缘提取(亚像素精度)
HXLDCont edges = smoothed.EdgesSubPix("canny", 1.0, 20, 40);
// 3. 分割区域
HRegion region = smoothed.Threshold(128, 255);
HRegion connected = region.Connection();
// 4. 形状筛选
HRegion selected = connected.SelectShape("area", "and", 100, 999999);
// 5. 获取特征
HTuple areas, row, column;
selected.AreaCenter(out areas, out row, out column);
// 6. 绘制结果
_window.SetColor("green");
_window.DispObj(image);
_window.SetColor("red");
_window.DispObj(selected);
// 7. 保存结果
string path = System.IO.Path.Combine(_outputDir, $"halcon_burst_{timestamp}.tif");
image.WriteImage("tiff", 0, path);
// 8. 释放资源
edges.Dispose();
region.Dispose();
connected.Dispose();
selected.Dispose();
}
finally
{
image.Dispose();
}
}
/// <summary>
/// 使用 HDevEngine 执行 HDevelop 脚本处理 Burst 序列
/// </summary>
public void ProcessWithHDevEngine(IntPtr[] buffers, int width, int height,
string pixelType, long[] timestamps, string hdevPath)
{
HDevEngine engine = new HDevEngine();
engine.SetProcedurePath(System.IO.Path.GetDirectoryName(hdevPath));
HDevProgram program = new HDevProgram(hdevPath);
HDevProgramCall call = new HDevProgramCall(program);
for (int i = 0; i < buffers.Length; i++)
{
// 创建 HImage 并传入 HDevelop 程序
HImage image = new HImage(pixelType, width, height, buffers[i]);
call.SetInputIconicParamImage("Image", image);
call.SetInputCtrlParamTuple("Timestamp", timestamps[i]);
call.SetInputCtrlParamTuple("OutputDir", _outputDir);
call.Execute();
// 获取结果
HTuple defectCount = call.GetOutputCtrlParamTuple("DefectCount");
Console.WriteLine($"Frame {i}: 缺陷数 = {defectCount}");
image.Dispose();
}
engine.Dispose();
}
/// <summary>
/// 批量保存原始 Burst 数据(用于事后 Halcon 分析)
/// </summary>
public void SaveRawBurstData(IntPtr[] buffers, int width, int height,
int bytesPerPixel, long[] timestamps)
{
int frameSize = width * height * bytesPerPixel;
for (int i = 0; i < buffers.Length; i++)
{
string path = System.IO.Path.Combine(_outputDir, $"raw_{timestamps[i]}.bin");
byte[] data = new byte[frameSize];
System.Runtime.InteropServices.Marshal.Copy(buffers[i], data, 0, frameSize);
System.IO.File.WriteAllBytes(path, data);
}
}
public void Dispose()
{
_window?.Dispose();
}
}
性能对比与选型建议
| 处理方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| OpenCvSharp 零拷贝 | 免费开源,社区活跃,Bitmap 互转方便 | 工业相机 SDK 支持不如 Halcon 完善 | 中小型项目,预算有限 |
| Halcon 原生算子 | 工业级稳定,算子优化极致,3D/深度学习原生支持 | 商业授权费用高 | 高精度工业检测,大规模部署 |
| HDevEngine 脚本 | 快速原型,算法可热更新,非程序员也能调参 | 脚本执行有额外开销 | 算法频繁迭代,多项目复用 |
| C# 多线程 + 队列 | 充分利用多核,解耦采集与处理 | 线程同步复杂,调试困难 | 高帧率、大数据量场景 |
CSDN 发布建议 :可补充实际测试数据(如 Basler acA2500 在 Burst 模式下的帧率-CPU 占用曲线图),增加说服力。标签:
#C##机器视觉#Burst模式#工业相机#OpenCvSharp#Halcon
五、几个容易踩的坑
坑一:缓存满了自动丢帧。相机内部缓存满了之后,新拍的图会直接丢弃。在高速Burst模式下,连拍结束后的传输间隙要预留够。
坑二:Burst模式和普通触发混用。确认触发源配置正确,FrameBurstStart触发和普通FrameStart触发是两套独立的触发通道。
坑三:存图速度跟不上取图速度。Burst模式解决了"拍得快",没解决"存得快"。内部缓存满了之后,如果电脑取图太慢,新图一样会丢。后端的异步处理线程必须足够快,或者队列足够大。
坑四:不同品牌参数名不一样 。Basler叫BslAcquisitionBurstMode和AcquisitionBurstFrameCount。海康叫AcquisitionBurstFrameCount。堡盟叫MemoryMode和MemoryPartBlocks。换品牌的时候别照着抄。
六、什么时候该用,什么时候别用
该用:高速瞬态抓拍(碰撞测试、跌落分析)、多相机同时触发但网络带宽不够、需要短时间密集采样的场景。
不该用:24×7连续采集、相机内存容量小于单批图像总大小、对实时性要求极高(Burst模式有传输延迟)。
七、核心优势
| 优势维度 | 具体说明 |
|---|---|
| 高速连续捕获 | 以极高帧率连续采集多帧图像,数据暂存于相机内部高速缓存,避免实时传输瓶颈 |
| 零丢帧保障 | 规避常规连续采集中因总线带宽不足或 OS 调度延迟导致的丢帧问题,确保关键帧完整捕获 |
| 总线带宽优化 | 批量传输而非逐帧实时传输,降低对 GigE/USB3 等接口的持续带宽压力 |
| CPU 占用降低 | 配合异步回调或零拷贝传输,减少 C# 应用层线程阻塞与上下文切换开销 |
| 触发响应精准 | 外部硬触发信号启动 Burst,实现微秒级同步,适合与产线 PLC/编码器联动 |
| C# 集成友好 | 主流 SDK(Basler Pylon、Baumer、Halcon)均提供 GrabImageBurst 等托管接口,异步编程模型成熟 |
八、行业应用
| 应用领域 | 典型场景 | Burst 模式价值 |
|---|---|---|
| 半导体检测 | 晶圆表面缺陷扫描、Die 级 AOI | 高速旋转/平移中捕获数百帧,不遗漏细微瑕疵 |
| 锂电池制造 | 极片涂布缺陷检测、极耳尺寸测量 | 配合频闪光源冻结运动模糊,获取清晰边缘轮廓 |
| 3C 电子 | 手机屏幕跌落测试、按键寿命测试 | 连续记录高速冲击/回弹过程,逐帧回溯分析失效机理 |
| 汽车安全 | 安全气囊点爆形态分析、碰撞测试 | 毫秒级捕捉气囊展开全过程,验证设计参数 |
| 食品/医药包装 | 高速灌装液位检测、封膜完整性检查 | 产线 600+ 瓶/分钟速度下,确保每瓶都有独立检测帧 |
| 高速运动分析 | 弹道轨迹追踪、机械振动模态分析 | 高帧率序列支持慢动作回放与运动学参数提取 |
九、选型建议速查
| 场景特征 | 推荐配置 |
|---|---|
| 帧率 > 500fps | 选择 Camera Link / CoaXPress 接口 + 大容量相机缓存 |
| 多相机同步 | 外触发 + PTP(IEEE 1588)精确时间协议 |
| 长时间 Burst | 关注相机缓存容量(如 4GB DDR),或配合 RAID 阵列实时落盘 |
| C# 低延迟处理 | 使用 unsafe 代码或 Span<byte> 避免 Bitmap 拷贝开销 |
CSDN 发布建议 :可配合实际项目截图(如 Halcon HSmartWindow 显示 Burst 序列、Basler Pylon Viewer 参数配置界面),增加阅读体验。标签建议:
#C##机器视觉#工业相机#Burst模式#图像采集
十、总结
Burst模式的核心就一句话:拍的时候只管往内存里塞,传的时候慢慢往外倒。相机内部缓存越大的话,那么能扛的爆发速度越高。
把Burst模式和普通连续采集区分开------前者解决的是"短时间拍得快",后者解决的是"长时间传得稳"。两个场景不同,别混着用。
小提示:第一次用Burst模式,先用MVS或pylon Viewer手动触发一次,看相机内部缓存能存多少张、传完需要多久,心里有个底再写代码。不同分辨率下缓存张数不一样,ROI开得越小,能存的张数越多。