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
相关产品推荐
相关产品推荐

