英文:
Why does my program immediately terminate when I move `opencv.NewWindow()` into a subfunction?
问题
我还在努力理解Go语言,最近遇到了一些令人困惑的行为。以下是我代码的一个工作版本:
注意,如果你想执行这些示例,你需要安装OpenCV(在Ubuntu中是libopencv-dev
包)和go-opencv(go get github.com/lazywei/go-opencv/opencv
)。
工作版本:
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 is nil")
}
}
}
}()
return frames
}
func DisplayFrames(win *opencv.Window, frames <-chan *opencv.IplImage) {
for fr := range frames {
win.ShowImage(fr)
}
}
不工作版本:
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 is 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)
}
}
直观上看,程序应该一直运行,直到被强制停止,因为:
- 对
opencv.WaitKey(0)
的调用应该只是等待某种按键操作。 GetFrameGenerator
中的匿名goroutine应该持续工作,并在每一帧上与DisplayFrames
进行同步。- OpenCV窗口实例与
DisplayFrames
的调用堆栈的生命周期相关联,而后者又与未关闭的frames
生成器相关联。
那么问题出在哪里?我漏掉了什么吗?
英文:
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?
答案1
得分: 3
我没有安装OpenCV,所以无法测试,但是类似这样的代码应该可以解决问题:
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()
只有在调用opencv.NewWindow()
之后才会阻塞。由于你在一个goroutine中调用它,你需要添加同步以确保它已经完成。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论