From d1b78ca038fde514f98716561848bb1e1fab8dd8 Mon Sep 17 00:00:00 2001 From: Martyn Ranyard Date: Sun, 12 Dec 2021 01:12:03 +0100 Subject: [PATCH] Webcam with working ticker --- examples/webcam/main.go | 50 +++++++++++++++++++++ pkg/webcam/webcam.go | 97 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 examples/webcam/main.go create mode 100644 pkg/webcam/webcam.go diff --git a/examples/webcam/main.go b/examples/webcam/main.go new file mode 100644 index 0000000..9135600 --- /dev/null +++ b/examples/webcam/main.go @@ -0,0 +1,50 @@ +package main + +import ( + "strconv" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/app" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/widget" + "git.martyn.berlin/martyn/fyne-widgets/pkg/layouts" + "git.martyn.berlin/martyn/fyne-widgets/pkg/webcam" +) + +var webcamID int +var webcamLabel *widget.Label +var webcamWidget *webcam.Webcam + +func switchWebcam(id int) { + webcamLabel.Text = "Webcam: " + strconv.Itoa(id) + webcamLabel.Refresh() + webcamWidget.WebcamID = int64(id) + webcamWidget.Refresh() +} + +func incWebCamID() { + webcamID = webcamID + 1 + switchWebcam(webcamID) +} + +func decWebCamID() { + webcamID = webcamID - 1 + switchWebcam(webcamID) +} + +func main() { + a := app.New() + w := a.NewWindow("Webcam") + + webcamWidget = webcam.NewWebcam() + layout := layouts.NewFloatingControlsLayout() + layout.FloatingControlsLocation = layouts.FloatingControlsCenter + webcamID = 0 + + webcamLabel = widget.NewLabel("Webcam: 0") + buttons := container.NewHBox(webcamLabel, widget.NewButton("-", decWebCamID), widget.NewButton("+", incWebCamID)) + + w.SetContent(container.New(&layout, webcamWidget, buttons)) + w.Resize(fyne.NewSize(640, 480)) + w.ShowAndRun() +} diff --git a/pkg/webcam/webcam.go b/pkg/webcam/webcam.go new file mode 100644 index 0000000..b5870d9 --- /dev/null +++ b/pkg/webcam/webcam.go @@ -0,0 +1,97 @@ +package webcam + +import ( + "image" + "image/color" + "time" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/canvas" + "fyne.io/fyne/v2/widget" + "gocv.io/x/gocv" +) + +var _ fyne.WidgetRenderer = (*webcamRenderer)(nil) + +type Webcam struct { + widget.BaseWidget + + WebcamID int64 + UpdateFPS int64 + fpsTimer *time.Ticker +} + +func NewWebcam() *Webcam { + w := &Webcam{} + w.ExtendBaseWidget(w) + w.WebcamID = 0 + w.UpdateFPS = 25 + + return w +} + +func (w *Webcam) Resize(s fyne.Size) { + w.BaseWidget.Resize(s) +} + +func (w *Webcam) CreateRenderer() fyne.WidgetRenderer { + fpsTimer := time.NewTicker(time.Duration(1000/25) * time.Millisecond) + go func(w *Webcam) { + for { + _ = <-fpsTimer.C + w.Refresh() + } + }(w) + return newWebcamRenderer(w) +} + +type webcamRenderer struct { + webcam *Webcam + background *canvas.Rectangle + currentframe *canvas.Raster + goCVVideoCapture *gocv.VideoCapture +} + +func renderframe(w, h int) image.Image { + frameImage := image.NewRGBA(image.Rect(0, 0, w, h)) + return frameImage +} + +func (r *webcamRenderer) actualrenderframe(w, h int) image.Image { + webcam, _ := gocv.VideoCaptureDevice(int(r.webcam.WebcamID)) + img := gocv.NewMat() + webcam.Read(&img) + frameImage, _ := img.ToImage() //no point doing anything other than returning anyway! + return frameImage +} + +func newWebcamRenderer(w *Webcam) *webcamRenderer { + renderer := &webcamRenderer{ + webcam: w, + background: canvas.NewRectangle(color.RGBA{255, 0, 255, 255}), + } + renderer.currentframe = canvas.NewRaster(renderer.actualrenderframe) + return renderer +} + +func (r *webcamRenderer) Objects() []fyne.CanvasObject { + // The order is critical, rect is drawn first then currentframe + return []fyne.CanvasObject{r.background, r.currentframe} +} + +func (r *webcamRenderer) Layout(s fyne.Size) { + r.background.Resize(s) + r.currentframe.Resize(s) +} + +func (r *webcamRenderer) MinSize() fyne.Size { + return fyne.NewSize(200, 200) +} + +func (r *webcamRenderer) Refresh() { + r.currentframe.Refresh() +} + +func (r *webcamRenderer) Destroy() { + r.webcam.fpsTimer.Stop() +} // Called when the renderer is destroyed