I'm still trying to wrap my head around the Go language and I've just come across some rather confusing behavior. Here is a working version of my code:
Note, you will need to install OpenCV (package libopencv-dev
in Ubuntu) and go-opencv (go get github.com/lazywei/go-opencv/opencv
) if you want to execute these examples.
Working:
package main
import (
"fmt"
"github.com/lazywei/go-opencv/opencv"
)
func main() {
win := opencv.NewWindow("Go-OpenCV Webcam")
defer win.Destroy()
frames := GetFrameGenerator()
go DisplayFrames(win, frames)
opencv.WaitKey(0)
}
func GetFrameGenerator() chan *opencv.IplImage {
frames := make(chan *opencv.IplImage)
cap := opencv.NewCameraCapture(0)
if cap == nil {
panic("cannot open camera")
}
go func() {
defer cap.Release()
for {
if cap.GrabFrame() {
img := cap.RetrieveFrame(1)
if img != nil {
frames <- img
} else {
fmt.Println("Image ins nil")
}
}
}
}()
return frames
}
func DisplayFrames(win *opencv.Window, frames <-chan *opencv.IplImage) {
for fr := range frames {
win.ShowImage(fr)
}
}
Not Working:
package main
import (
"fmt"
"github.com/lazywei/go-opencv/opencv"
)
func main() {
frames := GetFrameGenerator()
go DisplayFrames(frames)
opencv.WaitKey(0)
}
func GetFrameGenerator() chan *opencv.IplImage {
frames := make(chan *opencv.IplImage)
cap := opencv.NewCameraCapture(0)
if cap == nil {
panic("cannot open camera")
}
go func() {
defer cap.Release()
for {
if cap.GrabFrame() {
img := cap.RetrieveFrame(1)
if img != nil {
frames <- img
} else {
fmt.Println("Image ins nil")
}
}
}
}()
return frames
}
func DisplayFrames(frames <-chan *opencv.IplImage) {
win := opencv.NewWindow("Go-OpenCV Webcam")
defer win.Destroy()
for fr := range frames {
win.ShowImage(fr)
}
}
Intuitively, it seems as though the program should run until it is forcibly stopped because
opencv.WaitKey(0)
should just sit there and wait for some sort of keypressGetFrameGenerator
should just keep chugging away, synchronizing with DisplayFrames
on each frame.DisplayFrames
' call stack, which is in turn tied to frames
generator being unclosed.So what gives? What am I missing, here?
I don't have opencv installed so I could not test, but something like this should do the trick:
package main
import (
"fmt"
"github.com/lazywei/go-opencv/opencv"
)
func main() {
frames := GetFrameGenerator()
ready := make(chan struct{})
defer close(ready)
go DisplayFrames(frames, ready)
<-ready
opencv.WaitKey(0)
}
func GetFrameGenerator() chan *opencv.IplImage {
frames := make(chan *opencv.IplImage)
cap := opencv.NewCameraCapture(0)
if cap == nil {
panic("cannot open camera")
}
go func() {
defer cap.Release()
for {
if cap.GrabFrame() {
img := cap.RetrieveFrame(1)
if img != nil {
frames <- img
} else {
fmt.Println("Image ins nil")
}
}
}
}()
return frames
}
func DisplayFrames(frames <-chan *opencv.IplImage, ready <-chan struct{}) {
win := opencv.NewWindow("Go-OpenCV Webcam")
defer win.Destroy()
ready <- struct{}{}
for fr := range frames {
win.ShowImage(fr)
}
}
opencv.WaitKey() will block only if opencv.NewWindow() has been called. As you are calling it in a goroutine, you need to add synchronization to make sure it has been done.