为什么将opencv.NewWindow()移到子函数中时程序立即终止?
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
- the call to
opencv.WaitKey(0)
should just sit there and wait for some sort of keypress - the anonymous goroutine in
GetFrameGenerator
should just keep chugging away, synchronizing withDisplayFrames
on each frame. - The OpenCV window instance is tied to the lifetime of
DisplayFrames
' call stack, which is in turn tied toframes
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.