在wx.panel中使用OpenCV和python和wxPython显示视频捕获:仅显示视频的一小部分
我正在尝试在wxPython中显示带有Python接口的OpenCV。 我可以显示它,但只能在视频的左上角显示一个小区域。 我的代码有什么问题? 它是父面板的大小还是其他什么? 请注意,我使用的代码来自 它可以完美运行,但我需要在面板(或其他父框架)中显示它 先谢谢你在wx.panel中使用OpenCV和python和wxPython显示视频捕获:仅显示视频的一小部分,python,opencv,wxpython,wxwidgets,Python,Opencv,Wxpython,Wxwidgets,我正在尝试在wxPython中显示带有Python接口的OpenCV。 我可以显示它,但只能在视频的左上角显示一个小区域。 我的代码有什么问题? 它是父面板的大小还是其他什么? 请注意,我使用的代码来自 它可以完美运行,但我需要在面板(或其他父框架)中显示它 先谢谢你 import wx import cv, cv2 class MainWindow(wx.Panel): def __init__(self, parent,capture): wx.Panel.__in
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()
这是图像:
很抱歉,由于信誉不好,我无法将图像放在这里。基本上,没有任何设置将您的
ShowCapture
窗口大小设置为所需大小,因此它仍然停留在某个默认大小。最简单的解决方案可能是根本不使用videoFrame
,因为它似乎不需要,只需使用所需的初始大小创建cap
本身,这也将成为最小窗口大小
问题更新后的后续行动:
- 项目本身会增长,即,如果您希望它在尺寸标注器的主方向上增长(垂直表示
box尺寸标注器,水平表示……您猜到了),则项目本身具有正比例;如果您希望它在另一个方向上增长,则项目本身具有wxVERTICAL
标志。当然,如果你想让它向两个方向发展,也可以两者兼而有之wxEXPAND
- 非常重要的一点常常被遗忘:内含施胶剂本身也会增长。也就是说,如果窗口本身在其大小调整器内增长,而其大小调整器没有在其自身包含的大小调整器内增长,则不会发生任何事情
videoFrame
是不必要的,事实上,如果您使用3.0以获得最佳效果,您应该使您的视频窗口成为videoWarper
的子窗口:从3.0开始,创建wxStaticBoxSizer
的内容时应将其wxStaticBox
作为父窗口感谢VZ发布的答案 现在我明白我的问题了。 小区域是由继承的
ShowCapture
的默认大小wx.Panel
造成的。
它在dc=wx中设置了dc
。BufferedPaintDC(self)
的尺寸只有20px*20px,
因此,self.bmp
,即640px*480px,仅在小区域上绘制,超过20px*20px的所有内容都被忽略
解决方案是将panel\uuuuu init\uuuu
参数更改为
class ShowCapture(wx.Panel):
def __init__(self, parent, capture, fps=24):
wx.Panel.__init__(self, parent, wx.ID_ANY, (0,0), (640,480))
请注意:
videoFrame
仍然需要,因为ShowCapture
需要父帧(用于sizer中的布局)。不知道是否有更好的方法这是我想到的,它使用
GenStaticBitmap
,它是wx.Panel
的子类,并在其OnPaint
方法中执行dc.DrawBitmap
。我通过SpinCtrl
和将鼠标悬停在右侧ROIGenStaticBitmap
控件添加了ROI选择。我还添加了一个按钮,当右键单击时保存两个图像,但当左键单击时冻结当前图像,并允许用户保存其中一个图像或两个图像。画悬停和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()
我更新了我的问题,请详细解释。对不起,我还是wxPython的初学者。