从相机读取帧时 RAM 使用量增加
RAM usage increasing when reading frames from camera
我正在使用 AForge 库进行一些测试。我正在尝试读取来自我的 USB 相机(帧)的数据。它工作得很好,但唯一的问题是 RAM。它泄漏。似乎一帧需要大约 30 KB,但使用的内存不断增加。
这是我的代码:
Imports AForge
Imports AForge.Controls
Imports AForge.Video
Imports AForge.Video.DirectShow
Imports System.Threading
Imports System.IO
Imports System.Collections.Concurrent
Imports System.ComponentModel
Public Class Form1
Dim sources As New FilterInfoCollection(FilterCategory.VideoInputDevice)
Dim WithEvents device As VideoCaptureDevice
Dim count As Long, bit As Bitmap
Dim read As New Thread(AddressOf read_que)
Dim pic_que As New ConcurrentQueue(Of Bitmap)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For Each cam As FilterInfo In sources
ComboBox1.Items.Add(cam.Name)
Next
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
device = New VideoCaptureDevice(sources(ComboBox1.SelectedIndex).MonikerString)
AddHandler device.NewFrame, new Video.NewFrameEventHandler(AddressOf frame)
device.WaitForStop()
device.Start()
End Sub
Sub frame(obj As Object, args As NewFrameEventArgs)
If bit IsNot Nothing Then
bit.Dispose()
bit = Nothing
End If
bit = New Bitmap(args.Frame)
If PictureBox1.Image IsNot Nothing Then
PictureBox1.Invoke(New MethodInvoker(Sub() PictureBox1.Image.Dispose()))
End If
PictureBox1.Image =bit ' or ... = Imaging.Image.Clone(args.Frame)
End Sub
End Class
我什至尝试将所有帧放在一个并发队列中,然后在一个单独的线程中读取它(我发布了似乎占用最少 ram 内存的简化版本)。
但是还有另一个问题(这不是那么重要):当我启动应用程序时,图片框是空白的,使用的 ram 是 16 MB(常量 - 所以它不起作用)。
只有当我进入任务管理器并按下结束进程(实际上没有关闭它)时,它才会开始显示框架。我认为它与 GUI 相关(当我按下 End Process 时,它可能会触发一个启动帧读取的事件 class?)。
只是在随机时间它似乎从第一次开始工作(这确实可能是相机的问题,因为它很旧并且只能在 XP 上工作所以我不得不使用 .NET Framework 4)。
哪里出了问题(主要是内存泄漏)?
试试这个:
Sub frame(obj As Object, args As NewFrameEventArgs)
If Me.InvokeRequired Then
Me.BeginInvoke(Sub() frame(obj, args))
Else
Dim oldImage = PictureBox1.Image
Dim bitmap = New Bitmap(args.Frame)
args.Frame.Dispose() 'Not sure if it has a Dispose
PictureBox1.Image = bitmap
If oldImage IsNot Nothing Then oldImage.Dispose()
End If
End Sub
解决了。感谢您的所有帮助,但我知道我的代码可以正常工作(我在委托之前使用过在图片框上绘制,因此它是线程安全的——我提供的代码是 "quick and dirty")。问题是......虚拟机。我在虚拟机上测试代码。它适用于普通 PC。
代码现在看起来像这样:
Imports AForge
Imports AForge.Controls
Imports AForge.Video
Imports AForge.Video.DirectShow
Imports System.Threading
Imports System.IO
Imports System.Collections.Concurrent
Imports System.ComponentModel
Public Class Form1
Dim sources As New FilterInfoCollection(FilterCategory.VideoInputDevice)
Dim device As VideoCaptureDevice
Delegate Sub lp(ByRef pic As Bitmap)
Delegate Sub lpp(nr As Integer, nr2 As Integer)
Delegate Sub slp()
Dim count As Long, bit As Bitmap
Dim read As New Thread(AddressOf read_que)
Dim pic_que As New ConcurrentQueue(Of Bitmap)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For Each cam As FilterInfo In sources
ComboBox1.Items.Add(cam.Name)
Next
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
device = New VideoCaptureDevice(sources(ComboBox1.SelectedIndex).MonikerString)
AddHandler device.NewFrame, new Video.NewFrameEventHandler(AddressOf frame)
'device.WaitForStop()
device.Start()
'read.IsBackground = True
'read.Start()
End Sub
Sub frame(obj As Object, args As NewFrameEventArgs)
'If bit IsNot Nothing Then
' bit.Dispose()
' bit = Nothing
'End If
'bit = New Bitmap(args.Frame)
If PictureBox1.Image IsNot Nothing Then
PictureBox1.Invoke(New MethodInvoker(Sub() PictureBox1.Image.Dispose()))
End If
PictureBox1.Invoke(New MethodInvoker(Sub() PictureBox1.Image = Imaging.Image.Clone(args.Frame))) 'Imaging.Image.Clone(args.Frame) ' or ...=bit
End Sub
End Class
我正在使用 AForge 库进行一些测试。我正在尝试读取来自我的 USB 相机(帧)的数据。它工作得很好,但唯一的问题是 RAM。它泄漏。似乎一帧需要大约 30 KB,但使用的内存不断增加。
这是我的代码:
Imports AForge
Imports AForge.Controls
Imports AForge.Video
Imports AForge.Video.DirectShow
Imports System.Threading
Imports System.IO
Imports System.Collections.Concurrent
Imports System.ComponentModel
Public Class Form1
Dim sources As New FilterInfoCollection(FilterCategory.VideoInputDevice)
Dim WithEvents device As VideoCaptureDevice
Dim count As Long, bit As Bitmap
Dim read As New Thread(AddressOf read_que)
Dim pic_que As New ConcurrentQueue(Of Bitmap)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For Each cam As FilterInfo In sources
ComboBox1.Items.Add(cam.Name)
Next
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
device = New VideoCaptureDevice(sources(ComboBox1.SelectedIndex).MonikerString)
AddHandler device.NewFrame, new Video.NewFrameEventHandler(AddressOf frame)
device.WaitForStop()
device.Start()
End Sub
Sub frame(obj As Object, args As NewFrameEventArgs)
If bit IsNot Nothing Then
bit.Dispose()
bit = Nothing
End If
bit = New Bitmap(args.Frame)
If PictureBox1.Image IsNot Nothing Then
PictureBox1.Invoke(New MethodInvoker(Sub() PictureBox1.Image.Dispose()))
End If
PictureBox1.Image =bit ' or ... = Imaging.Image.Clone(args.Frame)
End Sub
End Class
我什至尝试将所有帧放在一个并发队列中,然后在一个单独的线程中读取它(我发布了似乎占用最少 ram 内存的简化版本)。 但是还有另一个问题(这不是那么重要):当我启动应用程序时,图片框是空白的,使用的 ram 是 16 MB(常量 - 所以它不起作用)。
只有当我进入任务管理器并按下结束进程(实际上没有关闭它)时,它才会开始显示框架。我认为它与 GUI 相关(当我按下 End Process 时,它可能会触发一个启动帧读取的事件 class?)。
只是在随机时间它似乎从第一次开始工作(这确实可能是相机的问题,因为它很旧并且只能在 XP 上工作所以我不得不使用 .NET Framework 4)。
哪里出了问题(主要是内存泄漏)?
试试这个:
Sub frame(obj As Object, args As NewFrameEventArgs)
If Me.InvokeRequired Then
Me.BeginInvoke(Sub() frame(obj, args))
Else
Dim oldImage = PictureBox1.Image
Dim bitmap = New Bitmap(args.Frame)
args.Frame.Dispose() 'Not sure if it has a Dispose
PictureBox1.Image = bitmap
If oldImage IsNot Nothing Then oldImage.Dispose()
End If
End Sub
解决了。感谢您的所有帮助,但我知道我的代码可以正常工作(我在委托之前使用过在图片框上绘制,因此它是线程安全的——我提供的代码是 "quick and dirty")。问题是......虚拟机。我在虚拟机上测试代码。它适用于普通 PC。
代码现在看起来像这样:
Imports AForge
Imports AForge.Controls
Imports AForge.Video
Imports AForge.Video.DirectShow
Imports System.Threading
Imports System.IO
Imports System.Collections.Concurrent
Imports System.ComponentModel
Public Class Form1
Dim sources As New FilterInfoCollection(FilterCategory.VideoInputDevice)
Dim device As VideoCaptureDevice
Delegate Sub lp(ByRef pic As Bitmap)
Delegate Sub lpp(nr As Integer, nr2 As Integer)
Delegate Sub slp()
Dim count As Long, bit As Bitmap
Dim read As New Thread(AddressOf read_que)
Dim pic_que As New ConcurrentQueue(Of Bitmap)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For Each cam As FilterInfo In sources
ComboBox1.Items.Add(cam.Name)
Next
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
device = New VideoCaptureDevice(sources(ComboBox1.SelectedIndex).MonikerString)
AddHandler device.NewFrame, new Video.NewFrameEventHandler(AddressOf frame)
'device.WaitForStop()
device.Start()
'read.IsBackground = True
'read.Start()
End Sub
Sub frame(obj As Object, args As NewFrameEventArgs)
'If bit IsNot Nothing Then
' bit.Dispose()
' bit = Nothing
'End If
'bit = New Bitmap(args.Frame)
If PictureBox1.Image IsNot Nothing Then
PictureBox1.Invoke(New MethodInvoker(Sub() PictureBox1.Image.Dispose()))
End If
PictureBox1.Invoke(New MethodInvoker(Sub() PictureBox1.Image = Imaging.Image.Clone(args.Frame))) 'Imaging.Image.Clone(args.Frame) ' or ...=bit
End Sub
End Class