Opencv与wxpython的集成

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Opencv与wxpython的集成相关的知识,希望对你有一定的参考价值。

我只是想将来自我的网络摄像头的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()
答案

以下示例代码在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()
另一答案

您必须设置面板的大小以显示捕获的图像。我使用了你的代码而且我添加了“

self.SetSize(width,height)

没关系

另一答案

我有代码解决了上面的问题,但不幸的是我只能在wx.Python 2.8上运行它。对于最新的Phoenix版本(版本> 4.00),没有可见的视频面板。任何需要改变的想法?代码:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import numpy as np
import cv2
import wx
import sys, time
wxversion = wx.__version__

class webcamPanel(wx.Panel):
    def __init__(self, parent, camera, fps=10, pause=False, mirror=False):
        wx.Panel.__init__(self, parent)
        self.camera = camera
        return_value, self.frame = self.camera.read()
        height, width = self.frame.shape[:2]
        self.frame = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB)
        if mirror:
            self.frame = cv2.flip(self.frame, 1)
        if wxversion[0] == "2":
            self.bmp = wx.BitmapFromBuffer(width, height, self.frame)
        else:
            self.bmp = wx.Bitmap.FromBuffer(width, height, self.frame)
        self.SetSize((width,height))
        self.pause = pause
        self.mirror = mirror
        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 GetState(self):
        return self.pause

    def Kill(self):
        self.Pause()
        self.timer.Stop()

    def Mirror(self, mirror=None):
        if mirror is None:
            self.mirror = not self.mirror
        else:
            self.mirror = mirror

    def OnPaint(self, e):
        dc = wx.BufferedPaintDC(self)
        dc.DrawBitmap(self.bmp, 0, 0)

    def Pause(self):
        self.pause = True

    def Start(self):
        self.pause = False

    def NextFrame(self, e):
        if not self.pause:
            return_value, self.frame = self.camera.read()
            if return_value:
                self.frame = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB)
                if self.mirror:
                    self.frame = cv2.flip(self.frame, 1)
                self.bmp.CopyFromBuffer(self.frame)
                self.Refresh()

class mainWindow(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, style=wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN)
        self.Bind(wx.EVT_CLOSE, self.CloseApp)

        # Creating any menubar.
        filemenu= wx.Menu()
        filemenu.Append(101, "Open", "Open")
        filemenu.Append(102, "Save", "Save")
        filemenu.Append(wx.ID_ABOUT, "About","About")
        filemenu.Append(wx.ID_EXIT,"Exit","Close")
        menuBar = wx.MenuBar()
        menuBar.Append(filemenu,"File")
        self.SetMenuBar(menuBar)

        #main ui
        self.camera = cv2.VideoCapture(0)
        return_value, frame = self.camera.read()
        self.mirror = True
        self.height, self.width, _ = frame.shape
        self.iteration = 0
        self.webcampanel = webcamPanel(self, self.camera, mirror=self.mirror)
        self.button = wx.Button(self, label="Take Picture!")
        self.button1 = wx.Button(self, label="Toggle Camera on/off")
        self.button2 = wx.Button(self, label="Mirror")

        main_window_sizer = wx.BoxSizer(wx.VERTICAL)
        main_window_sizer.Add(self.webcampanel, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 10)
        buttonSizer = wx.BoxSizer(wx.HORIZONTAL)
        buttonSizer.Add(self.button, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 10)
        buttonSizer.Add(self.button1, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 10)
        buttonSizer.Add(self.button2, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 10)
        main_window_sizer.Add(buttonSizer, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 10)
        self.SetSizer(main_window_sizer)
        main_window_sizer.Fit(self)

        self.Bind(wx.EVT_BUTTON, self.take_picture, self.button)
        self.Bind(wx.EVT_BUTTON, self.toggle, self.button1)
        self.Bind(wx.EVT_BUTTON, self.toggle_mirror, self.button2)

    def toggle_mirror(self, event):
        self.webcampanel.Mirror()

    def take_picture(self, e):
        image = self.webcampanel.frame
        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
        # show the image in a new window!
        cv2.imshow('Snapshot!', image)

    def toggle(self, event):
        if self.webcampanel.GetState(): # pause
            self.webcampanel.Start()
        else:
            self.webcampanel.Pause()

    def CloseApp(self, event):
        self.webcampanel.Kill()
        time.sleep(.2)
        self.camera.release()
        cv2.destroyAllWindows()
        self.Destroy()
        sys.exit()

if __name__ == '__main__':
    app = wx.App()
    window = mainWindow()
    window.Show()
    window.Maximize()
    app.MainLoop()

以上是关于Opencv与wxpython的集成的主要内容,如果未能解决你的问题,请参考以下文章

opencv视屏流嵌入wxpython框架

使用 openCV 和 wxPython 从网络摄像头获取流

rasberry pi 4的相机与opencv集成

在Ubuntu中打开文件时出现wxPython错误

在 Python 多处理进程中运行较慢的 OpenCV 代码片段

wxPython:一曲MFC的挽歌,理想主义的绝唱