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.
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
Tutorials
+9.3k Golang : Changing a RGBA image number of channels with OpenCV
+10.9k Golang : How to determine a prime number?
+10.5k Android Studio : Checkbox for user to select options example
+8.3k Golang : Add text to image and get OpenCV's X, Y co-ordinates example
+5.9k Golang : Convert Chinese UTF8 characters to Pin Yin
+11.7k Golang : Convert decimal number(integer) to IPv4 address
+9.5k Golang : Detect number of active displays and the display's resolution
+78.6k Golang : How to return HTTP status code?
+7.1k Golang : Calculate how many weeks left to go in a given year
+33.6k Golang : convert(cast) bytes to string
+5.8k Javascript : Get operating system and browser information
+12.3k Golang : Arithmetic operation with numerical slices or arrays example