Opencv 与 wxpython 的集成
Posted
技术标签:
【中文标题】Opencv 与 wxpython 的集成【英文标题】:Opencv integration with wxpython 【发布时间】:2013-01-26 02:49:47 【问题描述】:我只是想将来自我的网络摄像头的 opencv 视频流集成到一个比 highgui 所能提供的更复杂的 gui 中,没有什么特别的,只是几个按钮和其他东西,但事实证明它并不是那么微不足道。我找不到任何可以开始设计 gui 的基本示例。 我尝试将这个code 转换为新的opencv 接口,结果很差。我是 opencv、numpy 和 gui 设计的新手。有时确实会流式传输视频,但大多数时候它只是挂在那里。我想我的一个错误可能是在 wx.BitmapFromBuffer(col, row, img) 中,因为在旧版本中他们使用 pil 图像格式,现在它使用 numpy 数组,所以在原始代码中使用了 pil 函数“imageData”,而不是正如我正在做的那样直接传递numpy数组。 非常感谢任何帮助。
这是我的代码转换。
import wx
import cv2
class MyFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent)
self.displayPanel = wx.Panel(self)
self.displayPanel.SetSize(wx.Size(800,640))
self.cam = cv2.VideoCapture(1)
self.cam.set(3, 640)
self.cam.set(4, 480)
ret, img = self.cam.read()
cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
row, col, x = img.shape
self.SetSize((col,row))
self.bmp = wx.BitmapFromBuffer(col, row, img)
self.displayPanel.Bind(wx.EVT_PAINT, self.onPaint)
self.playTimer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.onNextFrame)
self.playTimer.Start(1000/15)
def onPaint(self, evt):
if self.bmp:
dc = wx.BufferedPaintDC(self.displayPanel)
self.PrepareDC(dc)
dc.DrawBitmap(self.bmp, 0, 0, True)
evt.Skip()
def onNextFrame(self, evt):
ret, img = self.cam.read()
if ret == True:
cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
self.bmp.CopyFromBuffer(img)
self.displayPanel.Refresh()
evt.Skip()
if __name__=="__main__":
app = wx.App()
MyFrame(None).Show()
app.MainLoop()
【问题讨论】:
您的代码对我不起作用,但经过细微调整后就可以了。我看到的问题是,例如,当我调整窗口大小时,流被中断,直到我停止调整大小。但是,如果我不触摸窗户,它就会继续进行下去。除了简单地显示框架之外,您还在做其他事情吗? @mmgp 你是对的,如果我评论我设置大小的两行,它可以工作,虽然我想我正在失去颜色通道。我附上了图片。 关于颜色,cvtColor
不会原地发生,因此您必须将其结果重新分配给 img
。
@mmgp 现在除了显示捕获的帧外,我没有执行任何其他操作,即使我打算这样做也很难。
如果你有一个函数f(x)
不能就地运行,你必须将结果分配给某个东西才能保存结果。 cvtColor
就是这样一种功能。
【参考方案1】:
下面的示例代码在 OS X 下对我来说很好,但是我对跨平台的 wx 有一些小小的惊喜。这几乎是相同的代码,不同之处在于重新分配了cvtColor
的结果,并添加了wx.Panel
的子类(这是重要部分)。
import wx
import cv, cv2
class ShowCapture(wx.Panel):
def __init__(self, parent, capture, fps=15):
wx.Panel.__init__(self, parent)
self.capture = capture
ret, frame = self.capture.read()
height, width = frame.shape[:2]
parent.SetSize((width, height))
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
self.bmp = wx.BitmapFromBuffer(width, height, frame)
self.timer = wx.Timer(self)
self.timer.Start(1000./fps)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.Bind(wx.EVT_TIMER, self.NextFrame)
def OnPaint(self, evt):
dc = wx.BufferedPaintDC(self)
dc.DrawBitmap(self.bmp, 0, 0)
def NextFrame(self, event):
ret, frame = self.capture.read()
if ret:
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
self.bmp.CopyFromBuffer(frame)
self.Refresh()
capture = cv2.VideoCapture(0)
capture.set(cv.CV_CAP_PROP_FRAME_WIDTH, 320)
capture.set(cv.CV_CAP_PROP_FRAME_HEIGHT, 240)
app = wx.App()
frame = wx.Frame(None)
cap = ShowCapture(frame, capture)
frame.Show()
app.MainLoop()
【讨论】:
为什么你将面板子类化而不是框架?不应该是 wx.Frame wx 层次结构中的第一个“容器”吗?我猜第二个导入在 OSX 上也不起作用,因为要从 cv2 访问旧的 cv,您需要导入 cv2.cv。您的代码可以在我的机器上运行,顺便说一句,它是基于 linux debian 的机器,但是它没有将大小框架设置为 640X480。 我可以在 OSX 中很好地导入cv
。框架肯定没有设置为640 x 480
,因为在示例中它设置为320 x 240
,您是否尝试更改它?正在创建 wx.Frame
,它是 wx.Panel
子类的父级。
我尝试使用新模块和旧模块更改大小,但是一旦我调整它的大小,它就不再刷新并且再次开始崩溃。
“调整大小”是指调整运行程序的窗口大小吗?如前所述,当我调整此窗口的大小时,我也会停止获取更新。但它不会使程序崩溃。崩溃是指程序退出吗?也许您收到的错误消息可能会有用。
对不起,我没有说清楚我的意思是它变得没有响应并且它停止自我更新。【参考方案2】:
您必须设置面板的大小才能显示捕获的图像。 我使用了你的代码并添加了“
self.SetSize(width,height)
没关系
【讨论】:
【参考方案3】:您应该为下面的行添加注释
#self.PrepareDC(dc)
它对我有用。
【讨论】:
以上是关于Opencv 与 wxpython 的集成的主要内容,如果未能解决你的问题,请参考以下文章
设置上的wxpython错误 - ModuleNotFound:没有名为'wx'的模块
使用 openCV 和 wxPython 从网络摄像头获取流