簡體   English   中英

在wx.panel中使用OpenCV和python以及wxPython顯示VideoCapture:僅顯示視頻的小區域

[英]Displaying VideoCapture using OpenCV with python and wxPython in a wx.panel: Show only small region of the video

我試圖在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對不起,由於聲譽低,我無法將圖像放在此處。

感謝VZ發布的答案

現在我明白了我的問題。 較小的區域是由繼承ShowCapturewx.Panel的默認大小引起的。 它使dcdc = wx.BufferedPaintDC(self)曾在尺寸只有20像素* 20像素,所以self.bmp ,這是640像素* 480像素,繪制僅在小區域和一切說謊超出20像素* 20像素被忽略。

解決方案是將面板__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需要(在定徑機進行布局)父幀。 不知道是否有更好的方法。

基本上,沒有任何東西將您的ShowCapture窗口大小設置為所需的大小,因此它仍然保持某種默認大小。 最簡單的解決方案可能是沒有videoFrame ,因為它似乎不需要,只需創建具有所需初始大小的cap本身,這也將成為最小窗口大小。


問題更新后的跟進:

  1. 您可以使用sizer自動調整大小並確保:
    • 項目本身增長,即如果你希望它在sizer的主要方向上增長( wxVERTICAL box sizer垂直,水平為...你猜對了),或者wxEXPAND標志,如果你想讓它在另一個增長方向。 或者兩者,當然,如果你想讓它在兩個方向上成長。
    • 非常重要,因為經常被遺忘:包含sizer本身也會增長。 即如果窗口本身在其sizer中生長,如果其sizer不會在其自己的sizer內生長,則不會發生任何事情。
  2. videoFrame不是必需的,事實上,如果你使用3.0以獲得最佳結果,你應該讓你的視頻窗口成為videoWarper孩子:從3.0開始, wxStaticBoxSizer的內容應該以其wxStaticBox作為父級創建。

這就是我GenStaticBitmap ,它使用GenStaticBitmap ,它是wx.Panel的子類,並在其OnPaint方法中執行dc.DrawBitmap 我使用SpinCtrl添加ROI選擇, SpinCtrl懸停在右側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()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM