拍摄一张并显示之前的一张 - VB - OpenCV

Taking one capture and displaying the one before - VB - OpenCV

我在使用网络摄像头、opencv 和 emgucv 拍摄照片时遇到了一个特殊问题。

我以前用过这个功能,一直很好用,但是现在不知道为什么,图片框显示的是之前拍的照片。让我解释一下:

我启动程序 - 我按下按钮并在拍照前等待几秒钟 - 我使用 img = capturez.QueryFrame() 拍照 - 我在 PictureBox 中显示图片。这是代码:

Private Sub startButton_Click() Handles startButton.Click

    Dim timeToWait As Integer
    PictureBox1.Image = Nothing
    If globalGMT <> Nothing And globalLatitude <> Nothing And globalLongitude <> Nothing Then
        'If TextBox_GMT.Text IsNot Nothing And TextBox_LAT.Text IsNot Nothing And TextBox_LON.Text IsNot Nothing Then
        SunPosition(globalGMT, globalLatitude, globalLongitude, ELEVACIONDELSOL, AZIMUTDELSOL)
    End If
    startButton.Enabled = False
    SetDefaultTimeButton.Enabled = False
    SetParameters.Enabled = False
    TextBoxTime.Text = System.DateTime.UtcNow

    timeToWait = globalTimeLeft

    For i = 0 To timeLeft
        wait()
        i += 1
        timeToWait -= 1
        timeLabel.Text = timeToWait & " seconds"
    Next

    Dim img As Image(Of Bgr, Byte) = capturez.QueryFrame()

    For x = 0 To img.Width - 1
        For y = 0 To img.Height - 1
            Dim pixelColor As Bgr = img(y, x)

            If (pixelColor.Blue >= 200 And pixelColor.Blue <= 255) And
               (pixelColor.Green >= 200 And pixelColor.Green <= 255) And (pixelColor.Red >= 200 And pixelColor.Red <= 255) Then
                pixelColor.Blue = 255
                pixelColor.Green = 255
                pixelColor.Red = 255
                img(y, x) = pixelColor
            Else
                pixelColor.Blue = 0
                pixelColor.Green = 0
                pixelColor.Red = 0
                img(y, x) = pixelColor
            End If
        Next
    Next

    PictureBox1.Image = img.ToBitmap

    startButton.Enabled = True
    SetParameters.Enabled = True
    SetDefaultTimeButton.Enabled = True
    SetForm()

End Sub

函数 wait() 如下所示:

Private Sub wait()
    Dim seconds As Integer = 1
    For i As Integer = 0 To seconds * 100
        System.Threading.Thread.Sleep(10)
        'Application.DoEvents()
    Next
End Sub

也许你会问,为什么不用定时器呢?这是因为使用计时器我遇到了完全相同的问题。下面是使用定时器的代码:

'This function will start the activity of the form
Private Sub startButton_Click() Handles startButton.Click

    Dim timeToWait As Integer
    PictureBox1.Image = Nothing
    If globalGMT <> Nothing And globalLatitude <> Nothing And globalLongitude <> Nothing Then
        'If TextBox_GMT.Text IsNot Nothing And TextBox_LAT.Text IsNot Nothing And TextBox_LON.Text IsNot Nothing Then
        SunPosition(globalGMT, globalLatitude, globalLongitude, ELEVACIONDELSOL, AZIMUTDELSOL)
    End If
    startButton.Enabled = False
    SetDefaultTimeButton.Enabled = False
    SetParameters.Enabled = False
    TextBoxTime.Text = System.DateTime.UtcNow
    StartButtonTimer.Start()
End Sub

'This function will start the timer of the form 
Private Sub StartButtonTimer_Tick() Handles StartButtonTimer.Tick
    Dim X As Integer
    Dim Y As Integer

    If timeLeft > 0 Then
        timeLeft -= 1
        timeLabel.Text = timeLeft & " seconds"

        'DLE prueba tomar foto después del tiempo especificado - pongo a negro el fondo del picturebox
        PictureBox1.BackColor = Color.Black
    Else

        'DLE prueba tomar foto después del tiempo especificado - hago foto de lo que ve la camara
        Dim img As Image(Of Bgr, Byte) = capturez.QueryFrame()

        For X = 0 To img.Width - 1
            For Y = 0 To img.Height - 1
                Dim pixelColor As Bgr = img(Y, X)

                If (pixelColor.Blue >= 200 And pixelColor.Blue <= 255) And
                   (pixelColor.Green >= 200 And pixelColor.Green <= 255) And
                   (pixelColor.Red >= 200 And pixelColor.Red <= 255) Then
                    pixelColor.Blue = 255
                    pixelColor.Green = 255
                    pixelColor.Red = 255
                    img(Y, X) = pixelColor
                Else
                    pixelColor.Blue = 0
                    pixelColor.Green = 0
                    pixelColor.Red = 0
                    img(Y, X) = pixelColor
                End If
            Next
        Next
        StartButtonTimer.Stop()
        PictureBox1.Image = img.ToBitmap
        startButton.Enabled = True
        SetParameters.Enabled = True
        SetDefaultTimeButton.Enabled = True
        SetForm()
    End If
End Sub

函数 SetForm() 只启用部分按钮。

问题是: 我拍第一张照片 - 图片框显示第一张照片。 我拍第二张照片 - 图片框再次显示第一张照片。 我拍了第三张照片 - 图片框显示了第二张照片。 我拍了第四张照片 - 图片框显示了第三张照片。 ... ... 拍照后,我只识别出一种颜色,并以白色显示该颜色,将图片的其余部分显示为黑色(如果有人需要此解释)

感谢您能给我的任何帮助!

编辑:如果我在函数末尾添加这一行:Dim image As Image(Of Bgr, Byte) = capturez.QueryFrame(),效果很好:

...
        ...
        Next
        StartButtonTimer.Stop()
        PictureBox1.Image = img.ToBitmap
        startButton.Enabled = True
        SetParameters.Enabled = True
        SetDefaultTimeButton.Enabled = True
        SetForm()
    End If

    Dim image As Image(Of Bgr, Byte) = capturez.QueryFrame()

End Sub

结束Class

我不是无缘无故地使用最后一个变量,只是我在没有使用它的情况下声明它。我不明白为什么用这条线效果很好,当我擦掉它时,它不起作用..

我花了一段时间才弄明白这一点,但我认为问题在于您没有 Dispose 捕获。由于您仅在单击按钮时捕获一帧(并且您没有实时网络摄像头流),因此您应该在使用 Capture 对象后 Dispose。现在发生的是你请求一个新框架,Capture 对象将 return 旧框架,然后开始检索另一个为下一次使用做好准备的框架。因此,如果您在方法的末尾放置另一个 QueryFrame() 它会再次起作用,因为旧框架已被覆盖。

这应该可以解决您的问题:

'Make sure you can use your retrieved image even after the dispose
Dim img As Image(Of Bgr, Byte);

'Create a new capture object
Using capturez As New Capture
    'Since it's a new object the webcam is forced to retrieve a frame now
    'Also, use Copy() to make sure your image is still available after diposing
    img = capturez.QueryFrame().Copy()
End Using 'Dispose the object now 

'Now do with your img object whatever you want!