You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VB.NET中使用Emgu.CV绘制指定面积轮廓时触发SEHException异常

解决Emgu CV遍历轮廓时触发SEHException的问题

问题分析

异常触发在调用CvInvoke.ContourArea(contours(j))时,属于非托管代码抛出的外部异常,核心原因是传入的轮廓对象无效(空指针、内存损坏、点数量不足等)。

修复方案

1. 校验轮廓有效性

计算轮廓面积前,先检查单个轮廓是否存在且点数量≥3(少于3个点无法构成闭合区域,计算面积会出错):

Dim contour As VectorOfPoint = contours(j)
If contour IsNot Nothing AndAlso contour.Size >= 3 Then
    Dim area As Double = CvInvoke.ContourArea(contour)
    If area > threshold Then
        CvInvoke.DrawContours(frame, contours, j, New MCvScalar(0, 0, 255), 5)
    End If
End If

2. 正确管理非托管资源

Emgu CV的VectorOfVectorOfPoint、Mat属于非托管包装类,需用Using语句确保资源及时释放,避免内存泄漏导致的无效对象:

Using contours As New Emgu.CV.Util.VectorOfVectorOfPoint(), hier As New Mat()
    CvInvoke.FindContours(imgContours, contours, hier, CvEnum.RetrType.External, CvEnum.ChainApproxMethod.ChainApproxSimple)
    ' 后续轮廓遍历逻辑放在Using块内
End Using

3. 确保背景帧与当前帧一致性

背景帧直接赋值会导致和当前帧共享内存,后续修改会污染背景;同时要校验尺寸是否匹配:

If backgroundFrame Is Nothing Then
    backgroundFrame = frame.Clone() ' 用Clone而非直接赋值
Else
    If backgroundFrame.Size <> frame.Size Then
        backgroundFrame = frame.Clone() ' 尺寸不匹配时更新背景
        Exit Sub
    End If
    ' 背景减法逻辑
End If

4. 增加帧有效性校验

获取摄像头帧后先检查是否为空,避免后续操作基于无效帧:

Dim currFr As Emgu.CV.Image(Of Bgr, Byte) = videoCap.QueryFrame()?.ToImage(Of Bgr, Byte)
If currFr Is Nothing Then Return

完整修复后的代码

' cyclic routine
Dim currFr As Emgu.CV.Image(Of Bgr, Byte) = videoCap.QueryFrame()?.ToImage(Of Bgr, Byte)
If currFr Is Nothing Then Return ' 校验帧是否有效

' copy frame
Dim frame As Emgu.CV.Image(Of Bgr, Byte) = currFr.Resize(1, CvEnum.Inter.Lanczos4)
Dim imgContours As New Image(Of Gray, Byte)(frame.Size)

If backgroundFrame Is Nothing Then
    ' 保存背景帧,使用Clone避免引用关联
    backgroundFrame = frame.Clone()
Else
    ' 确保背景帧与当前帧尺寸一致
    If backgroundFrame.Size <> frame.Size Then
        backgroundFrame = frame.Clone()
        Exit Sub
    End If

    ' background subtraction
    Dim elFrame As Emgu.CV.Image(Of Bgr, Byte) = frame - backgroundFrame

    ' get contours from image (as VectorOfVectorOfPoint)
    imgContours = elFrame.Convert(Of Gray, Byte).ThresholdBinary(New Gray(80), New Gray(255))
    
    ' Using块管理非托管资源,自动释放内存
    Using contours As New Emgu.CV.Util.VectorOfVectorOfPoint(), hier As New Mat()
        CvInvoke.FindContours(imgContours, contours, hier, CvEnum.RetrType.External, CvEnum.ChainApproxMethod.ChainApproxSimple)

        ' draw all contours on the original frame of blue
        CvInvoke.DrawContours(frame, contours, -1, New MCvScalar(255, 0, 0), 5)

        ' iterate through contours
        For j As Integer = 0 To contours.Length - 1
            Dim contour As Emgu.CV.Util.VectorOfPoint = contours(j)
            ' 校验轮廓是否有效(非空且点数量≥3)
            If contour IsNot Nothing AndAlso contour.Size >= 3 Then
                Dim area As Double = CvInvoke.ContourArea(contour)
                If area > threshold Then
                    ' draw the current contour of red
                    CvInvoke.DrawContours(frame, contours, j, New MCvScalar(0, 0, 255), 5)
                End If
            End If
        Next
    End Using
End If

' display the frame in the PictureBox
picFrame.Image = frame.ToBitmap

内容的提问来源于stack exchange,提问作者user2959923

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 20:43:26