###前提・実現したいこと
ここ一週間くらい、teratailの皆様の力を借りながら、python上で動く動画や画像を表示できるGUIを作っています。画像は何とか表示でき、画像とパネルとでアスペクト比が合っていないときには黒帯をつけてアスペクト比を合わせるところまで来ました。
###発生している問題
- OpenCV上の画像をwxPythonに表示させる段階で画像がおかしくなる
次の段階としてWEBカメラの写真を表示できるようにしている段階です。メニューバーからカメラモードに切り替えその後USBカメラから画像を取り込み、OpenCV上の画像をパネル上に表示させるところでこけています。
※上の画像には本当は壁が写っているはずなのですが、真っ黒の画像の上の部分にちょろちょろと白い粒が並んでいる状態になってしまっています。
- カメラ使用中にラグがひどくなる
カメラモードにすると、GUIの操作が滞るほどにラグ(0.2fps程度)が発生します。CUI+OpenCVのサンプル(while trueループ内でimshowを繰り返すもの)はほとんどラグがなく、同じくらいのレベル(3 fps以上)を目標にしています。
長いコードでごめんなさい
Python
1import wx 2import os 3import sys 4import cv2 5import numpy as np 6 7GUI_IMAGE_X = 240 8GUI_IMAGE_Y = 180 9TIMER_MS = 1000 10 11class MyFileDropTarget(wx.FileDropTarget): 12 def __init__(self, panel): 13 wx.FileDropTarget.__init__(self) 14 self.panel = panel 15 16 def OnDropFiles(self, x, y, filenames): 17 self.panel.Release_camera() 18 for filepath in filenames: 19 extention = "." + str(str(filenames).split(".")[-1:][-1])[:-2] 20 wildcard = [".jpg",".jpeg",".png",".bmp",".mpg",".mpeg",".mp2",".mp4",".avi"] 21 if extention in wildcard: 22 self.panel.updateImage_from_file(filepath) 23 self.panel.updateText(filepath) 24self.panel.GetTopLevelParent().setstatusbarTXT(filepath) 25 else: 26 self.panel.updateImage_from_file("") 27 self.panel.GetTopLevelParent().setstatusbarTXT("Not supported file.") 28 return True 29 30class DnDPanel(wx.Panel): 31 32 def __init__(self, parent): 33 wx.Panel.__init__(self, parent=parent) 34 file_drop_target = MyFileDropTarget(self) 35 img = wx.Image(GUI_IMAGE_X,GUI_IMAGE_Y) 36 self.imageCtrl = wx.StaticBitmap(self, wx.ID_ANY,wx.Bitmap(img)) 37 self.fileTextCtrl = wx.TextCtrl(self,style=wx.TE_MULTILINE|wx.HSCROLL|wx.TE_READONLY) 38 self.SetDropTarget(file_drop_target) 39 sizer = wx.BoxSizer(wx.HORIZONTAL) 40 sizer.Add(self.imageCtrl, 1, wx.ALL, 5) 41 sizer.Add(self.fileTextCtrl, 1, wx.EXPAND|wx.ALL, 5) 42 self.SetSizer(sizer) 43 self.Fit() 44 self.timer = wx.Timer(self) 45 46 def cam_check(self): 47 capture = cv2.VideoCapture(0) 48 if capture.isOpened() is False: 49 self.timer.Stop() 50 capture.release() 51 return False 52 else: 53 capture.release() 54 return True 55 56 def updateText(self, text): 57 #Overwtite a text 58 self.fileTextCtrl.SetValue(text) 59 60 def Camera_mode(self): 61 # Connection check 62 if self.cam_check() == False: 63 self.updateText("ERROR: Camera is not connected.") 64 return False 65 66 # Start timer event 67 self.Bind(wx.EVT_TIMER,self.On_CamTimer) 68 self.timer.Start(TIMER_MS) 69 70 def On_CamTimer(self,event): 71 cap = cv2.VideoCapture(0) 72 73 #Auto toggle camera mode 74 ret, frame = cap.read() 75 if ret == False: 76 self.timer.Stop() 77 capture.release() 78 return False 79 self.updateImage_Entity(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) 80 cap.release() 81 82 def updateImage_Entity(self, cv2image): 83 # Calculate aspect rat 84 mag_X = GUI_IMAGE_X / cv2image.shape[1] 85 mag_Y = GUI_IMAGE_Y / cv2image.shape[0] 86 87 if mag_X < mag_Y: 88 img = cv2.resize(cv2image, None, fx = mag_X, fy = mag_X) 89 else: 90 img = cv2.resize(cv2image, None, fx = mag_Y, fy = mag_Y) 91 92 # X-axis 93 diff_X = GUI_IMAGE_X - img.shape[1] 94 diff_X_start = round(diff_X/2) 95 diff_X_end = diff_X_start + img.shape[1] 96 97 # Y-axis 98 diff_Y = GUI_IMAGE_Y - img.shape[0] 99 diff_Y_start = round(diff_Y/2) 100 diff_Y_end = diff_Y_start + img.shape[0] 101 102 # combine 103 bg_image = np.zeros((GUI_IMAGE_Y, GUI_IMAGE_X, 3), np.uint8) 104 105bg_image[diff_Y_start:diff_Y_end,diff_X_start:diff_X_end] = img 106 107 # BGR --> RGB 108 img = cv2.cvtColor(bg_image, cv2.COLOR_BGR2RGB) 109 110 #cv2.imshow("END",img ) 111 #cv2.waitKey(0) 112 #cv2.destroyAllWindows() 113 114 # Convert 115 img = wx.Bitmap.FromBuffer(img.shape[1], img.shape[0], img) 116 117 self.imageCtrl.SetBitmap(img) 118 119 def updateImage_from_file(self, fileaddress): 120 121 if not os.path.exists(fileaddress): 122 self.updateText("File not found.") 123 self.GetTopLevelParent().setstatusbarTXT("Please drop/load a image file.") 124 return False 125 self.updateImage_Entity(cv2.imread(fileaddress , cv2.IMREAD_COLOR)) 126 127 def Release_camera(self): 128 self.timer.Stop() 129 self.updateText("Camera is released.") 130 self.cam_check() 131 132class DnDFrame(wx.Frame): 133 def __init__(self): 134 self.window = wx.Frame.__init__(self, parent=None, title="GUI test", style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER) 135 136 self.InitMenu() 137 self.panel = DnDPanel(self) 138 self.Fit() 139 self.Show() 140 141 # Initialize 142 def InitMenu(self): 143 144 menubar = wx.MenuBar() 145 fileMenu = wx.Menu() 146 f_item1 = fileMenu.Append(wx.ID_ANY, '&Load file(L)', 'Load image file') 147 f_item2 = fileMenu.Append(wx.ID_ANY, '&Camera(C)', 'Load image from USB camera') 148 fileMenu.AppendSeparator() 149 f_item3 = fileMenu.Append(wx.ID_ANY, '&Quit(Q)', 'Quit application') 150 menubar.Append(fileMenu, '&File(F)') 151 helpMenu = wx.Menu() 152 h_item1 = helpMenu.Append(wx.ID_ANY, '&About(A)', 'About this program') 153 menubar.Append(helpMenu, '&Help(H)') 154 self.SetMenuBar(menubar) 155 self.Bind(wx.EVT_MENU, self.OnLoad, f_item1) 156 self.Bind(wx.EVT_MENU, self.OnCamera, f_item2) 157 self.Bind(wx.EVT_MENU, self.OnQuit, f_item3) 158 self.Bind(wx.EVT_MENU, self.OnAbout, h_item1) 159 self.Centre() 160 self.CreateStatusBar() 161 self.setstatusbarTXT("Please drop/load a image file.") 162 self.Show(True) 163 164 def OnLoad(self, event): 165 self.panel.Release_camera() 166 self.dirname = '' 167 wildcard = "Supported media files (*.jpg,*.jpeg,*.png,*.bmp))|*.jpg;*.jpeg;*.png;*.bmp" 168 dlg = wx.FileDialog(self, "Please select a file.", self.dirname,defaultFile="", wildcard=wildcard,style= wx.FD_OPEN ) 169 if dlg.ShowModal() == wx.ID_OK: 170 self.filename = dlg.GetFilename() 171 self.dirname = dlg.GetDirectory() 172 fileaddress = self.dirname + "\\" + self.filename 173 if not os.path.exists(fileaddress): 174 self.panel.updateText("File notot found.") 175 self.setstatusbarTXT("Please drop/load a image file.") 176 self.panel.updateImage_from_file("") 177 else: 178 with open(os.path.join(self.dirname, self.filename), 'r') as f: 179 self.panel.updateText(fileaddress) 180 self.panel.updateImage_from_file(fileaddress) 181 self.setstatusbarTXT(fileaddress) 182 else: 183 self.panel.updateText("") 184 self.setstatusbarTXT("Please drop/load a image file.") 185 dlg.Destroy() 186 187 def setstatusbarTXT(self, msg): 188 self.SetStatusText(msg) 189 190 def OnQuit(self,event): 191 self.panel.Release_camera() 192 self.Destroy() 193 194 def OnCamera(self, event): 195 self.panel.updateText("Camera mode") 196 self.setstatusbarTXT("Camera mode") 197 198 self.panel.Camera_mode() 199 200 def OnAbout(self, event): 201 self.panel.Release_camera() 202 about_window=About_window(self,"About this program") 203 204 try: 205 about_window.ShowModal() 206 finally: 207 about_window.Destroy() 208 return True 209 210class About_window(wx.Dialog): 211 212 def __init__(self, parent,title): 213 wx.Dialog.__init__(self, parent, title=title) 214 self.InitUI() 215 216 def InitUI(self): 217 pnl = wx.Panel(self) 218 vbox = wx.BoxSizer(wx.VERTICAL) 219 self.text = wx.TextCtrl(pnl, size = (-1,100),style = wx.TE_MULTILINE|wx.TE_READONLY) 220 self.btn1 = wx.Button(pnl, label = "OK") 221 self.Bind(wx.EVT_BUTTON,self.OnClick, self.btn1) 222 223 vbox.Add(self.text, proportion = 1, flag = wx.EXPAND|wx.ALIGN_CENTRE) 224 vbox.Add(self.btn1, proportion = 0.1, flag = wx.ALIGN_RIGHT) 225 pnl.SetSizer(vbox) 226 self.Show(True) 227 228 try: 229 f = open(README_FILE , 'r') 230 data = f.read() 231 self.text.SetValue(data) 232 233 # Except IOError as e: 234 except: 235 self.text.SetValue("\"" + README_FILE + "\" is not appropriate.") 236 237 def OnClick(self, e): 238 self.Destroy() 239 240if __name__ == "__main__": 241 app = wx.App(False) 242 frame = DnDFrame() 243 app.MainLoop()
###試したこと
コメントアウトしてありますが、updateImage_Entityの部分で処理の段階ごとにimshowをして動作確認をしました。それでも、GUIに表示させるところでコケています。通常の画像は表示出来てカメラは黒塗り白ごま画像になってしまて行き詰っています。
###補足情報(言語/FW/ツール等のバージョンなど)
Win10(64bit)
Python 3.5.3(64bit)
wxPython 4.0.0a1 (Phoenix)

回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
退会済みユーザー
2017/05/14 13:38