Estrarre e salvare singole immagini da una ripresa video mediante WebCam effettuata con il Componente gb.media

Da Gambas-it.org - Wikipedia.

A volte può essere necessario estrarre e salvare in appositi file singole immagini di una ripresa video effettuata mediante una WebCam con il Componente gb.media. [Nota 1]
Per fare ciò, sono disponibili alcune modalità.


Usare le Classi "MediaPlayer" e "MediControl"

Innanzitutto è possibile usare le Classi "MediaPlayer" e "MediControl". In particolare, per catturare le singole immagini, si utilizzerà in tal caso la sotto-proprietà ".Image" della proprietà "Video" della Classe "MediaPlayer".

Risulta che le risorse dei Componenti grafici, fondati su QT, causano errore alla predetta sotto-proprietà ".Image", pertanto sarà opportuno attivare in alternativa il Componente "gb.gui" o il Componente "gb.gtk", oppure il Componente "gb.gtk3".

Mostriamo di seguito un semplice esempio, nel quale verrà effettuata una ripresa video con una webcam. La ripresa sarà mostrata all'interno di una DrawingArea, e sarà salvata ogni secondo un'immagine della ripresa all'interno di un file immagine di formato PNG.

Private pl As MediaPlayer
Private im As MediaControl
Private tb As ToggleButton
Private tempus As Timer
Private i As Integer


Public Sub Form_Open()
 
 Dim drar As DrawingArea
 Dim flt As MediaFilter
   
  With Me
    .W = 700
    .H = 600
  End With
  With drar = New DrawingArea(Me)
    .X = 10
    .Y = 10
    .W = 680
    .H = 480
    .Border = Border.Plain
    .Background = Color.Transparent
  End With
  With tb = New ToggleButton(Me) As "Tasto"
    .X = 500
    .Y = 550
    .W = 80
    .H = 40
    .Text = "Avvia"
  End With
  
  pl = New MediaPlayer As "MediaPlayer"
  flt = New MediaFilter(pl, "video/x-raw,width=640,height=480,framerate=30/1")
  im = New MediaControl(pl, "xvimagesink")
  
  pl.Video.Output = im
  pl.URL = "v4l2:///dev/video0"
  
  im.SetWindow(drar)
  
End


Public Sub Tasto_Click()
 
 If tb.Value Then
   pl.Play
   With tempus = New Timer As "Tempus"
     .Delay = 1000
     .Start()
   End With
 Else
   pl.Stop
   pl.Close
   tempus.Stop
 Endif
 
End


Public Sub Tempus_Timer()
 
 Dim img As Image
 Dim s As String
 
  img = pl.Video.Image
  Inc i
  s = CStr(i)
  img.Save("/tmp/foto_" & s & ".png", 100)
  
  Write #File.out, "\rImmagini catturate: " & s
  
End


Usare il metodo ".GetLastImage( )" della Classe "MediaControl" per catturare singole immagini dal video, e utilizzare una DrawingArea per mostrare la ripresa video

Quest'altra modalità prevede che:

  • sia utilizzata una DrawingArea, come superficie ove mostrare la ripresa video;
  • sia utilizzato il metodo ".GetLastImage( )" della Classe "MediaControl" per catturare singole immagini dal video.

Anche in questo caso, come nel primo esempio, è stato riscontrato che le risorse del sistema QT danno problemi all'uso del metodo ".GetLastImage( )". E' dunque opportuno attivare in alternativa il Componente "gb.gui" o il Componente "gb.gtk", oppure il Componente "gb.gtk3".

Mostriamo di seguito un esempio pratico, nel quale la cattura delle immagini dalla ripresa video avviene ogni 500 millisecondi:

Private pl As MediaPipeline
Private snk As MediaControl


Public Sub Form_Open()
 
 Dim src As MediaControl
 Dim ftr As MediaFilter
 Dim dr As DrawingArea
 
  With dr = New DrawingArea(Me)
    .X = 10
    .Y = 10
    .W = 640
    .H = 480
' Affinché la "DrawingArea" mostri il video, è assolutamente necessario attribuire un colore qualsiasi alla sua proprietà ".Background":
    .Background = Color.Black
  End With
  
  pl = New MediaPipeline
 
  src = New MediaControl(pl, "v4l2src")
  
  ftr = New MediaFilter(pl)
  ftr.Filter = "video/x-raw,width=640,height=480,framerate=30/1"
  
  snk = New MediaControl(pl, "xvimagesink")
    
  src.LinkTo(ftr)
  ftr.LinkTo(snk)
  
' Imposta la DrawingArea come superficie ove mostrare la ripresa video:
  snk.SetWindow(dr)
  
End


Public Sub Button1_Click()
 
 Dim i As Integer
 Dim drc, s As String
  
  drc = "/tmp/immagini"
  
  If Not Exist(drc) Then
    Mkdir drc
  Else
    For Each s In Dir(drc, "immagine_*", gb.file)
      Kill drc &/ s
    Next
  Endif
  
  pl.Play()
  
  While pl.State = Media.Playing
    snk.GetLastImage().Save(drc &/ "immagine_" & CStr(I) & ".png")
    Print "Schermata video salvata nella cartella " & drc
    Wait 0.5
    Inc i
  Wend
  
End


Public Sub Button2_Click()
  
  pl.Stop()
  pl.Close()
  
End


Usare il metodo ".GetScreenshot( )" della Classe "DesktopWindow" per catturare singole immagini dal video, e utilizzare una DrawingArea per mostrare la ripresa video

Con questa modalità si raccoglierà mediante il metodo ".GetScreenshot( )" della Classe DesktopWindow quanto appare sulla superficie video utilizzata. Per individuare utilmente tale superficie video, è necessario individuare il suo handle.
E' necessario attivare nell'applicazione Gambas i Componenti "gb.desktop" e "gb.desktop.x11".

Mostriamo di seguito un esempio pratico, nel quale si salverà in un vettore di tipo Picture[ ] ogni 300 millesimi di secondo un'immagine del video, mostrato all'interno di una DrawingArea. Al termine della ripresa video si provvederà a salvare ciascuna immagine, salvata nel predetto vettore, in un file immagine di tipo png.

Private dr As DrawingArea
Private pl As MediaPipeline
Private pc As New Picture[]


Public Sub Form_Open()
 
Dim src, tim, snk As MediaControl
Dim ftr As MediaFilter
 
 With dr = New DrawingArea(Me)
   .X = 10
   .Y = 10
   .W = 640
   .H = 480
' Affinché la "DrawingArea" mostri il video, è assolutamente necessario attribuire un colore qualsiasi alla sua proprietà ".Background":
   .Background = Color.Black
 End With
 
 pl = New MediaPipeline 
 
 src = New MediaControl(pl, "v4l2src")
 ftr = New MediaFilter(pl, "video/x-raw,width=640,height=480,framerate=30/1")
' Mostra nel video anche il tempo trascorso dall'avvio della ripresa:
 tim = New MediaControl(pl, "timeoverlay")
 snk = New MediaControl(pl, "xvimagesink")
 
' Colleghiamo i quattro plug-in di "GStreamer":
 src.LinkTo(tim)
 tim.LinkTo(ftr)
 ftr.LinkTo(snk)
 snk.SetWindow(dr)
  
End


Public Sub Button1_Click()
 
 Dim dw As DesktopWindow
 
' Avvia la ripresa video della WebCam:
  pl.State = Media.Playing
  pl.Play()
 
' Resta in attesa che la WebCam avvi effettivamente la ripresa video:
  Wait 2
  
  dw = New DesktopWindow(dr.Handle)
 
  While pl.State = Media.Playing
' Cattura una schermata del contenuto video mostrato in quel momento dalla "DrawingArea":
    pc.Push(dw.GetScreenshot(True))
' La cattura della schermata avviene ogni 300 millisecondi:
    Wait 0.3
  Wend
     
End


Public Sub Button2_Click()    ' Questo evento arresta la ripresa video e salva ogni picture in un file .png
 
 Dim i As Integer
 Dim drc, s As String
  
  drc = "/tmp/imago"
  
  pl.Stop
 
  If Not Exist(drc) Then
    Mkdir drc
  Else
    For Each s In Dir(drc, "picture_*", gb.file)
      Kill drc &/ s
    Next
  Endif
 
  For i = 0 To pc.Max
    pc[i].Save(drc &/ "picture_" & CStr(i) & ".png", 100)
  Next
  
End


Usare il metodo ".GetLastImage( )" della Classe "MediaControl" per catturare singole immagini dal video, ma senza utilizzare una DrawingArea

Quest'altra modalità prevede che:

  • non sia utilizzata una DrawingArea, come superficie ove mostrare la ripresa video, bensì una superficie generata automaticamente da GStreamer;
  • sia utilizzato il metodo ".GetLastImage( )" della Classe "MediaControl" per catturare singole immagini dal video.

Anche in questo caso, come nel primo esempio, è stato riscontrato che le risorse del sistema QT danno problemi all'uso del metodo ".GetLastImage( )". E' dunque opportuno attivare in alternativa il Componente "gb.gui" o il Componente "gb.gtk", oppure il Componente "gb.gtk3".

Mostriamo di seguito un esempio pratico:

Private pl As MediaPipeline
Private snk As MediaControl


Public Sub Form_Open()
 
 Dim src As MediaControl
 Dim ftr As MediaFilter
 
  pl = New MediaPipeline
 
  src = New MediaControl(pl, "v4l2src")
  
  ftr = New MediaFilter(pl)
  ftr.Filter = "video/x-raw,width=640,height=480,framerate=30/1"
  
  snk = New MediaControl(pl, "xvimagesink")
    
  src.LinkTo(ftr)
  ftr.LinkTo(snk)
  
End


Public Sub Button1_Click()
 
 Dim i As Integer
 Dim drc, s As String
  
  drc = "/tmp/immagini"
  
  If Not Exist(drc) Then
    Mkdir drc
  Else
    For Each s In Dir(drc, "immagine_*", gb.file)
      Kill drc &/ s
    Next
  Endif
  
  pl.Play()
  
  While pl.State = Media.Playing
    snk.GetLastImage().Save(drc &/ "immagine_" & CStr(I) & ".png")
    Print "Schermata video salvata nella cartella " & drc
    Wait 0.5
    Inc i
  Wend
  
End


Public Sub Button2_Click()
  
  pl.Stop()
  pl.Close()
  
End



Note

[1] Vedi anche questa pagina della WIKI: Generare un file immagine da una DrawingArea