質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.51%
OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

7701閲覧

wxPythonにおいて、USBカメラの画像表示をしたい

退会済みユーザー

退会済みユーザー

総合スコア0

OpenCV

OpenCV(オープンソースコンピュータービジョン)は、1999年にインテルが開発・公開したオープンソースのコンピュータビジョン向けのクロスプラットフォームライブラリです。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2017/05/14 09:08

###前提・実現したいこと
ここ一週間くらい、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)

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

一部のみカバー、かつ具体性に欠ける内容なんですが、ラグや低fpsに関してはGUIメインループのスレッド内でリアルタイム系の処理を入れてるからじゃないかなと思いました。

wxではありませんが私も過去にGUIアプリの音声再生でプツプツ切れるという問題に悩まされたことがあり、その時は音声再生のスレッドをGUIのメインループとは別に立てることで回避しました。

よってカメラ系の処理を別スレッドに外出しして、GUIのメインループとは非同期でやり取りするようにすれば少なくともGUIの操作が滞る事はなくなると思います。

投稿2017/05/14 12:23

YouheiSakurai

総合スコア6142

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2017/05/14 13:38

Youhei様 行き詰っている中、解決につながるアイデアを頂ありがとうございます。 特に、以前の改善事例のおかげで問題の全貌が見えてきた感じがしてきました。 私も、そういえば、Pythonとは関係のないところでシングルスレッドのスクリプトで高速化するために、一部の処理を別のスクリプトに丸投げして並行して走らせる、ということをしていました。 頂いたヒントを元に修正したいと思います。
guest

0

ベストアンサー

5/19朝追記
GUIを落としてからまだ黒窓が残ってしまっています

粗削りですが…

Python

1import wx 2import os 3import cv2 4import numpy as np 5import threading 6import sys 7 8GUI_IMAGE_X = 240 9 10GUI_IMAGE_Y = 180 11CAMMODE = False 12 13######################################################################## 14class DnDPanel(wx.Panel): 15 16 #---------------------------------------------------------------------- 17 def __init__(self, parent): 18 wx.Panel.__init__(self, parent=parent) 19 20 # Image box 21 img = wx.Image(GUI_IMAGE_X,GUI_IMAGE_Y) 22 23 # Statc bitmap 24 self.imageCtrl = wx.StaticBitmap(self, wx.ID_ANY,wx.Bitmap(img)) 25 26 # Text box 27 self.fileTextCtrl = wx.TextCtrl(self,style=wx.TE_MULTILINE|wx.HSCROLL|wx.TE_READONLY) 28 29 sizer = wx.BoxSizer(wx.HORIZONTAL) 30 sizer.Add(self.imageCtrl, 1, wx.ALL, 5) 31 sizer.Add(self.fileTextCtrl, 1, wx.EXPAND|wx.ALL, 5) 32 self.SetSizer(sizer) 33 self.Fit() 34 35 #---------------------------------------------------------------------- 36 def updateText(self, text): 37 #Overwtite a text 38 self.fileTextCtrl.SetValue(text) 39 40 #Add a text 41 #self.fileTextCtrl.WriteText(text) 42 43 #---------------------------------------------------------------------- 44 def updateImage_Entity(self, cv2image): 45 46 # Calculate aspect rat 47 mag_X = GUI_IMAGE_X / cv2image.shape[1] 48 mag_Y = GUI_IMAGE_Y / cv2image.shape[0] 49 50 if mag_X < mag_Y: 51 img = cv2.resize(cv2image, None, fx = mag_X, fy = mag_X) 52 else: 53 img = cv2.resize(cv2image, None, fx = mag_Y, fy = mag_Y) 54 55 # Calculate aspect ratio diff 56 # X-axis 57 diff_X = GUI_IMAGE_X - img.shape[1] 58 diff_X_start = round(diff_X/2) 59 diff_X_end = diff_X_start + img.shape[1] 60 61 # Y-axis 62 diff_Y = GUI_IMAGE_Y - img.shape[0] 63 diff_Y_start = round(diff_Y/2) 64 diff_Y_end = diff_Y_start + img.shape[0] 65 #print("[(%s,%s) : (%s,%s)]"%(diff_X_start,diff_Y_start,diff_X_end,diff_Y_end)) 66 67 # Create modified picture 68 bg_image = np.zeros((GUI_IMAGE_Y, GUI_IMAGE_X, 3), np.uint8) 69 70 bg_image[diff_Y_start:diff_Y_end,diff_X_start:diff_X_end] = img 71 # BGR --> RGB 72 img = cv2.cvtColor(bg_image, cv2.COLOR_BGR2RGB) 73 74 # Convert color array to bitmap image 75 img = wx.Bitmap.FromBuffer(img.shape[1], img.shape[0], img) 76 77 #Static bitmap 78 self.imageCtrl.SetBitmap(img) 79 80 81######################################################################## 82class CameraControl(threading.Thread): 83 84 def __init__(self,parent): 85 threading.Thread.__init__(self) 86 87 # Prepare camera mode 88 self.panelText = DnDPanel(parent).updateText 89 self.panelImage = DnDPanel(parent).updateImage_Entity 90 91 #---------------------------------------------------------------------- 92 def run(self): 93 print("RUN時のスレッド数 : " + str(threading.activeCount())) 94 global CAMMODE 95 96 while CAMMODE == True : 97 # Get camera information : "0" is device numer 98 cap = cv2.VideoCapture(0) 99 ret, frame = cap.read() 100 while ret == False: 101 # Get camera information : "0" is device numer 102 cap = cv2.VideoCapture(0) 103 ret, frame = cap.read() 104 self.panelText("ERROR: Camera is not working.") 105 106 while ret == True: 107 cv2.waitKey(1) 108 ret, frame = cap.read() 109 self.panelText("Camera mode") 110 # Load an image to entity from file 111 self.panelImage(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) 112 113 # 複数スレッド化がうまくいていない 114 if threading.activeCount() == 1: 115 sys.exit("うまくいっていない") 116 117######################################################################## 118class DnDFrame(wx.Frame): 119 #---------------------------------------------------------------------- 120 def __init__(self): 121 self.window = wx.Frame.__init__(self, parent=None, title="GUI test", style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER) 122 123 self.InitMenu() 124 self.panel = DnDPanel(self) 125 self.Fit() 126 127 self.cc = CameraControl(self) 128 self.cc.setDaemon(True) 129 self.cc.start() 130 131 self.Show() 132 133 #---------------------------------------------------------------------- 134 # Initialize 135 def InitMenu(self): 136 # Menubar 137 menubar = wx.MenuBar() 138 fileMenu = wx.Menu() 139 f_item2 = fileMenu.Append(wx.ID_ANY, '&Camera(C)', 'Load image from USB camera') 140 fileMenu.AppendSeparator() 141 f_item3 = fileMenu.Append(wx.ID_ANY, '&Quit(Q)', 'Quit application') 142 menubar.Append(fileMenu, '&File(F)') 143 144 self.SetMenuBar(menubar) 145 146 # Event call definition 147 self.Bind(wx.EVT_MENU, self.OnCamera, f_item2) 148 self.Bind(wx.EVT_MENU, self.OnQuit, f_item3) 149 150 # Frame definition 151 self.Centre() 152 153 # Status bar 154 self.CreateStatusBar() 155 self.setstatusbarTXT("") 156 157 self.Show(True) 158 159 #---------------------------------------------------------------------- 160 # Event hander: set status text 161 def setstatusbarTXT(self, msg): 162 self.SetStatusText(msg) 163 164 #---------------------------------------------------------------------- 165 # Event: Quit 166 def OnQuit(self,event): 167 #self.Destroy() 168 sys.exit() 169 170 #---------------------------------------------------------------------- 171 # Event: Camera 172 def OnCamera(self, event): 173 global CAMMODE 174 CAMMODE = True 175 self.panel.updateText("Camera mode") 176 self.setstatusbarTXT("Camera mode") 177 178 self.cc = CameraControl(self) 179 self.cc.setDaemon(True) 180 self.cc.start() 181 182#---------------------------------------------------------------------- 183if __name__ == "__main__": 184 app = wx.App(False) 185 frame = DnDFrame() 186 app.MainLoop() 187 188

投稿2017/05/18 12:58

編集2017/05/18 22:31
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.51%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問