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

狂风中的少年 提交于 2019-12-11 05:15:59

问题


I am having a special problem with capturing a picture using my webcam, opencv and emgucv.

I have used this function before, and always worked well, but now, I don't know why, the picturebox is showing me the picture taken before. Let me explain:

I start the program - I press the button and wait some seconds before the picture is taken - I take the picture using img = capturez.QueryFrame() - I display the picture in the PictureBox. Here is the code:

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

The function wait() looks like this:

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

Maybe you can ask, why don't you use a timer for that? It is because with the timer I am having exactly the same problem. Here is the code using the timer:

'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

The function SetForm() only enables some buttons.

The problem is: I take the first picture - The picturebox shows the first picture. I take the second picture - The picturebox shows the first picture again. I take the third picture - The picturebox shows the second picture. I take the fourth picture - The picturebox shows the third picture. ... ... After taking the picture, I'm only recognizing a colour and show that colour in white and the rest of the picture in black (if someone needs this explanation)

Thanks for any help you could give me!

EDIT: if I add this line at the end of the function: Dim image As Image(Of Bgr, Byte) = capturez.QueryFrame(), it works well:

...
        ...
        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

End Class

I don't use this last variable for nothing, only I am declaring it without use it. I don't understand why with this line it works well, and when I erase it, it doesn´t works..


回答1:


It took me a while to figure this about, but I believe the problem is that you don't Dispose your capture. Since you only capture one frame on a button click (and you don't have a live webcam stream) you should Dispose of your Capture object after you use it. What happens now is that you ask for a new frame, the Capture object will return the old frame and then starts retrieving another one that's ready for next use. Therefore, if you put another QueryFrame() at the end of your method it works again, since the old frame is overwritten.

This should solve your problem:

'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!


来源:https://stackoverflow.com/questions/43211664/taking-one-capture-and-displaying-the-one-before-vb-opencv

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!