【问题标题】:Displaying VideoCapture using OpenCV with python and wxPython in a wx.panel: Show only small region of the video在 wx.panel 中使用 OpenCV 和 python 和 wxPython 显示 VideoCapture:仅显示视频的小区域
【发布时间】:2014-09-05 09:59:19
【问题描述】:

我正在尝试在 wxPython 中显示带有 Python 接口的 OpenCV。 我可以显示它,但只能显示视频左上角的一个小区域。 我的代码有什么问题? 是父面板的大小还是其他? 请注意,我使用来自 https://stackoverflow.com/a/14818080/2389238 的代码 它可以完美运行,但我需要在面板(或其他父框架)中显示它。

提前致谢。

import wx
import cv, cv2

class MainWindow(wx.Panel):
    def __init__(self, parent,capture):
        wx.Panel.__init__(self, parent)
        mainSizer = wx.BoxSizer(wx.VERTICAL)

        self.inputBox = wx.TextCtrl(self)
        mainSizer.Add(self.inputBox, 0, wx.ALL, 5)

        # video
        videoWarper = wx.StaticBox(self, label="Video",size=(640,480))
        videoBoxSizer = wx.StaticBoxSizer(videoWarper, wx.VERTICAL)
        videoFrame = wx.Panel(self, -1,size=(640,480))
        cap = ShowCapture(videoFrame, capture)
        videoBoxSizer.Add(videoFrame,0)
        mainSizer.Add(videoBoxSizer,0)

        parent.Centre()
        self.Show()
        self.SetSizerAndFit(mainSizer)


class ShowCapture(wx.Panel):
    def __init__(self, parent, capture, fps=24):
        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)

app = wx.App(False)
frame = wx.Frame(None,-1,'HGA Count',size=(400, 400))
panel = MainWindow(frame,capture)
frame.Show()
app.MainLoop()

这是图片:http://i58.tinypic.com/2u5t7kh.png 抱歉,由于声誉低,我无法将图片放在这里。

【问题讨论】:

    标签: python opencv wxpython wxwidgets


    【解决方案1】:

    感谢VZ的回答

    现在我明白我的问题了。 小区域是由继承ShowCapture 的默认大小wx.Panel 引起的。 它使dc = wx.BufferedPaintDC(self)中的dc只有20px*20px的尺寸, 因此,self.bmp,即 640px * 480px,仅绘制在小区域上,超过 20px*20px 的所有内容都将被忽略。

    解决方案是将面板__init__ 参数更改为

    class ShowCapture(wx.Panel):
        def __init__(self, parent, capture, fps=24):
            wx.Panel.__init__(self, parent, wx.ID_ANY, (0,0), (640,480))
    

    请注意:

    1. 不知道是否可以配置为自动调整面板大小

    2. videoFrame 仍然需要,因为 ShowCapture 需要一个父框架(用于 sizer 中的布局)。不知道有没有更好的办法。

    【讨论】:

      【解决方案2】:

      基本上,没有什么可以将您的ShowCapture 窗口大小设置为所需的大小,因此它仍然停留在某个默认大小。最简单的解决方案可能是完全不使用 videoFrame,因为它似乎不需要,只需创建具有所需初始大小的 cap 本身,这也将成为最小窗口大小。


      问题更新后跟进:

      1. 您可以使用 sizers 自动调整它的大小并确保:
        • 项目本身会增长,即如果您希望它在 sizer 的主要方向上增长(垂直为wxVERTICAL box sizer,水平为...你猜对了)或wxEXPAND 标志如果你希望它向另一个方向发展。当然,如果您希望它双向增长,或者两者兼而有之。
        • 非常重要,但经常被遗忘:包含的sizer 本身也会增长。 IE。如果窗口本身在它的 sizer 中增长,如果它的 sizer 没有在它自己的包含的 sizer 中增长,那么什么都不会发生。
      2. videoFrame 不是必需的,事实上,如果您使用 3.0 以获得最佳效果,您应该将视频窗口设为 videoWarper 的子窗口:从 3.0 开始,wxStaticBoxSizer 的内容应该使用其 @ 创建987654329@ 作为家长。

      【讨论】:

      • 我更新了我的问题,请更详细地解释。抱歉,我还是 wxPython 的初学者。
      【解决方案3】:

      这是我想出的,它使用GenStaticBitmap,它是wx.Panel 的子类,并在其OnPaint 方法中使用dc.DrawBitmap。我使用SpinCtrl 添加了 ROI 选择,还通过将鼠标悬停在右侧 ROI GenStaticBitmap 控件上。我还添加了一个按钮,当右键单击时保存两个图像,但当左键单击时冻结当前图像并允许用户保存一个图像或两者。绘制悬停和 ROI 选择十字准线很有趣,希望对其他人有所帮助!

      import wx
      from wx.lib import statbmp
      import cv, cv2
      import numpy as np
      import os
      import traceback
      
      class ChooseSaveDialog(wx.Dialog):
          def __init__(self, parent):
              wx.Dialog.__init__(self, parent)
              panel = wx.Panel(self, -1)
              sizer = wx.BoxSizer(wx.VERTICAL)
              btn1 = wx.Button(panel, -1, 'Save Original Image')
              btn2 = wx.Button(panel, -1, 'Save ROI Image')
              btn3 = wx.Button(panel, -1, 'Save Both')
              sizer.Add(btn1, 0)
              sizer.Add(btn2, 0)
              sizer.Add(btn3, 0)
              panel.SetSizer(sizer)
      
              btn1.Bind(wx.EVT_BUTTON, self.save_orig)
              btn2.Bind(wx.EVT_BUTTON, self.save_roi)
              btn3.Bind(wx.EVT_BUTTON, self.save_both)
      
          def save_orig(self, evt):
              save_dialog = wx.FileDialog(self, "Save Original to JPEG", "", "", "JPG files(*.jpg)", wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)#|wx.FD_CHANGE_DIR)
      
              if save_dialog.ShowModal() == wx.ID_OK:
                  save_path = save_dialog.GetPath()
                  if save_path[:-4].lower() != '.jpg':
                      save_path += '.jpg'
                  print save_path
                  cv2.imwrite(save_path, self.GetParent().orig_frame)
              self.EndModal(wx.OK)
      
          def save_roi(self, evt):
              save_dialog = wx.FileDialog(self, "Save ROI to JPEG", "", "", "JPG files(*.jpg)", wx.FD_SAVE|wx.FD_OVERWRITE_PROMPT)#|wx.FD_CHANGE_DIR)
      
              if save_dialog.ShowModal() == wx.ID_OK:
                  save_path = save_dialog.GetPath()
                  if save_path[:-4].lower() != '.jpg':
                      save_path += '.jpg'
                  print save_path
                  cv2.imwrite(save_path, self.GetParent().frameRoi)
              try:
                  self.EndModal(wx.OK)
              except wx.PyAssertionError:
                  pass
      
          def save_both(self, evt):
              self.save_orig(evt)
              self.save_roi(evt)
      
      
      class ShowCapture(wx.Frame):
          def __init__(self, capture, fps=15):
              wx.Frame.__init__(self, None)
              panel = wx.Panel(self, -1)
      
              #create a grid sizer with 5 pix between each cell
              sizer = wx.GridBagSizer(5, 5)
      
              self.capture = capture
              ret, frame = self.capture.read()
      
              height, width = frame.shape[:2]
              self.orig_height = height
              self.orig_width = width
      
              frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
      
              self.bmp = wx.BitmapFromBuffer(width, height, frame)
      
              self.dummy_element = wx.TextCtrl(panel, -1,'')
              self.dummy_element.Hide()
      
              #create SpinCtrl widgets, these have vertical up/down buttons and a TextCtrl that increments with up/down press
              self.roi_x = wx.SpinCtrl(panel, -1, "ROI X",  style=wx.TE_PROCESS_ENTER|wx.SP_ARROW_KEYS, min=0, max=width, initial=0, size=(60,-1))
              self.roi_y = wx.SpinCtrl(panel, -1, "ROI Y",  style=wx.TE_PROCESS_ENTER|wx.SP_ARROW_KEYS, min=0, max=height, initial=0, size=(60,-1))
              self.roi_width = wx.SpinCtrl(panel, -1, "ROI W",  style=wx.TE_PROCESS_ENTER|wx.SP_ARROW_KEYS, min=0, max=width, initial=width, size=(60,-1))
              self.roi_height = wx.SpinCtrl(panel, -1, "ROI H",  style=wx.TE_PROCESS_ENTER|wx.SP_ARROW_KEYS, min=0, max=height, initial=height, size=(60,-1))
      
              save_bmp_path = os.path.join(os.path.dirname(__file__), 'icons', 'ic_action_save.png')
              if os.path.isfile(save_bmp_path):
                  save_bmp = wx.Image(save_bmp_path).ConvertToBitmap()
                  save_button = wx.BitmapButton(panel,wx.ID_ANY, bitmap=save_bmp, style = wx.NO_BORDER, size=(32,32)) # )
              else:
                  save_button = wx.Button(panel, -1, 'Save')
      
              settings_bmp_path = os.path.join(os.path.dirname(__file__), 'icons', 'ic_action_settings.png')
              if os.path.isfile(settings_bmp_path):
                  settings_bmp = wx.Image(settings_bmp_path).ConvertToBitmap()
                  settings_button = wx.BitmapButton(panel,wx.ID_ANY, bitmap=settings_bmp, style = wx.NO_BORDER, size=(32,32)) # )
              else:
                  settings_button = wx.Button(panel, -1, 'Settings')
      
              #create image display widgets
              self.ImgControl = statbmp.GenStaticBitmap(panel, wx.ID_ANY, self.bmp)
              self.ImgControl2 = statbmp.GenStaticBitmap(panel, wx.ID_ANY, self.bmp)
      
              #add text to the sizer grid
              sizer.Add(wx.StaticText(panel, -1, 'ROI'), (0, 0), (1,2),  wx.ALL, 5)
              sizer.Add(wx.StaticText(panel, -1, 'X'), (1, 0), wx.DefaultSpan,  wx.ALL, 5)
              sizer.Add(wx.StaticText(panel, -1, 'Y'), (2, 0), wx.DefaultSpan,  wx.ALL, 5)
              sizer.Add(wx.StaticText(panel, -1, 'width,'), (1, 2), wx.DefaultSpan,  wx.ALL, 5)
              sizer.Add(wx.StaticText(panel, -1, 'height'), (2, 2), wx.DefaultSpan,  wx.ALL, 5)
              sizer.Add(wx.StaticText(panel, -1, 'Right-click image to reset ROI'), (2, 4), wx.DefaultSpan,  wx.ALL, 5)
      
              tool_button_sizer = wx.BoxSizer(wx.HORIZONTAL)
              tool_button_sizer.Add(save_button, 0)
              tool_button_sizer.Add(settings_button, 0)
              #sizer.Add(, (0, 6), wx.DefaultSpan, wx.ALIGN_RIGHT)#,  wx.ALL, 5)
              sizer.Add(tool_button_sizer, (0, 7), wx.DefaultSpan, wx.ALIGN_RIGHT)#,  wx.ALL, 5)
      
              #add SpinCtrl widgets to the sizer grid
              sizer.Add(self.roi_x, (1, 1), wx.DefaultSpan,  wx.ALL, 5)
              sizer.Add(self.roi_y, (2, 1), wx.DefaultSpan,  wx.ALL, 5)
              sizer.Add(self.roi_width, (1, 3), wx.DefaultSpan,  wx.ALL, 5)
              sizer.Add(self.roi_height, (2, 3), wx.DefaultSpan,  wx.ALL, 5)
      
              #add image widgets to the sizer grid
              sizer.Add(self.ImgControl, (3, 0), (1,4), wx.EXPAND|wx.CENTER|wx.LEFT|wx.BOTTOM, 5)
              sizer.Add(self.ImgControl2, (3, 4), (1,4), wx.EXPAND|wx.CENTER|wx.RIGHT|wx.BOTTOM, 5)
      
              #set the sizer and tell the Frame about the best size
              panel.SetSizer(sizer)
              sizer.SetSizeHints(self)
              panel.Layout()
              panel.SetFocus()
      
              #start a timer that's handler grabs a new frame and updates the image widgets
              self.timer = wx.Timer(self)
              self.fps = fps
              self.timer.Start(1000./self.fps)
      
              #bind timer events to the handler
              self.Bind(wx.EVT_TIMER, self.NextFrame)
      
              #bind events to ROI image widget
              self.ImgControl2.Bind(wx.EVT_LEFT_DOWN, self.On_ROI_Click)
              self.ImgControl2.Bind(wx.EVT_LEFT_UP, self.On_ROI_ClickRelease)
              self.ImgControl2.Bind(wx.EVT_RIGHT_DOWN, self.On_ROI_RightClick)
              self.ImgControl2.Bind(wx.EVT_MOTION, self.On_ROI_Hover)
              self.ImgControl2.Bind(wx.EVT_ENTER_WINDOW, self.On_ROI_mouse_enter)
              self.ImgControl2.Bind(wx.EVT_LEAVE_WINDOW, self.On_ROI_mouse_leave)
      
              #bind save button
              save_button.Bind(wx.EVT_BUTTON, self.on_save_click)
              save_button.Bind(wx.EVT_RIGHT_DOWN, self.on_quick_save)
      
              #bind settings button
              settings_button.Bind(wx.EVT_BUTTON, self.on_settings_click)
              settings_button.Bind(wx.EVT_LEFT_UP, self.on_settings_click_release)
      
          def on_settings_click(self, evt):
              pass
      
          def on_settings_click_release(self, evt):
              self.dummy_element.SetFocus()
      
          def on_save_click(self, evt):
              modal = ChooseSaveDialog(self)
              self.timer.Stop()
              modal.ShowModal()
              modal.Destroy()
              self.timer.Start(1000./self.fps)
      
          def on_quick_save(self, evt):
              cv2.imwrite('orig_frame.jpg', self.orig_frame)
              cv2.imwrite('frameRoi.jpg', self.frameRoi)
      
          def On_ROI_RightClick(self, evt):
              self.roi_x.SetValue(0)        
              self.roi_y.SetValue(0)
              self.roi_width.SetValue(self.orig_width)
              self.roi_height.SetValue(self.orig_height)
      
          def On_ROI_Hover(self, evt):
              self.ROI_crosshair_pos = evt.GetPosition()
      
          def On_ROI_mouse_enter(self, evt):
              self.enable_crosshairs = True
      
          def On_ROI_mouse_leave(self, evt):
              try:
                  self.enable_crosshairs = False
                  if hasattr(self, 'roi_click_down_pos'):
                      self.update_spinners(evt.GetPosition())
                  del self.roi_click_down_pos
              except AttributeError:
                  pass
      
          def On_ROI_Click(self, evt):
              self.roi_click_down_pos = evt.GetPosition()
      
          def On_ROI_ClickRelease(self, evt):
              roi_click_up_pos = evt.GetPosition()
              #if roi_click_up_pos[0] >= 0 and roi_click_up_pos[1] >= 0:
              if hasattr(self, 'roi_click_down_pos'):
                  self.update_spinners(roi_click_up_pos)
              try:
                  del self.roi_click_down_pos
              except AttributeError:
                  pass
      
          def update_spinners(self, new_pos):
              self.roi_width.SetValue(abs(new_pos[0] - self.roi_click_down_pos[0]))
              self.roi_height.SetValue(abs(new_pos[1] - self.roi_click_down_pos[1]))
              self.roi_x.SetValue(min(self.roi_click_down_pos[0], new_pos[0]))
              self.roi_y.SetValue(min(self.roi_click_down_pos[1], new_pos[1]))
      
          def NextFrame(self, event):
              ret, self.orig_frame = self.capture.read()
              if ret:
                  frame = cv2.cvtColor(self.orig_frame, cv2.COLOR_BGR2RGB)
      
                  self.bmp.CopyFromBuffer(frame)
                  self.ImgControl.SetBitmap(self.bmp)
      
                  try:
                      orig_height, orig_width = frame.shape[:2]
                      y1 = self.roi_y.GetValue()
                      y2 = y1 + self.roi_height.GetValue()
                      y2 = min(y2, orig_height)
                      x1 = self.roi_x.GetValue()
                      x2 = x1 + self.roi_width.GetValue()
                      x2 = min(x2, orig_width)
      
                      frameRoi = self.orig_frame[y1:y2, x1:x2]
                      roi_width = x2-x1
                      roi_height = y2-y1
                      #frameRoi = cv2.cvtColor(frameRoi, cv2.COLOR_BGR2GRAY )
                      #print len(frameRoi)
      
                      #frameRoi -= 110#frameRoi #* 1.25
                      #print len(frameRoi)
      
                      #frameRoi = frameRoi.clip(255.)
                      #frameRoi = (255./1)*((frameRoi/(255./1))**0.5)# 0.5
      
                      if hasattr(self, 'ROI_crosshair_pos') and self.enable_crosshairs:
                          try:
                              cross_x = self.ROI_crosshair_pos[0]
                              cross_y = self.ROI_crosshair_pos[1]
                              frameRoi[0:roi_height, cross_x:cross_x+1] = [42,0,255]
                              frameRoi[cross_y:cross_y+1, 0:roi_width] = [42,0,255]
      
                              if hasattr(self, 'roi_click_down_pos'):
                                  roi_x1 = self.roi_click_down_pos[0]
                                  roi_y1 = self.roi_click_down_pos[1]
      
                                  if cross_y>roi_y1:
                                      frameRoi[0:roi_y1, 0:roi_width] = frameRoi[0:roi_y1, 0:roi_width]*.50
                                      frameRoi[cross_y:roi_height, 0:roi_width] = frameRoi[cross_y:roi_height, 0:roi_width]*.50
                                  else:
                                      frameRoi[roi_y1:roi_height, 0:roi_width] = frameRoi[roi_y1:roi_height, 0:roi_width]*.50
                                      frameRoi[0:cross_y, 0:roi_width] = frameRoi[0:cross_y, 0:roi_width]*.50
      
                                  if cross_x>roi_x1:
                                      frameRoi[0:roi_height, 0:roi_x1] = frameRoi[0:roi_height, 0:roi_x1]*.50
                                      frameRoi[0:roi_height, cross_x:roi_width] = frameRoi[0:roi_height, cross_x:roi_width]*.50
                                  else:
                                      frameRoi[0:roi_height, roi_x1:roi_width] = frameRoi[0:roi_height, roi_x1:roi_width]*.50
                                      frameRoi[0:roi_height, 0:cross_x] = frameRoi[0:roi_height, 0:cross_x]*.50
      
      
                          except:
                              print 'couldn\'t draw crosshairs'
                              traceback.print_exc()
                      self.frameRoi = np.array(frameRoi , dtype = np.uint8)
      
                      #frameRoi = np.repeat(frameRoi, 3)
                      #frameRoi = array(newImage0,dtype=uint8)
      
                      frameRoi = cv2.cvtColor(self.frameRoi, cv2.COLOR_BGR2RGB)#GRAY2RGB)
                      self.bmp2 = wx.BitmapFromBuffer(roi_width, roi_height, frameRoi)
                      self.ImgControl2.SetBitmap(self.bmp2)
      
                  except:
                      traceback.print_exc()
      
      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 = ShowCapture( capture)
      frame.Show()
      app.MainLoop()
      

      【讨论】:

        猜你喜欢
        • 2015-10-24
        • 1970-01-01
        • 2019-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-20
        • 2017-10-23
        相关资源
        最近更新 更多