Golang : Another camera capture GUI application with GTK and OpenCV




For those that prefer to use GTK over Qt, this is another tutorial/example to show you how to create a GUI application similar to Apple's PhotoBooth with GTK instead of Qt.

In this example, we will create a "floating" toolbar similar to Photoshop's floating toolbar concept. This is purely for performance reason and allow us to skip the transformation of OpenCV's IplImage(Intel Image Processing Library) to QImage or GDK Pixbuf.

GUI-golang-GTK-OpenCV example

We will use the Golang-GTK binding at https://mattn.github.io/go-gtk/. If you prefer to use https://github.com/gotk3/gotk3, please change the code example that follows.

To get the code example below running, first please

>brew install gtk

or

>brew install gtk+3

and

>go get -u https://mattn.github.io/go-gtk

>go get -u github.com/lazywei/go-opencv/opencv

Here you go!


 package main

 import (
  "fmt"
  "os"
  "strconv"
  "strings"

  "github.com/lazywei/go-opencv/opencv"
  "github.com/mattn/go-gtk/glib"
  "github.com/mattn/go-gtk/gtk"
 )

 var (
  win = new(opencv.Window)
  webCamera = new(opencv.Capture)
  statusbar = new(gtk.Statusbar)
  snapshotFileName string
  width, height int
  sliderPos int
  filterOn = true
  snapPhoto = false
 )

 func savePhoto(img *opencv.IplImage) {
  // snap photo
  if snapPhoto {
 fmt.Println("Snapshot save to : ", snapshotFileName)
 // params - to set jpeg quality
 // but unable to pass params []int slice to opencv...

 os.Remove(snapshotFileName) // remove previous save file - ignoring error!
 opencv.SaveImage(snapshotFileName, img, opencv.CV_IMWRITE_JPEG_QUALITY)

 snapPhoto = false // reset to false again
  }
 }

 // from https://github.com/lazywei/go-opencv/blob/master/samples/webcam.go
 func applyFilters(img *opencv.IplImage) {

  w := img.Width()
  h := img.Height()

  // Create the output image
  cedge := opencv.CreateImage(w, h, opencv.IPL_DEPTH_8U, 3)
  defer cedge.Release()

  // Convert to grayscale
  gray := opencv.CreateImage(w, h, opencv.IPL_DEPTH_8U, 1)
  edge := opencv.CreateImage(w, h, opencv.IPL_DEPTH_8U, 1)
  defer gray.Release()
  defer edge.Release()

  opencv.CvtColor(img, gray, opencv.CV_BGR2GRAY)

  opencv.Smooth(gray, edge, opencv.CV_BLUR, 3, 3, 0, 0)
  opencv.Not(gray, edge)

  // Run the edge detector on grayscale
  opencv.Canny(gray, edge, float64(sliderPos), float64(sliderPos*3), 3)

  opencv.Zero(cedge)
  // copy edge points
  opencv.Copy(img, cedge, edge)

  // update here. if update in the for loop... the image frames will be corrupted.
  win.ShowImage(cedge)
  savePhoto(cedge)
 }

 func processFrameAndUpdate() {

  for {

 if webCamera.GrabFrame() {
 IplImgFrame := webCamera.RetrieveFrame(1)
 if IplImgFrame != nil {
 // Have to make the image frame
 // smaller, so that it does not blow up the GUI application.
 IplImgFrame = opencv.Resize(IplImgFrame, 0, height-200, opencv.CV_INTER_LINEAR)

 if filterOn == true {
 applyFilters(IplImgFrame)
 } else {
 sliderPos = 0 // otherwise the save file will be blurred
 win.ShowImage(IplImgFrame)
 savePhoto(IplImgFrame)
 }

 // apply filters
 //*IplImgFrame = applyFilters(IplImgFrame)

 //win.ShowImage(IplImgFrame) -- will cause alien EMP attack on images. WTF!

 }
 }

  }

 }

 func main() {

  if len(os.Args) != 2 {
 fmt.Printf("Usage : %s <save to filename>\n", os.Args[0])
 os.Exit(0)
  }

  snapshotFileName = os.Args[1]

  if !strings.HasSuffix(snapshotFileName, ".jpg") {
 snapshotFileName += ".jpg"
  }

  fmt.Println("Will be saving snapshot image to : ", snapshotFileName)

  // a new OpenCV window
  win = opencv.NewWindow("Go-OpenCV camera feed for Gtk-GUI")
  defer win.Destroy()

  // activate webCamera
  webCamera = opencv.NewCameraCapture(opencv.CV_CAP_ANY) // autodetect

  if webCamera == nil {
 panic("Unable to open camera")
  }

  defer webCamera.Release()

  // get some data from camera
  width = int(webCamera.GetProperty(opencv.CV_CAP_PROP_FRAME_WIDTH))
  height = int(webCamera.GetProperty(opencv.CV_CAP_PROP_FRAME_HEIGHT))

  fmt.Println("Camera width : ", width)
  fmt.Println("Camera height : ", height)

  // open up a new "pure" OpenCV window first
  go processFrameAndUpdate() // goroutine to update feed from camera

  // then our "floating" GTK toolbar
  gtk.Init(nil)
  window := gtk.NewWindow(gtk.WINDOW_TOPLEVEL)

  window.SetPosition(gtk.WIN_POS_CENTER)
  window.SetTitle("Golang-GTK-OpenCV-AppleBooth-Example!")
  window.SetIconName("gtk-dialog-info")
  window.Connect("destroy", func(ctx *glib.CallbackContext) {
 println("got destroy!", ctx.Data().(string))
 gtk.MainQuit()
  }, "Happy coding!")

  vbox := gtk.NewVBox(false, 1)

  //--------------------------------------------------------
  // GtkVPaned
  //--------------------------------------------------------
  vpaned := gtk.NewVPaned()
  vbox.Add(vpaned)


  frame2 := gtk.NewFrame("Control panel with scroll bar and buttons(GUI) for OpenCV")
  framebox2 := gtk.NewVBox(false, 1)
  frame2.Add(framebox2)

  //--------------------------------------------------------
  // GtkScale
  //--------------------------------------------------------
  scaleHBox := gtk.NewHBox(false, 1)

  scale := gtk.NewHScaleWithRange(0, 100, 1)
  scale.Connect("value-changed", func() {
 
 sliderPos = int(scale.GetValue())
 statusbar.Push(statusbar.GetContextId("go-gtk"), "Position value : "+strconv.Itoa(sliderPos))
  })
  scaleHBox.Add(scale)
  framebox2.PackStart(scaleHBox, false, false, 0)

  vpaned.Pack2(frame2, false, false)

  //--------------------------------------------------------
  // GtkHBox
  //--------------------------------------------------------
  buttons := gtk.NewHBox(false, 1)

  //--------------------------------------------------------
  // GtkButton
  //--------------------------------------------------------
  button := gtk.NewButtonWithLabel("Take a snapshot!")
  button.Clicked(func() {
 snapPhoto = true
  })
  buttons.Add(button)

  quitButton := gtk.NewButtonWithLabel("Quit")
  quitButton.Clicked(func() {
 gtk.MainQuit()
  })

  buttons.Add(quitButton)
  framebox2.PackStart(buttons, false, false, 0)


  //--------------------------------------------------------
  // GtkVSeparator
  //--------------------------------------------------------
  vsep := gtk.NewVSeparator()
  framebox2.PackStart(vsep, false, false, 0)

  statusbar = gtk.NewStatusbar()
  context_id := statusbar.GetContextId("go-gtk")

  combos := gtk.NewHBox(false, 1)
  //--------------------------------------------------------
  // GtkStatusbar and GtkComboBox
  //--------------------------------------------------------
  combobox := gtk.NewComboBoxNewText()
  combobox.AppendText("Yes")
  combobox.AppendText("No")
  combobox.SetActive(0) // yes
  combobox.Connect("changed", func() {
 println("value:", combobox.GetActiveText())

 if combobox.GetActiveText() == "Yes" {
 statusbar.Push(context_id, "Applying filter.")
 filterOn = true
 } else {
 statusbar.Push(context_id, "Not applying filter.")
 filterOn = false
 }
  })
  combos.Add(combobox)

  framebox2.PackStart(combos, false, false, 0)

  //--------------------------------------------------------
  // GtkStatusbar
  //--------------------------------------------------------
  framebox2.PackStart(statusbar, false, false, 0)

  //--------------------------------------------------------
  // Event
  //--------------------------------------------------------
  window.Add(vbox)
  window.SetSizeRequest(400, 115)
  window.ShowAll()

  gtk.Main()

 }

  See also : Golang : GUI with Qt and OpenCV to capture image from camera





By Adam Ng

IF you gain some knowledge or the information here solved your programming problem. Please consider donating to the less fortunate or some charities that you like. Apart from donation, planting trees, volunteering or reducing your carbon footprint will be great too.


Advertisement