diff --git a/imagepy/T1.jpg b/imagepy/T1.jpg new file mode 100644 index 00000000..5f34d74f Binary files /dev/null and b/imagepy/T1.jpg differ diff --git a/imagepy/T2.jpg b/imagepy/T2.jpg new file mode 100644 index 00000000..cb5dd27b Binary files /dev/null and b/imagepy/T2.jpg differ diff --git a/imagepy/core/engine/simple.py b/imagepy/core/engine/simple.py index b989ea09..faa6894f 100644 --- a/imagepy/core/engine/simple.py +++ b/imagepy/core/engine/simple.py @@ -24,12 +24,12 @@ def __init__(self, ips=None): print('simple start') self.ips = IPy.get_ips() if ips==None else ips self.dialog = None - + def progress(self, i, n): self.prgs = (i, n) def load(self, ips):return True - + def preview(self, ips, para):pass def show(self, temp=ParaDialog): @@ -41,16 +41,16 @@ def show(self, temp=ParaDialog): self.dialog.on_ok = lambda : self.ok(self.ips) self.dialog.on_cancel = lambda : self.cancel(self.ips) self.dialog.Show() - + def run(self, ips, imgs, para = None):pass - + def cancel(self, ips):pass def ok(self, ips, para=None, callafter=None): if para == None: para = self.para if IPy.uimode() == 'no': self.runasyn(ips, ips.imgs, para, callafter) - else: threading.Thread(target = self.runasyn, + else: threading.Thread(target = self.runasyn, args = (ips, ips.imgs, para, callafter)).start() win = WidgetsManager.getref('Macros Recorder') if win!=None: win.write('{}>{}'.format(self.title, para)) @@ -99,7 +99,7 @@ def check(self, ips): IPy.alert('stack3d required!') return False return True - + def start(self, para=None, callback=None): #print self.title, para if not self.check(self.ips):return @@ -118,4 +118,4 @@ def start(self, para=None, callback=None): self.ok(self.ips, para, callback) else:self.cancel(self.ips) if not self.dialog is None: self.dialog.Destroy() - else: self.show() \ No newline at end of file + else: self.show() diff --git a/imagepy/core/engine/tool.py b/imagepy/core/engine/tool.py index ec7054e6..d9c82c33 100644 --- a/imagepy/core/engine/tool.py +++ b/imagepy/core/engine/tool.py @@ -6,10 +6,58 @@ from ... import IPy from ...core.manager import ToolsManager +from wx import * +import wx, platform +# import wx, platform + +menu_titles = [ "Open", + "Properties", + "Rename", + "Delete" ] + +menu_title_by_id = {} +for title in menu_titles: + # menu_title_by_id[ wxNewId() ] = title + menu_title_by_id[ wx.NewId() ] = title + +list_title = "files" +list_items = [ "binding.py", + "clipboard.py", + "config.py", + "debug.py", + "dialog.py", + "dispatch.py", + "error.py", ] + class Tool: title = 'Tool' view, para = None, None - + list = None + + def popUpInit(self, **key): + box = wx.BoxSizer(wx.VERTICAL) + + # Make and layout the controls + fs = key['canvas'].GetFont().GetPointSize() + bf = wx.Font(fs+4, wx.SWISS, wx.NORMAL, wx.BOLD) + nf = wx.Font(fs+2, wx.SWISS, wx.NORMAL, wx.NORMAL) + + t = wx.StaticText(key['canvas'], -1, "PopupMenu") + t.SetFont(bf) + + box.Add(t, 0, wx.CENTER|wx.ALL, 5) + box.Add(wx.StaticLine(key['canvas'], -1), 0, wx.EXPAND) + box.Add((10,20)) + + # text = 'hello' + # t = wx.StaticText(key['canvas'], -1, text) + # t.SetFont(nf) + # box.Add(t, 0, wx.CENTER|wx.ALL, 5) + t.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu) + + key['canvas'].SetSizer(box) + key['canvas'].Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu) + def show(self): if self.view == None:return rst = IPy.get_para(self.title, self.view, self.para) @@ -29,4 +77,248 @@ def start(self): def mouse_down(self, ips, x, y, btn, **key): pass def mouse_up(self, ips, x, y, btn, **key): pass def mouse_move(self, ips, x, y, btn, **key): pass - def mouse_wheel(self, ips, x, y, d, **key): pass \ No newline at end of file + def mouse_wheel(self, ips, x, y, d, **key): pass + + def OnContextMenu(self, **key): + print("OnContextMenu\n") + + # only do this part the first time so the events are only bound once + # + # Yet another anternate way to do IDs. Some prefer them up top to + # avoid clutter, some prefer them close to the object of interest + # for clarity. + if not hasattr(self, "popupID1"): + self.popupID1 = wx.NewId() + self.popupID2 = wx.NewId() + self.popupID3 = wx.NewId() + # self.popupID4 = wx.NewId() + # self.popupID5 = wx.NewId() + # self.popupID6 = wx.NewId() + # self.popupID7 = wx.NewId() + # self.popupID8 = wx.NewId() + # self.popupID9 = wx.NewId() + + self.Bind(wx.EVT_MENU, self.OnPopupOne, id=self.popupID1) + self.Bind(wx.EVT_MENU, self.OnPopupTwo, id=self.popupID2) + self.Bind(wx.EVT_MENU, self.OnPopupThree, id=self.popupID3) + # self.Bind(wx.EVT_MENU, self.OnPopupFour, id=self.popupID4) + # self.Bind(wx.EVT_MENU, self.OnPopupFive, id=self.popupID5) + # self.Bind(wx.EVT_MENU, self.OnPopupSix, id=self.popupID6) + # self.Bind(wx.EVT_MENU, self.OnPopupSeven, id=self.popupID7) + # self.Bind(wx.EVT_MENU, self.OnPopupEight, id=self.popupID8) + # self.Bind(wx.EVT_MENU, self.OnPopupNine, id=self.popupID9) + + # make a menu + menu = wx.Menu() + # Show how to put an icon in the menu + item = wx.MenuItem(menu, self.popupID1,"One") + # bmp = images.Smiles.GetBitmap() + # item.SetBitmap(bmp) + menu.AppendItem(item) + # add some other items + menu.Append(self.popupID2, "Two") + menu.Append(self.popupID3, "Three") + # menu.Append(self.popupID4, "Four") + # menu.Append(self.popupID5, "Five") + # menu.Append(self.popupID6, "Six") + # make a submenu + # sm = wx.Menu() + # sm.Append(self.popupID8, "sub item 1") + # sm.Append(self.popupID9, "sub item 1") + # menu.AppendMenu(self.popupID7, "Test Submenu", sm) + + + # Popup the menu. If an item is selected then its handler + # will be called before PopupMenu returns. + key['canvas'].PopupMenu(menu) + menu.Destroy() + + def OnPopupOne(self): + print("Popup one\n") + + def OnPopupTwo(self): + print("Popup two\n") + + def OnPopupThree(self): + print("Popup three\n") + + def dropmenue(self, ips, x, y, btn, list_items, **key): + # build listF + if not self.list: + list_title = 'test' + self.list = wx.ListCtrl( key['canvas'],pos=(x,y), size=(1, 10),style=wx.LC_REPORT) + self.list.InsertColumn( 0, list_title ) + + + for i, x in enumerate(list_items): + self.list.InsertStringItem(0,x) + self.list.EnsureVisible(i) + + ### 1. Register source's EVT_s to invoke launcher. ### + EVT_LIST_ITEM_RIGHT_CLICK( self.list, -1, self.RightClickCb ) + # clear variables + self.list_item_clicked = None + + # # show & run + key['canvas'].Show(1) + + # def dropmenue(self, ips, x, y, btn, list_items, **key): + + box = wx.BoxSizer(wx.VERTICAL) + + # Make and layout the controls + fs = key['canvas'].GetFont().GetPointSize() + bf = wx.Font(fs+4, wx.SWISS, wx.NORMAL, wx.BOLD) + nf = wx.Font(fs+2, wx.SWISS, wx.NORMAL, wx.NORMAL) + + t = wx.StaticText(key['canvas'], -1, "PopupMenu") + t.SetFont(bf) + box.Add(t, 0, wx.CENTER|wx.ALL, 5) + + box.Add(wx.StaticLine(key['canvas'], -1), 0, wx.EXPAND) + box.Add((10,20)) + + text = 'PopUp Menu' + t = wx.StaticText(key['canvas'], -1, text) + t.SetFont(nf) + box.Add(t, 0, wx.CENTER|wx.ALL, 5) + t.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu) + + self.SetSizer(box) + + self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu) + # return 1 + def RightClickCb( self, event ): + # record what was clicked + self.list_item_clicked = right_click_context = event.GetText() + + ### 2. Launcher creates wxMenu. ### + menu = wx.Menu() + for (id,title) in menu_title_by_id.items(): + ### 3. Launcher packs menu with Append. ### + menu.Append( id, title ) + ### 4. Launcher registers menu handlers with EVT_MENU, on the menu. ### + EVT_MENU( menu, id, self.MenuSelectionCb ) + + ### 5. Launcher displays menu with call to PopupMenu, invoked on the source component, passing event's GetPoint. ### + key['canvas'].PopupMenu( menu, event.GetPoint() ) + menu.Destroy() # destroy to avoid mem leak + + def MenuSelectionCb( self, event ): + # do something + operation = menu_title_by_id[ event.GetId() ] + target = self.list_item_clicked + print( 'Perform "%(operation)s" on "%(target)s."' % vars()) + def OnContextMenu(self, event): + self.log.WriteText("OnContextMenu\n") + + # only do this part the first time so the events are only bound once + # + # Yet another anternate way to do IDs. Some prefer them up top to + # avoid clutter, some prefer them close to the object of interest + # for clarity. + if not hasattr(key['canvas'], "popupID1"): + self.popupID1 = wx.NewId() + self.popupID2 = wx.NewId() + self.popupID3 = wx.NewId() + self.popupID4 = wx.NewId() + self.popupID5 = wx.NewId() + self.popupID6 = wx.NewId() + self.popupID7 = wx.NewId() + self.popupID8 = wx.NewId() + self.popupID9 = wx.NewId() + + self.Bind(wx.EVT_MENU, self.OnPopupOne, id=self.popupID1) + self.Bind(wx.EVT_MENU, self.OnPopupTwo, id=self.popupID2) + self.Bind(wx.EVT_MENU, self.OnPopupThree, id=self.popupID3) + self.Bind(wx.EVT_MENU, self.OnPopupFour, id=self.popupID4) + self.Bind(wx.EVT_MENU, self.OnPopupFive, id=self.popupID5) + self.Bind(wx.EVT_MENU, self.OnPopupSix, id=self.popupID6) + self.Bind(wx.EVT_MENU, self.OnPopupSeven, id=self.popupID7) + self.Bind(wx.EVT_MENU, self.OnPopupEight, id=self.popupID8) + self.Bind(wx.EVT_MENU, self.OnPopupNine, id=self.popupID9) + + # make a menu + menu = wx.Menu() + # Show how to put an icon in the menu + item = wx.MenuItem(menu, self.popupID1,"One") + bmp = images.Smiles.GetBitmap() + item.SetBitmap(bmp) + menu.AppendItem(item) + # add some other items + menu.Append(self.popupID2, "Two") + menu.Append(self.popupID3, "Three") + menu.Append(self.popupID4, "Four") + menu.Append(self.popupID5, "Five") + menu.Append(self.popupID6, "Six") + # make a submenu + sm = wx.Menu() + sm.Append(self.popupID8, "sub item 1") + sm.Append(self.popupID9, "sub item 1") + menu.AppendMenu(self.popupID7, "Test Submenu", sm) + + + # Popup the menu. If an item is selected then its handler + # will be called before PopupMenu returns. + self.PopupMenu(menu) + menu.Destroy() + + def OnContextMenu(self, event): + self.log.WriteText("OnContextMenu\n") + # only do this part the first time so the events are only bound once + # + # Yet another anternate way to do IDs. Some prefer them up top to + # avoid clutter, some prefer them close to the object of interest + # for clarity. + if not hasattr(self, "popupID1"): + self.popupID1 = wx.NewId() + self.popupID2 = wx.NewId() + self.popupID3 = wx.NewId() + self.popupID4 = wx.NewId() + self.popupID5 = wx.NewId() + self.popupID6 = wx.NewId() + self.popupID7 = wx.NewId() + self.popupID8 = wx.NewId() + self.popupID9 = wx.NewId() + + self.Bind(wx.EVT_MENU, self.OnPopupOne, id=self.popupID1) + self.Bind(wx.EVT_MENU, self.OnPopupTwo, id=self.popupID2) + self.Bind(wx.EVT_MENU, self.OnPopupThree, id=self.popupID3) + self.Bind(wx.EVT_MENU, self.OnPopupFour, id=self.popupID4) + self.Bind(wx.EVT_MENU, self.OnPopupFive, id=self.popupID5) + self.Bind(wx.EVT_MENU, self.OnPopupSix, id=self.popupID6) + self.Bind(wx.EVT_MENU, self.OnPopupSeven, id=self.popupID7) + self.Bind(wx.EVT_MENU, self.OnPopupEight, id=self.popupID8) + self.Bind(wx.EVT_MENU, self.OnPopupNine, id=self.popupID9) + + # make a menu + menu = wx.Menu() + # Show how to put an icon in the menu + item = wx.MenuItem(menu, self.popupID1,"One") + bmp = images.Smiles.GetBitmap() + item.SetBitmap(bmp) + menu.AppendItem(item) + # add some other items + menu.Append(self.popupID2, "Two") + menu.Append(self.popupID3, "Three") + menu.Append(self.popupID4, "Four") + menu.Append(self.popupID5, "Five") + menu.Append(self.popupID6, "Six") + # make a submenu + sm = wx.Menu() + sm.Append(self.popupID8, "sub item 1") + sm.Append(self.popupID9, "sub item 1") + menu.AppendMenu(self.popupID7, "Test Submenu", sm) + + + # Popup the menu. If an item is selected then its handler + # will be called before PopupMenu returns. + self.PopupMenu(menu) + menu.Destroy() + def OnPopupOne(self, event): + self.log.WriteText("Popup one\n") + + +# dropmenue方法,传入一个[(title, function), ...] + + \ No newline at end of file diff --git a/imagepy/core/engine/toolFormal.py b/imagepy/core/engine/toolFormal.py new file mode 100644 index 00000000..d1515d3b --- /dev/null +++ b/imagepy/core/engine/toolFormal.py @@ -0,0 +1,237 @@ +# -*- coding: utf-8 -*- +""" +Created on Sat Dec 3 03:55:51 2016 +@author: yxl +""" +from ... import IPy +from ...core.manager import ToolsManager + +from wx import * +import wx, platform +# import wx, platform + +menu_titles = [ "Open", + "Properties", + "Rename", + "Delete" ] + +menu_title_by_id = {} +for title in menu_titles: + # menu_title_by_id[ wxNewId() ] = title + menu_title_by_id[ wx.NewId() ] = title + +list_title = "files" +list_items = [ "binding.py", + "clipboard.py", + "config.py", + "debug.py", + "dialog.py", + "dispatch.py", + "error.py", ] + +class Tool: + title = 'Tool' + view, para = None, None + list = None + + def show(self): + if self.view == None:return + rst = IPy.get_para(self.title, self.view, self.para) + if rst!=None : self.config() + + def config(self):pass + def load(self):pass + def switch(self):pass + + def start(self): + ips = IPy.get_ips() + if not ips is None and not ips.tool is None: + ips.tool = None + ips.update = True + ToolsManager.set(self) + + + def mouse_down(self, ips, x, y, btn, **key): pass + def mouse_up(self, ips, x, y, btn, **key): pass + def mouse_move(self, ips, x, y, btn, **key): pass + def mouse_wheel(self, ips, x, y, d, **key): pass + # def dropmenue(self, ips, x, y, btn, list_items, **key): + # # build listF + # if not self.list: + # list_title = 'test' + # self.list = wx.ListCtrl( key['canvas'],pos=(x,y), size=(1, 10),style=wx.LC_REPORT) + # self.list.InsertColumn( 0, list_title ) + + + # for i, x in enumerate(list_items): + # self.list.InsertStringItem(0,x) + # self.list.EnsureVisible(i) + + # ### 1. Register source's EVT_s to invoke launcher. ### + # EVT_LIST_ITEM_RIGHT_CLICK( self.list, -1, self.RightClickCb ) + # # clear variables + # self.list_item_clicked = None + + # # # show & run + # key['canvas'].Show(1) + + def dropmenue(self, ips, x, y, btn, list_items, **key): + + box = wx.BoxSizer(wx.VERTICAL) + + # Make and layout the controls + fs = key['canvas'].GetFont().GetPointSize() + bf = wx.Font(fs+4, wx.SWISS, wx.NORMAL, wx.BOLD) + nf = wx.Font(fs+2, wx.SWISS, wx.NORMAL, wx.NORMAL) + + t = wx.StaticText(key['canvas'], -1, "PopupMenu") + t.SetFont(bf) + box.Add(t, 0, wx.CENTER|wx.ALL, 5) + + box.Add(wx.StaticLine(key['canvas'], -1), 0, wx.EXPAND) + box.Add((10,20)) + + text = 'PopUp Menu' + t = wx.StaticText(key['canvas'], -1, text) + t.SetFont(nf) + box.Add(t, 0, wx.CENTER|wx.ALL, 5) + t.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu) + + self.SetSizer(box) + + self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu) + # return 1 + def RightClickCb( self, event ): + # record what was clicked + self.list_item_clicked = right_click_context = event.GetText() + + ### 2. Launcher creates wxMenu. ### + menu = wx.Menu() + for (id,title) in menu_title_by_id.items(): + ### 3. Launcher packs menu with Append. ### + menu.Append( id, title ) + ### 4. Launcher registers menu handlers with EVT_MENU, on the menu. ### + EVT_MENU( menu, id, self.MenuSelectionCb ) + + ### 5. Launcher displays menu with call to PopupMenu, invoked on the source component, passing event's GetPoint. ### + key['canvas'].PopupMenu( menu, event.GetPoint() ) + menu.Destroy() # destroy to avoid mem leak + + def MenuSelectionCb( self, event ): + # do something + operation = menu_title_by_id[ event.GetId() ] + target = self.list_item_clicked + print( 'Perform "%(operation)s" on "%(target)s."' % vars()) + def OnContextMenu(self, event): + self.log.WriteText("OnContextMenu\n") + + # only do this part the first time so the events are only bound once + # + # Yet another anternate way to do IDs. Some prefer them up top to + # avoid clutter, some prefer them close to the object of interest + # for clarity. + if not hasattr(key['canvas'], "popupID1"): + self.popupID1 = wx.NewId() + self.popupID2 = wx.NewId() + self.popupID3 = wx.NewId() + self.popupID4 = wx.NewId() + self.popupID5 = wx.NewId() + self.popupID6 = wx.NewId() + self.popupID7 = wx.NewId() + self.popupID8 = wx.NewId() + self.popupID9 = wx.NewId() + + self.Bind(wx.EVT_MENU, self.OnPopupOne, id=self.popupID1) + self.Bind(wx.EVT_MENU, self.OnPopupTwo, id=self.popupID2) + self.Bind(wx.EVT_MENU, self.OnPopupThree, id=self.popupID3) + self.Bind(wx.EVT_MENU, self.OnPopupFour, id=self.popupID4) + self.Bind(wx.EVT_MENU, self.OnPopupFive, id=self.popupID5) + self.Bind(wx.EVT_MENU, self.OnPopupSix, id=self.popupID6) + self.Bind(wx.EVT_MENU, self.OnPopupSeven, id=self.popupID7) + self.Bind(wx.EVT_MENU, self.OnPopupEight, id=self.popupID8) + self.Bind(wx.EVT_MENU, self.OnPopupNine, id=self.popupID9) + + # make a menu + menu = wx.Menu() + # Show how to put an icon in the menu + item = wx.MenuItem(menu, self.popupID1,"One") + bmp = images.Smiles.GetBitmap() + item.SetBitmap(bmp) + menu.AppendItem(item) + # add some other items + menu.Append(self.popupID2, "Two") + menu.Append(self.popupID3, "Three") + menu.Append(self.popupID4, "Four") + menu.Append(self.popupID5, "Five") + menu.Append(self.popupID6, "Six") + # make a submenu + sm = wx.Menu() + sm.Append(self.popupID8, "sub item 1") + sm.Append(self.popupID9, "sub item 1") + menu.AppendMenu(self.popupID7, "Test Submenu", sm) + + + # Popup the menu. If an item is selected then its handler + # will be called before PopupMenu returns. + self.PopupMenu(menu) + menu.Destroy() + + def OnContextMenu(self, event): + self.log.WriteText("OnContextMenu\n") + # only do this part the first time so the events are only bound once + # + # Yet another anternate way to do IDs. Some prefer them up top to + # avoid clutter, some prefer them close to the object of interest + # for clarity. + if not hasattr(self, "popupID1"): + self.popupID1 = wx.NewId() + self.popupID2 = wx.NewId() + self.popupID3 = wx.NewId() + self.popupID4 = wx.NewId() + self.popupID5 = wx.NewId() + self.popupID6 = wx.NewId() + self.popupID7 = wx.NewId() + self.popupID8 = wx.NewId() + self.popupID9 = wx.NewId() + + self.Bind(wx.EVT_MENU, self.OnPopupOne, id=self.popupID1) + self.Bind(wx.EVT_MENU, self.OnPopupTwo, id=self.popupID2) + self.Bind(wx.EVT_MENU, self.OnPopupThree, id=self.popupID3) + self.Bind(wx.EVT_MENU, self.OnPopupFour, id=self.popupID4) + self.Bind(wx.EVT_MENU, self.OnPopupFive, id=self.popupID5) + self.Bind(wx.EVT_MENU, self.OnPopupSix, id=self.popupID6) + self.Bind(wx.EVT_MENU, self.OnPopupSeven, id=self.popupID7) + self.Bind(wx.EVT_MENU, self.OnPopupEight, id=self.popupID8) + self.Bind(wx.EVT_MENU, self.OnPopupNine, id=self.popupID9) + + # make a menu + menu = wx.Menu() + # Show how to put an icon in the menu + item = wx.MenuItem(menu, self.popupID1,"One") + bmp = images.Smiles.GetBitmap() + item.SetBitmap(bmp) + menu.AppendItem(item) + # add some other items + menu.Append(self.popupID2, "Two") + menu.Append(self.popupID3, "Three") + menu.Append(self.popupID4, "Four") + menu.Append(self.popupID5, "Five") + menu.Append(self.popupID6, "Six") + # make a submenu + sm = wx.Menu() + sm.Append(self.popupID8, "sub item 1") + sm.Append(self.popupID9, "sub item 1") + menu.AppendMenu(self.popupID7, "Test Submenu", sm) + + + # Popup the menu. If an item is selected then its handler + # will be called before PopupMenu returns. + self.PopupMenu(menu) + menu.Destroy() + def OnPopupOne(self, event): + self.log.WriteText("Popup one\n") + + +# dropmenue方法,传入一个[(title, function), ...] + + \ No newline at end of file diff --git a/imagepy/core/loader/loader.py b/imagepy/core/loader/loader.py index 22afe7a3..75c8d8d0 100644 --- a/imagepy/core/loader/loader.py +++ b/imagepy/core/loader/loader.py @@ -21,9 +21,9 @@ def getpath(root, path): def extend_plugins(path, lst, err): rst = [] for i in lst: - if isinstance(i, tuple) or i=='-': + if isinstance(i, tuple) or i=='-': rst.append(i) - + elif i[-3:] == '.mc': pt = os.path.join(root_dir,path) f = open(pt+'/'+i, 'r', 'utf-8') @@ -46,7 +46,7 @@ def extend_plugins(path, lst, err): rst.extend([j if j=='-' else Widget(j) for j in plg.wgts]) for p in plg.wgts: if not isinstance(p, str):WidgetsManager.add(p) - else: + else: rst.append(Widget(plg.Plugin)) WidgetsManager.add(plg.Plugin) except Exception as e: @@ -60,14 +60,14 @@ def extend_plugins(path, lst, err): rst.extend([j for j in plg.plgs]) for p in plg.plgs: if not isinstance(p, str):PluginsManager.add(p) - else: + else: rst.append(plg.Plugin) PluginsManager.add(plg.Plugin) except Exception as e: err.append((path, i, sys.exc_info()[1])) return rst - + def sort_plugins(catlog, lst): rst = [] for i in catlog: @@ -78,7 +78,7 @@ def sort_plugins(catlog, lst): rst.append(j) rst.extend(lst) return rst - + def build_plugins(path, err=False): root = err in (True, False) if root: sta, err = err, [] @@ -86,6 +86,8 @@ def build_plugins(path, err=False): cont = os.listdir(os.path.join(root_dir, path)) for i in cont: subp = os.path.join(path,i) + print('build_plugins in :{}'.format(subp)) + if os.path.isdir(os.path.join(root_dir, subp)): sub = build_plugins(subp, err) if len(sub)!=0:subtree.append(sub) @@ -94,20 +96,23 @@ def build_plugins(path, err=False): elif i[-3:] in ('.mc', '.md'): subtree.append(i) if len(subtree)==0:return [] - + rpath = path.replace('/', '.').replace('\\','.') #rpath = rpath[rpath.index('imagepy.'):] pg = __import__('imagepy.'+rpath,'','',['']) pg.title = os.path.basename(path) if hasattr(pg, 'catlog'): subtree = sort_plugins(pg.catlog, subtree) + + print('path:{}'.format(path)) + subtree = extend_plugins(path, subtree, err) - + if root and sta and len(err)>0: IPy.write('some plugin may be not loaded, but not affect otheres!') for i in err: IPy.write('>>> %-50s%-20s%s'%i) - return (pg, subtree) - + return (pg, subtree) + def extend_tools(path, lst, err): rst = [] for i in lst: @@ -116,23 +121,23 @@ def extend_tools(path, lst, err): f = open(pt+'/'+i) cmds = f.readlines() f.close() - rst.append((Macros(i[:-3], [getpath(pt, i) for i in cmds]), + rst.append((Macros(i[:-3], [getpath(pt, i) for i in cmds]), os.path.join(root_dir, path)+'/'+i[:-3]+'.gif')) else: try: rpath = path.replace('/', '.').replace('\\','.') #rpath = rpath[rpath.index('imagepy.'):] - + plg = __import__('imagepy.'+rpath+'.'+i,'','',['']) - if hasattr(plg, 'plgs'): + if hasattr(plg, 'plgs'): for i,j in plg.plgs: rst.append((i, path+'/'+j)) - else: rst.append((plg.Plugin, + else: rst.append((plg.Plugin, os.path.join(root_dir, path)+'/'+i.split('_')[0]+'.gif')) except Exception as e: err.append((path, i, sys.exc_info()[1])) for i in rst:ToolsManager.add(i[0]) return rst - + def sort_tools(catlog, lst): rst = [] for i in catlog: @@ -143,7 +148,7 @@ def sort_tools(catlog, lst): rst.append(j) rst.extend(lst) return rst - + def build_tools(path, err=False): root = err in (True, False) if root: sta, err = err, [] @@ -167,12 +172,12 @@ def build_tools(path, err=False): pg.title = os.path.basename(path) if hasattr(pg, 'catlog'): subtree = sort_tools(pg.catlog, subtree) - if not root:subtree = extend_tools(path, subtree, err) - elif sta and len(err)>0: + if not root:subtree = extend_tools(path, subtree, err) + elif sta and len(err)>0: IPy.write('tools not loaded:') for i in err: IPy.write('>>> %-50s%-20s%s'%i) return (pg, subtree) - + def extend_widgets(path, lst, err): rst = [] for i in lst: @@ -185,7 +190,7 @@ def extend_widgets(path, lst, err): err.append((path, i, sys.exc_info()[1])) for i in rst:WidgetsManager.add(i) return rst - + def sort_widgets(catlog, lst): rst = [] for i in catlog: @@ -196,7 +201,7 @@ def sort_widgets(catlog, lst): rst.append(j) rst.extend(lst) return rst - + def build_widgets(path, err=False): root = err in (True, False) if root: sta, err = err, [] @@ -219,8 +224,8 @@ def build_widgets(path, err=False): if hasattr(pg, 'catlog'): subtree = sort_widgets(pg.catlog, subtree) if not root: - subtree = extend_widgets(path, subtree, err) - elif sta and len(err)>0: + subtree = extend_widgets(path, subtree, err) + elif sta and len(err)>0: IPy.write('widgets not loaded:') for i in err: IPy.write('>>> %-50s%-20s%s'%i) return (pg, subtree) diff --git a/imagepy/menus/Plugins/Install/installplg_plgs.py b/imagepy/menus/Plugins/Install/installplg_plgs.py index a5752f63..ba3dfdc8 100644 --- a/imagepy/menus/Plugins/Install/installplg_plgs.py +++ b/imagepy/menus/Plugins/Install/installplg_plgs.py @@ -28,7 +28,7 @@ def Schedule(a,b,c, plg): class Install(Free): title = 'Install Plugins' - para = {'pkg':''} + para = {'pkg':'https://github.com/Image-Py/IBook'} prgs = (0, 100) view = [('lab', None, 'input a zipfile url or github url as http://github.com/username/project'), (str, 'pkg', 'package', '')] @@ -51,7 +51,7 @@ def run(self, para=None): zipf = zipfile.ZipFile(os.path.join(path_cache, domain+'_'+name+'.zip')) folder = zipf.namelist()[0] zipf.extractall(path_cache) - destpath = os.path.join(path_plgs, domain+'_'+folder).replace('-master','') + destpath = os.path.join(path_plgs, domain+'_'+folder.replace('-master','')) if os.path.exists(destpath): shutil.rmtree(destpath) os.rename(os.path.join(path_cache, folder), destpath) zipf.close() diff --git a/imagepy/menus/Plugins/Manager/plgtree_wgt.py b/imagepy/menus/Plugins/Manager/plgtree_wgt.py index df8c1147..6fdf0706 100644 --- a/imagepy/menus/Plugins/Manager/plgtree_wgt.py +++ b/imagepy/menus/Plugins/Manager/plgtree_wgt.py @@ -10,56 +10,57 @@ from imagepy import IPy, root_dir from imagepy.core.loader import loader from wx.py.editor import EditorFrame +from glob import glob class Plugin ( wx.Panel ): title = 'Plugin Tree View' single = None def __init__( self, parent ): - wx.Panel.__init__ ( self, parent, id = wx.ID_ANY, - pos = wx.DefaultPosition, size = wx.Size( 500,300 ), + wx.Panel.__init__ ( self, parent, id = wx.ID_ANY, + pos = wx.DefaultPosition, size = wx.Size( 500,300 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL ) bSizer1 = wx.BoxSizer( wx.HORIZONTAL ) - - self.tre_plugins = wx.TreeCtrl( self, wx.ID_ANY, wx.DefaultPosition, + + self.tre_plugins = wx.TreeCtrl( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.TR_DEFAULT_STYLE ) - self.tre_plugins.SetMinSize( wx.Size( 200,-1 ) ) - + # self.tre_plugins.SetMinSize( wx.Size( 200,-1 ) ) + self.tre_plugins.SetMinSize( wx.Size( 300,-1 ) ) bSizer1.Add( self.tre_plugins, 0, wx.ALL|wx.EXPAND, 5 ) bSizer3 = wx.BoxSizer( wx.VERTICAL ) bSizer4 = wx.BoxSizer( wx.HORIZONTAL ) - + self.m_staticText2 = wx.StaticText( self, wx.ID_ANY, "Plugin Infomation:", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText2.Wrap( -1 ) bSizer4.Add( self.m_staticText2, 0, wx.ALL, 5 ) - - self.m_staticText3 = wx.StaticText( self, wx.ID_ANY, "[SourceCode]", + + self.m_staticText3 = wx.StaticText( self, wx.ID_ANY, "[SourceCode]", wx.DefaultPosition, wx.DefaultSize, 0 ) self.m_staticText3.Wrap( -1 ) self.m_staticText3.SetForegroundColour( wx.SystemSettings.GetColour( wx.SYS_COLOUR_HIGHLIGHT ) ) - + bSizer4.Add( self.m_staticText3, 0, wx.ALL, 5 ) bSizer3.Add( bSizer4, 0, wx.EXPAND, 5 ) - - self.txt_info = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, + + self.txt_info = wx.TextCtrl( self, wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, wx.TE_MULTILINE ) bSizer3.Add( self.txt_info, 1, wx.ALL|wx.EXPAND, 5 ) - - + + bSizer1.Add( bSizer3, 1, wx.EXPAND, 5 ) self.SetSizer( bSizer1 ) self.Layout() - + self.Centre( wx.BOTH ) - + # Connect Events self.tre_plugins.Bind( wx.EVT_TREE_ITEM_ACTIVATED, self.on_run ) self.tre_plugins.Bind( wx.EVT_TREE_SEL_CHANGED, self.on_select ) self.m_staticText3.Bind( wx.EVT_LEFT_DOWN, self.on_source ) self.plg = None self.load() - + def addnode(self, parent, data): for i in data: if i=='-':continue @@ -70,17 +71,30 @@ def addnode(self, parent, data): else: item = self.tre_plugins.AppendItem(parent, i.title) self.tre_plugins.SetItemData(item, i) - + def load(self): - data = loader.build_plugins('menus') + datas = loader.build_plugins('menus') + keydata = {} + for i in datas[1]: + if isinstance(i, tuple): keydata[i[0].__name__.split('.')[-1]] = i[1] + #print(keydata) + extends = glob('plugins/*/menus') + for i in extends: + plgs = loader.build_plugins(i) + for j in plgs[1]: + if not isinstance(j, tuple): continue + name = j[0].__name__.split('.')[-1] + if name in keydata: + keydata[name].extend(j[1]) + else: datas[1].append(j) root = self.tre_plugins.AddRoot('Plugins') - self.addnode(root, data[1]) - + + self.addnode(root, datas[1]) # Virtual event handlers, overide them in your derived class def on_run( self, event ): plg = self.tre_plugins.GetItemPyData(event.GetItem()) if hasattr(plg, 'start'):plg().start() - + def on_select( self, event ): plg = self.tre_plugins.GetItemData(event.GetItem()) print(type(plg)) @@ -88,10 +102,10 @@ def on_select( self, event ): self.plg = plg if plg.__doc__!=None: self.txt_info.SetValue(plg.__doc__) - elif hasattr(plg, '__module__'): + elif hasattr(plg, '__module__'): self.txt_info.SetValue("plugin at {}".format(plg.__module__)) else: self.txt_info.SetValue("package at {}".format(plg.__name__)) - + def on_source(self, event): ## TODO: should it be absolute path ? filename = self.plg.__module__.replace('.','/')+'.py' @@ -99,4 +113,4 @@ def on_source(self, event): root = os.path.split(root_dir)[0] filename=os.path.join(root,filename) #print(filename) - EditorFrame(filename=filename).Show() \ No newline at end of file + EditorFrame(filename=filename).Show() diff --git a/imagepy/menus/Plugins/Manager/toltree_wgt.py b/imagepy/menus/Plugins/Manager/toltree_wgt.py index 8b9326dd..f26d8d66 100644 --- a/imagepy/menus/Plugins/Manager/toltree_wgt.py +++ b/imagepy/menus/Plugins/Manager/toltree_wgt.py @@ -10,6 +10,7 @@ from imagepy import IPy, root_dir from imagepy.core.loader import loader from wx.py.editor import EditorFrame +from glob import glob class Plugin ( wx.Panel ): title = 'Tool Tree View' @@ -74,9 +75,14 @@ def addnode(self, parent, data): self.tre_plugins.SetItemData(item, i[0]) def load(self): - data = loader.build_tools('tools') + datas = loader.build_tools('tools') + extends = glob('plugins/*/tools') + for i in extends: + tols = loader.build_tools(i) + if len(tols)!=0: datas[1].extend(tols[1]) + root = self.tre_plugins.AddRoot('Tools') - for i in data[1]: + for i in datas[1]: item = self.tre_plugins.AppendItem(root, i[0].title) self.tre_plugins.SetItemData(item, i[0]) for j in i[1]: diff --git a/imagepy/menus/Plugins/Match/__init__.py b/imagepy/menus/Plugins/Match/__init__.py new file mode 100755 index 00000000..deef7095 --- /dev/null +++ b/imagepy/menus/Plugins/Match/__init__.py @@ -0,0 +1 @@ +catlog = ['trans_plgs', '-', 'surf_plgs', 'sift_plgs', 'orb_plgs'] \ No newline at end of file diff --git a/imagepy/menus/Plugins/Match/basic.py b/imagepy/menus/Plugins/Match/basic.py new file mode 100755 index 00000000..938a3346 --- /dev/null +++ b/imagepy/menus/Plugins/Match/basic.py @@ -0,0 +1,56 @@ +from imagepy.core.engine import Tool +# 用于绘制特征集 +class FeatMark: + def __init__(self, feats): + self.feats = feats + + def draw(self, dc, f, **key): + for i in self.feats: + dc.DrawCircle(f(*i), 3) + +# 用于双图特征集交互 +class Pick(Tool): + title = 'Key Point Pick Tool' + def __init__(self, pts1, pts2, pair, msk, ips1, ips2, host, style): + self.pts1, self.pts2 = pts1, pts2 + self.ips1, self.ips2 = ips1, ips2 + self.pair, self.msk = pair, msk + self.cur, self.host = -1, host + self.pts = self.pts1 if host else self.pts2 + self.style = style + + def nearest(self, x, y): + mind, mini = 1000, -1 + for i1, i2 in self.pair: + i = i1 if self.host else i2 + d = np.sqrt((x-self.pts[i,0])**2+(y-self.pts[i,1])**2) + if d d + + def accept(self, v1, v2): + L = v2 + Dl = np.mat(np.diag(np.ones(2)))*self.std**2 + T = self.getT(v1.A1,v2.A1) + CX = (self.Dk.I + T.T * Dl.I * T).I + CL = CX * T .T* Dl.I + CV = np.mat(np.diag(np.ones(self.dim))) - CX * T.T * Dl.I * T + self.V = CL * L + CV * self.V + self.Dk = CV * self.Dk * CV.T + CL * Dl * CL.T + + def normalrize(self, pts): + o = pts.mean(axis=0) + l = norm(pts-o, axis=1).mean() + pts[:] = (pts-o)/l + + def filter(self, kpt1, feat1, kpt2, feat2): + kpt1 = np.array([(k.pt[0],k.pt[1]) for k in kpt1]) + kpt2 = np.array([(k.pt[0],k.pt[1]) for k in kpt2]) + self.normalrize(kpt1), self.normalrize(kpt2) + idx = self.match(feat1, feat2) + if self.dim == 0: + return idx, np.ones(len(idx), dtype=np.bool), 1 + mask = [] + for i1, i2 in idx: + v1 = np.mat(kpt1[i1]) + v2 = np.mat(kpt2[i2]) + if self.test(v1, v2): + self.accept(v1.T,v2.T) + mask.append(True) + else: mask.append(False) + mask = np.array(mask) + #print mask + return idx, mask, self.V + + def getTrans(self): + result = np.eye(3) + result[:2] = self.V.reshape((2,3)) + return result + + def checkV(self): + trans = self.getTrans()[:2,:2] + axis = norm(trans,axis=0) + return norm(axis-1)< 0.5 \ No newline at end of file diff --git a/imagepy/menus/Plugins/Match/orb_plgs.py b/imagepy/menus/Plugins/Match/orb_plgs.py new file mode 100755 index 00000000..049ce6fd --- /dev/null +++ b/imagepy/menus/Plugins/Match/orb_plgs.py @@ -0,0 +1,266 @@ +# 仿照surf_plgs +import cv2, wx +from imagepy.core.engine import Filter, Simple, Tool +from imagepy.core.manager import ImageManager +from .matcher import Matcher +import numpy as np +from imagepy import IPy + +from skimage.color import rgb2gray,gray2rgb +from skimage.feature import ( match_descriptors, corner_harris, corner_peaks, ORB, plot_matches) +from skimage.measure import ransac +from skimage.transform import warp +from skimage.transform import SimilarityTransform +from skimage.transform import FundamentalMatrixTransform +from skimage.transform import ProjectiveTransform + +import pandas as pd + + +class OrbFeatMark: + def __init__(self, feats): + self.feats = feats + + def draw(self, dc, f, **key): + for i in self.feats: + # print('i.pt:{},{}'.format(type(f(i.pt)),i.pt)) + dc.DrawCircle(f(i[0], i[1]), 3) + +class Orb(Filter): + title = 'ORB Detect' + note = ['all', 'not-slice'] + + para = {'Num':1000} + view = [ + (int, 'Num', (500,2000), 0, 'orb descriptor num', '1-1000')] + + def run(self, ips, snap, img, para): + descriptor_extractor = ORB(n_keypoints=para['Num']) + + grayImg = rgb2gray(img) + descriptor_extractor.detect_and_extract(grayImg) + keypoints1 = descriptor_extractor.keypoints + descriptors1 = descriptor_extractor.descriptors + + ips.orb_keypoint = keypoints1[::-1] + ips.orb_descriptors = descriptors1 + ips.mark = OrbFeatMark(keypoints1) + + IPy.write("Detect completed, {} ORB points found!".format(len(keypoints1)), 'Orb') + +class OrbPick(Tool): + title = 'Key Point Pick Tool' + def __init__(self, pts1, pts2, pair, msk, ips1, ips2, host, style): + self.pts1, self.pts2 = pts1, pts2 + self.ips1, self.ips2 = ips1, ips2 + self.pair, self.msk = pair, msk + self.cur, self.host = -1, host + self.pts = self.pts1 if host else self.pts2 + self.style = style + + def nearest(self, x, y): + mind, mini = 1000, -1 + for i1, i2 in self.pair: + i = i1 if self.host else i2 + d = np.sqrt((x-self.pts[i][0])**2+(y-self.pts[i][1])**2) + + # d = np.sqrt((x-self.pts[i].pt[0])**2+(y-self.pts[i].pt[1])**2) + if d1:img = img[::para['dsample'], ::para['dsample']] + + detector = cv2.xfeatures2d.SIFT_create() if cv2.__version__[0] =="3" else cv2.SIFT() + + kps = detector.detect(img, None) + ips.sift_keypoint = kps + skps = np.array([i.pt for i in kps])*para['dsample'] + ips.mark = FeatMark(skps) + IPy.write("Detect completed, {} points found!".format(len(kps)), 'SIFT') + +class Pick(Tool): + title = 'Key Point Pick Tool' + def __init__(self, pts1, pts2, pair, msk, ips1, ips2, host, style): + self.pts1, self.pts2 = pts1, pts2 + self.ips1, self.ips2 = ips1, ips2 + self.pair, self.msk = pair, msk + self.cur, self.host = -1, host + self.pts = self.pts1 if host else self.pts2 + self.style = style + + def nearest(self, x, y): + mind, mini = 1000, -1 + for i1, i2 in self.pair: + i = i1 if self.host else i2 + d = np.sqrt((x-self.pts[i].pt[0])**2+(y-self.pts[i].pt[1])**2) + if d1:img = img[::para['dsample'], ::para['dsample']] + detector = CVSURF(hessianThreshold=para['thr'], nOctaves=para['oct'], + nOctaveLayers=para['int'], upright=para['upright'],extended=para['ext']) + kps = detector.detect(img) + skps = np.array([i.pt for i in kps])*para['dsample'] + ips.mark = FeatMark(skps) + + # if para['tab'], show the table + if not para['tab']:return + feats = detector.compute(img, kps)[1] + columns=['Point-X','Point-Y']+['feat%d'%(i+1) for i in range(feats.shape[1])] + vs = pd.DataFrame(np.hstack((skps, feats*10000)), columns=columns) + IPy.show_table(vs, ips.title+'-SurfFeats') + +class Pick(Tool): + title = 'Key Point Pick Tool' + def __init__(self, pts1, pts2, pair, msk, ips1, ips2, host, style): + self.pts1, self.pts2 = pts1, pts2 + self.ips1, self.ips2 = ips1, ips2 + self.pair, self.msk = pair, msk + self.cur, self.host = -1, host + self.pts = self.pts1 if host else self.pts2 + self.style = style + + def nearest(self, x, y): + mind, mini = 1000, -1 + for i1, i2 in self.pair: + i = i1 if self.host else i2 + d = np.sqrt((x-self.pts[i].pt[0])**2+(y-self.pts[i].pt[1])**2) + if d{'path':'./T1.jpg'} +Open>{'path':'./T2.jpg'} +Orb Matcher>{'int': 3, 'upright': False, 'img2': u'T2', 'img1': u'T1', 'num': 200} + +#Open Url>{'url': u'http://data.imagepy.org/testdata/box.png'} +#Open Url>{'url': u'http://data.imagepy.org/testdata/box_in_scene.png'} +#Orb Matcher>{'int': 4, 'upright': False, 'img2': u'box', 'img1': u'box_in_scene', 'std': 1, 'style': 'Blue/Yellow', 'log': True, 'thr': 2000, 'ext': False, 'trans': 'Homo', 'oct': 3} diff --git a/imagepy/menus/Plugins/Surf/Surf Demo.mc b/imagepy/menus/Plugins/Surf/Surf Demo.mc index 51869842..fc01f041 100644 --- a/imagepy/menus/Plugins/Surf/Surf Demo.mc +++ b/imagepy/menus/Plugins/Surf/Surf Demo.mc @@ -1,3 +1,4 @@ -Open Url>{'url': u'http://data.imagepy.org/testdata/box.png'} -Open Url>{'url': u'http://data.imagepy.org/testdata/box_in_scene.png'} -Surf Matcher>{'int': 4, 'upright': False, 'img2': u'box_in_scene', 'img1': u'box', 'std': 1, 'style': 'Blue/Yellow', 'log': True, 'thr': 2000, 'ext': False, 'trans': 'Homo', 'oct': 3} +Open>{'path':'./T1.jpg'} +Open>{'path':'./T2.jpg'} + +Surf Matcher>{'int': 4, 'upright': False, 'img2': u'T1', 'img1': u'T2', 'std': 1, 'style': 'Blue/Yellow', 'log': True, 'thr': 2000, 'ext': False, 'trans': 'Homo', 'oct': 3} diff --git a/imagepy/menus/Plugins/Surf/__init__.py b/imagepy/menus/Plugins/Surf/__init__.py index 39f3f347..57389c5c 100644 --- a/imagepy/menus/Plugins/Surf/__init__.py +++ b/imagepy/menus/Plugins/Surf/__init__.py @@ -1 +1 @@ -catlog = ['surf_plg', '-', 'Surf Demo'] \ No newline at end of file +catlog = ['surf_plg', 'Surf Demo','-','orb_plg','Orb Demo', '-', 'imgStitch_plg'] diff --git a/imagepy/menus/Plugins/Surf/imgStitch_plg.py b/imagepy/menus/Plugins/Surf/imgStitch_plg.py new file mode 100644 index 00000000..7d8a40c8 --- /dev/null +++ b/imagepy/menus/Plugins/Surf/imgStitch_plg.py @@ -0,0 +1,225 @@ +#-*- coding:utf-8 -*- +import cv2, wx +from imagepy.core.engine import Filter, Simple, Tool +from imagepy.core.manager import ImageManager +from .matcher import Matcher +import numpy as np +from imagepy import IPy +from skimage.color import rgb2gray +from skimage.feature import ( match_descriptors, corner_harris, corner_peaks, ORB, plot_matches) + +CVSURF = cv2.xfeatures2d.SURF_create if cv2.__version__[0] =="3" else cv2.SURF + +class FeatMark: + def __init__(self, feats): + self.feats = feats + + def draw(self, dc, f, **key): + for i in self.feats: + # print('i.pt:{},{}'.format(type(f(i.pt)),i.pt)) + dc.DrawCircle(f(i.pt[0], i.pt[1]), 3) + +class Surf(Filter): + title = 'Surf Detect' + note = ['all', 'not-slice'] + + para = {'upright':False, 'oct':3, 'int':4, 'thr':1000, 'ext':False} + view = [ (int, 'oct', (0,5), 0, 'octaves', ''), + (int, 'int', (0,5), 0, 'intervals', ''), + (int, 'thr', (500,2000), 0, 'threshold', '1-100'), + (bool, 'ext', 'extended'), + (bool, 'upright', 'upright') ] + + def run(self, ips, snap, img, para): + detector = CVSURF(hessianThreshold=para['thr'], nOctaves=para['oct'], + nOctaveLayers=para['int'], upright=para['upright'],extended=para['ext']) + kps = detector.detect(img) + ips.surf_keypoint = kps + ips.mark = FeatMark(kps) + IPy.write("Detect completed, {} points found!".format(len(kps)), 'Surf') + + +class ImgsStitch(Simple): + title = 'ImgsStitch' + note = ['all'] + + #parameter + para = {'imgList':'','img2':'','upright':False, 'log':False, + 'oct':3, 'int':4, 'thr':1000, 'ext':False, + 'trans':'None', 'std':1, 'style':'Blue/Yellow'} + + def myInitialize(self): + self.images = [] + self.count = -1 + self.left_list, self.right_list, self.center_im = [], [],None + # self.matcher_obj = matchers() + + def load(self, ips): + titles = ImageManager.get_titles() + self.para['imgList'] = titles[0] + self.para['img2'] = titles[0] + ImgsStitch.view = [ ('lab', None, '========= two image in 8-bit ========='), + (list, 'imgList', titles, str, 'image list', ''), + (list, 'img2', titles, str, 'image2', ''), + ('lab', None, ''), + ('lab', None, '====== parameter about the surf ======'), + (int, 'oct', (0,5), 0, 'octaves', ''), + (int, 'int', (0,5), 0, 'intervals', ''), + (int, 'thr', (500,2000), 0, 'threshold', '1-100'), + (bool, 'ext', 'extended'), + (bool, 'upright', 'upright'), + ('lab', None, ''), + ('lab', None, '====== how to match and display ======'), + (list, 'trans', ['None', 'Affine', 'Homo'], str, 'transform', ''), + (int, 'std', (1, 5), 0, 'Std', 'torlerance'), + (list, 'style', ['Blue/Yellow', 'Hide'], str, 'Aspect', 'color'), + (bool, 'log', 'show log') ] + return True + + def prepare_lists(self): + print( "Number of images : %d".format(self.count)) + self.centerIdx = self.count/2 + print( "Center index image : %d".format(self.centerIdx)) + + self.center_im = self.images[int(self.centerIdx)] + for i in range(self.count): + if(i<=self.centerIdx): + self.left_list.append(self.images[i]) + else: + self.right_list.append(self.images[i]) + print( "Image lists prepared") + + def generateImgList(self,imglistpath): + fp = open(imglistpath, 'r') + filenames = [each.rstrip('\r\n') for each in fp.readlines()] + print(filenames) + self.images = [cv2.resize(cv2.imread(each),(480,320)) for each in filenames] + self.count = len(self.images) + self.left_list, self.right_list, self.center_im = [], [],None + # self.matcher_obj = matchers() + self.prepare_lists() + + def stitchAllImgs(self,para): + # print('current img list:{}'.format(para['imgList'])) + # curImgList = ImageManager.get(para['imgList']) + curImgList = '/Users/cooperjack/Documents/gao-imagepy/stitchImgs.txt' + print('curImgList:{}'.format(curImgList)) + + self.generateImgList(curImgList) + + # 对左方图像进行匹配 + a = self.left_list[0] + temp = a + for b in self.left_list[1:]: + # H = self.matcher_obj.match(a, b, 'left') + #### 内存处理应该怎样进行 + temp = self.stitchTwoImg(temp, b, para) + + IPy.show_img([temp], 'left') + + # 对右方图像进行匹配 + for each in self.right_list: + temp = self.stitchTwoImg(each,temp, para) + + # 输出最终的图像; + title = 'Stitched images' + IPy.show_img([temp], title) + + # 左图:ips1, 右图:ips2 + def stitchTwoImg(self,ips1, ips2,para): + + detector = CVSURF(hessianThreshold=para['thr'], nOctaves=para['oct'], + nOctaveLayers=para['int'], upright=para['upright'],extended=para['ext']) + + kps1, feats1 = detector.detectAndCompute(ips1, None) + kps2, feats2 = detector.detectAndCompute(ips2, None) + + dim, std = {'None':0, 'Affine':6, 'Homo':8}[para['trans']], para['std']/100.0 + + style = para['style']=='Blue/Yellow' + + idx, msk, m = Matcher(dim, std).filter(kps1,feats1,kps2,feats2) + # picker1 = Pick(kps1, kps2, idx, msk, ips1, ips2, True, style) + # picker2 = Pick(kps1, kps2, idx, msk, ips1, ips2, False, style) + + # ips1.tool, ips1.mark = picker1, picker1 + # ips2.tool, ips2.mark = picker2, picker2 + if para['log']:self.log(kps1, kps2, msk, m, dim) + + tempPnt1 = np.float32([kps1[i1].pt for i1,_ in idx]) + tempPnt2 = np.float32([kps2[i2].pt for _,i2 in idx]) # tidx = self.pair[:,1-self.host][self.msk] + + newPnt1=[] + newPnt2=[] + for i in range(len(msk)): + if msk[i]: + newPnt1.append(tempPnt1[i]) + newPnt2.append(tempPnt2[i]) + + # 第四个参数取值范围在 1 到 10 , 绝一个点对的阈值。原图像的点经过变换后点与目标图像上对应点的误差 + # 超过误差就认为是 outlier + # 返回值中 H 为变换矩阵。mask是掩模,online的点 + H, _ = cv2.findHomography(tempPnt1, tempPnt2, cv2.RANSAC, 1.0) + + newImg = self.combine_images( ips2, ips1, H) + return newImg + #process + def run(self, ips, imgs, para = None): + self.myInitialize() + self.stitchAllImgs(para) + + # print surf result to the Name 'Surf' Console + def log(self, pts1, pts2, msk, v, dim): + sb = [] + sb.append('Image1:{} points detected!'.format(len(pts1))) + sb.append('Image2:{} points detected!\r\n'.format(len(pts2))) + sb.append('Matched Point:{0}/{1}\r\n'.format(msk.sum(),len(msk))) + if dim == 0: return + sb.append('Transformation:') + sb.append('%15.4f%15.4f%15.4f'%tuple(v.A1[:3])) + sb.append('%15.4f%15.4f%15.4f'%tuple(v.A1[3:6])) + row = [0,0,1] if dim==6 else list(v[-2:])+[1] + sb.append('%15.4f%15.4f%15.4f'%tuple(row)) + + cont = '\n'.join(sb) + IPy.write(cont, 'Surf') + + def combine_images(self,img0,img1,h_matrix): + print('combining images... ') + + points0 = np.array( + [[0, 0], [0, img0.shape[0]], [img0.shape[1], img0.shape[0]], [img0.shape[1], 0]], dtype=np.float32) + points0 = points0.reshape((-1, 1, 2)) + points1 = np.array( + [[0, 0], [0, img1.shape[0]], [img1.shape[1], img0.shape[0]], [img1.shape[1], 0]], dtype=np.float32) + points1 = points1.reshape((-1, 1, 2)) + + points2 = cv2.perspectiveTransform(points1, h_matrix) + + points = np.concatenate((points0, points2), axis=0) + [x_min, y_min] = np.int32(points.min(axis=0).ravel() - 0.5) + [x_max, y_max] = np.int32(points.max(axis=0).ravel() + 0.5) + H_translation = np.array([[1, 0, -x_min], [0, 1, -y_min], [0, 0, 1]]) + # logger.debug('warping previous image...') + output_img = cv2.warpPerspective(img1, H_translation.dot(h_matrix), (x_max - x_min, y_max - y_min)) + output_img[-y_min:img0.shape[0] - y_min, -x_min:img0.shape[1] - x_min] = img0 + return output_img + +plgs = [ ImgsStitch] + +if __name__ == '__main__': + from .matcher import Matcher + + detector = CVSURF(1000, nOctaves=3, nOctaveLayers=4, upright=False,extended=False) + #img1 = cv2.imread('/home/yxl/opencv-2.4/samples/c/box.png', 0) + img1 = cv2.imread('/Users/cooperjack/Desktop/0001_o.jpg',0) + pts, des = detector.detectAndCompute(img1, None) + + matcher = cv2.BFMatcher(cv2.NORM_L2) + raw_matches = matcher.knnMatch(des, trainDescriptors = des, k = 1) + m = raw_matches[0][0] + lt = [(i[0].distance, i[0].queryIdx, i[0].trainIdx) for i in raw_matches] + lt = np.array(sorted(lt)) + + matcher = Matcher(8, 3) + idx, msk, m = matcher.filter(pts,des,pts,des) diff --git a/imagepy/menus/Plugins/Surf/orb_plg.py b/imagepy/menus/Plugins/Surf/orb_plg.py new file mode 100644 index 00000000..14dfb74d --- /dev/null +++ b/imagepy/menus/Plugins/Surf/orb_plg.py @@ -0,0 +1,243 @@ +import cv2, wx +from imagepy.core.engine import Filter, Simple, Tool +from imagepy.core.manager import ImageManager +from .matcher import Matcher +import numpy as np +from imagepy import IPy + +from skimage.color import rgb2gray,gray2rgb +from skimage.feature import ( match_descriptors, corner_harris, corner_peaks, ORB, plot_matches) +from skimage.measure import ransac +from skimage.transform import warp +from skimage.transform import SimilarityTransform +from skimage.transform import FundamentalMatrixTransform +from skimage.transform import ProjectiveTransform + +import pandas as pd + +CVSURF = cv2.xfeatures2d.SURF_create if cv2.__version__[0] =="3" else cv2.SURF + +class OrbFeatMark: + def __init__(self, feats): + self.feats = feats + + def draw(self, dc, f, **key): + for i in self.feats: + + dc.DrawCircle(f(i[1], i[0]), 3) + +class Orb(Filter): + title = 'ORB Detect' + note = ['all', 'not-slice'] + + para = {'Num':1000} + view = [ + (int, 'Num', (500,2000), 0, 'orb descriptor num', '1-1000')] + + def run(self, ips, snap, img, para): + descriptor_extractor = ORB(n_keypoints=para['Num']) + + grayImg = rgb2gray(img) + descriptor_extractor.detect_and_extract(grayImg) + keypoints1 = descriptor_extractor.keypoints + descriptors1 = descriptor_extractor.descriptors + + ips.orb_keypoint = keypoints1 + ips.orb_descriptors = descriptors1 + ips.mark = OrbFeatMark(keypoints1) + + IPy.write("Detect completed, {} ORB points found!".format(len(keypoints1)), 'Orb') + +class Pick(Tool): + title = 'Key Point Pick Tool' + def __init__(self, pts1, pts2, pair, msk, ips1, ips2, host, style): + self.pts1, self.pts2 = pts1, pts2 + self.ips1, self.ips2 = ips1, ips2 + self.pair, self.msk = pair, msk + self.cur, self.host = -1, host + self.pts = self.pts1 if host else self.pts2 + self.style = style + + def nearest(self, x, y): + mind, mini = 1000, -1 + for i1, i2 in self.pair: + i = i1 if self.host else i2 + d = np.sqrt((x-self.pts[i].pt[0])**2+(y-self.pts[i].pt[1])**2) + if d +#

PopupMenu

+# """ + text + """ +# +# """ + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/imagepy/test.py b/imagepy/test.py new file mode 100644 index 00000000..80d048c5 --- /dev/null +++ b/imagepy/test.py @@ -0,0 +1,74 @@ +# from wxPython.wx import * +from wx import * +import wx, platform +# import wx, platform + +menu_titles = [ "Open", + "Properties", + "Rename", + "Delete" ] + +menu_title_by_id = {} +for title in menu_titles: + # menu_title_by_id[ wxNewId() ] = title + menu_title_by_id[ wx.NewId() ] = title + + + +list_title = "files" +list_items = [ "binding.py", + "clipboard.py", + "config.py", + "debug.py", + "dialog.py", + "dispatch.py", + "error.py", ] + + + +class App( wx.PySimpleApp ): + def OnInit( self ): + # build frame + frame = wx.Frame(None, -1, "Hello from wxPython") + self.frame = frame # we'll use in RightClickCb + + # build listF + # list = wx.ListCtrl( frame, -1, style=wxLC_REPORT ) + list = wx.ListCtrl( frame, -1, style=wx.LC_REPORT) + list.InsertColumn( 0, list_title ) + for x in list_items: list.InsertStringItem(0,x) + + ### 1. Register source's EVT_s to invoke launcher. ### + EVT_LIST_ITEM_RIGHT_CLICK( list, -1, self.RightClickCb ) + + # clear variables + self.list_item_clicked = None + + # show & run + frame.Show(1) + return 1 + + def RightClickCb( self, event ): + # record what was clicked + self.list_item_clicked = right_click_context = event.GetText() + + ### 2. Launcher creates wxMenu. ### + menu = wx.Menu() + for (id,title) in menu_title_by_id.items(): + ### 3. Launcher packs menu with Append. ### + menu.Append( id, title ) + ### 4. Launcher registers menu handlers with EVT_MENU, on the menu. ### + EVT_MENU( menu, id, self.MenuSelectionCb ) + + ### 5. Launcher displays menu with call to PopupMenu, invoked on the source component, passing event's GetPoint. ### + self.frame.PopupMenu( menu, event.GetPoint() ) + menu.Destroy() # destroy to avoid mem leak + + def MenuSelectionCb( self, event ): + # do something + operation = menu_title_by_id[ event.GetId() ] + target = self.list_item_clicked + print( 'Perform "%(operation)s" on "%(target)s."' % vars()) + +app = App() +app.MainLoop() \ No newline at end of file diff --git a/imagepy/tools/Measure/angle2_tol.py b/imagepy/tools/Measure/angle2_tol.py index d548570a..caf3e165 100644 --- a/imagepy/tools/Measure/angle2_tol.py +++ b/imagepy/tools/Measure/angle2_tol.py @@ -19,13 +19,13 @@ class Angle: def __init__(self, body=None): self.body = body if body!=None else [] self.buf = [] - + def addline(self): line = self.buf if len(line)!=2 or line[0] !=line[-1]: self.body.append(line) self.buf = [] - + def snap(self, x, y, lim): minl, idx = 1000, None for i in self.body: @@ -33,20 +33,22 @@ def snap(self, x, y, lim): d = (j[0]-x)**2+(j[1]-y)**2 if d < minl:minl,idx = d,(i, i.index(j)) return idx if minl**0.52: self.body.append(line) self.buf = [] - + def snap(self, x, y, lim): minl, idx = 1000, None for i in self.body: @@ -32,21 +32,23 @@ def snap(self, x, y, lim): d = (j[0]-x)**2+(j[1]-y)**2 if d < minl:minl,idx = d,(i, i.index(j)) return idx if minl**0.5 10: + return + + blockIndex = [ i for i,j in enumerate(lines) if j==(-1,-1) ] + + blockIndex.insert(0,0) + + blockIndex3 = [ i-pntPos for i in blockIndex] + + # print('blockIndex3:{}\n'.format(blockIndex3)) + + blockIndex2 = [ blockIndex3[i] * blockIndex3[i+1] <= 0 for i,j in enumerate(blockIndex3[:-1])] + + # print('blockIndex2:{}\n'.format(blockIndex2)) + + + curIndex = 0 + if blockIndex2: + curIndex = np.argmax(blockIndex2) + + # print('curIndex:{}\n'.format(curIndex)) + # print('before self.body:{}\n',self.body) + + if blockIndex2: + startIndexToDelete = blockIndex[curIndex] + else: + startIndexToDelete = -1 + + tempBody = copy.deepcopy(self.buf) + + # print('before tempBody:{}\n',tempBody) + # print('before self.body:{}\n',self.buf) + # print('startIndexToDelete:{}\n',startIndexToDelete) + + removedIndex = [] + for i, j in enumerate(self.buf): + if i >= startIndexToDelete and j[0] != -1: + removedIndex.append(i) + if self.buf[i+1][0] == -1: + removedIndex.append(i+1) + break + + curBody = [ y for i,y in enumerate(self.buf) if i not in removedIndex ] + + self.buf = curBody + self.addline() + + + def snap(self, x, y, lim): + minl, idx = 1000, None + for i in self.body: + for j in i: + d = (j[0]-x)**2+(j[1]-y)**2 + if d < minl:minl,idx = d,(i, i.index(j)) + + return idx if minl**0.51: + dc.DrawLines([f(*i) for i in curLine if i[0] != -1 ]) + curLine=[] + + self.unit = Setting['ratioRuler'] + + font = wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False) + dc.SetFont(font) + dc.SetTextForeground(Setting['tcolor']) + + for line in self.body: + tempDist = 0 + if len(line) <=1 or line[0] == -1 and line[-1]== -1: + continue + + dc.DrawLines([f(*i) for i in line ]) + + for i in line : dc.DrawCircle(f(*i),2) + + # if g_DebugMode == True: + # print('line:{}'.format(line)) + + pts = np.array(line) + mid = (pts[:-1]+pts[1:])/2 + midPnt = (pts[-1]+pts[0]+(20,20))/2 + + dis = norm((pts[:-1]-pts[1:]), axis=1) + unit = 1 if self.unit is None else self.unit + + for i,j in zip(dis, mid): + tempDist += i + if j[0]>6: + j-=5 + if i <=0: + continue + dc.DrawText('%.2f'%(i * unit), f(*j)) + + font = wx.Font(15, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False) + # dc.SetTextForeground(Setting['hcolor']) + dc.SetFont(font) + dc.DrawText('%.2f mm'%(tempDist * unit), f(midPnt[0],midPnt[1])) + + def report(self, title): + rst = [] + for line in self.body: + pts = np.array(line) + dis = norm((pts[:-1]-pts[1:]), axis=1) + dis *= 1 if self.unit is None else self.unit + rst.append(list(dis.round(2))) + lens = [len(i) for i in rst] + maxlen = max(lens) + fill = [[0]*(maxlen-i) for i in lens] + rst = [i+j for i,j in zip(rst, fill)] + titles = ['L{}'.format(i+1) for i in range(maxlen)] + + lineTitle = ['{}'.format(i+1) for i in range(len(self.body))] + newLine = [list(row) for row in six.moves.zip_longest(*rst, fillvalue=0.0)] + + IPy.show_table(pd.DataFrame(newLine, columns=lineTitle), title) + + def updateReport(self, title): + if not (IPy.get_tps()): + return + data = IPy.get_tps().data + tempbuf = [] + self.buf = [] + for indexs in range(len(data.columns.values.tolist())): + + tempIndex = int(data.columns[indexs]) + print('cur index:{}'.format(tempIndex)) + + tempbuf.append(self.body[tempIndex][:]) + print('tempbuf:{}'.format(self.body[tempIndex])) + tempbuf.append([(-1,-1)]) + + for i in range(len(tempbuf)): + for x in range(len(tempbuf[i])): + self.buf.append(tempbuf[i][x] ) + self.addline() class Plugin(Tool): - """Define the diatance class plugin with the event callback functions""" - title = 'Distance' - def __init__(self): - self.curobj = None - self.doing = False - self.odx,self.ody = 0, 0 - - def mouse_down(self, ips, x, y, btn, **key): - if key['ctrl'] and key['alt']: - if isinstance(ips.mark, Distance): - ips.mark.report(ips.title) - return - - lim = 5.0/key['canvas'].get_scale() - if btn==1: - if not self.doing: - if isinstance(ips.mark, Distance): - self.curobj = ips.mark.pick(x, y, lim) - if self.curobj!=None:return - - if not isinstance(ips.mark, Distance): - ips.mark = Distance(unit=ips.unit) - self.doing = True - elif key['shift']: - self.doing = True - else: ips.mark = None - if self.doing: - ips.mark.buf.append((x,y)) - self.curobj = (ips.mark.buf, -1) - self.odx, self.ody = x,y - - elif btn==3: - if self.doing: - ips.mark.buf.append((x,y)) - self.doing = False - ips.mark.addline() - ips.update = True - - def mouse_up(self, ips, x, y, btn, **key): - self.curobj = None - - def mouse_move(self, ips, x, y, btn, **key): - if not isinstance(ips.mark, Distance):return - lim = 5.0/key['canvas'].get_scale() - if btn==None: - self.cursor = wx.CURSOR_CROSS - if ips.mark.snap(x, y, lim)!=None: - self.cursor = wx.CURSOR_HAND - elif btn==1: - ips.mark.draged(self.odx, self.ody, x, y, self.curobj) - ips.update = True - self.odx, self.ody = x, y - - def mouse_wheel(self, ips, x, y, d, **key): - pass \ No newline at end of file + """Define the diatance class plugin with the event callback functions""" + title = 'Distance' + def __init__(self): + + self.curobj = None + self.doing = False + self.odx,self.ody = 0, 0 + self.list_items = ['del', 'copy','move'] + self.popUpMenuInitialized = False + + def mouse_down(self, ips, x, y, btn, **key): + + if key['shift'] and isinstance(ips.mark, Distance): + print('updateReport!') + ips.mark.updateReport(ips.title) + + if key['ctrl'] and key['alt']: + # print('key mouse_down:{}'.format(key)) + # print('table in') + if isinstance(ips.mark, Distance): + ips.mark.report(ips.title) + return + + lim = 5.0/key['canvas'].get_scale() + if btn==1:# 按下了左键 + if not self.doing: + if isinstance(ips.mark, Distance): + self.curobj = ips.mark.pick(x, y, lim) + if not isinstance(ips.mark, Distance): + ips.mark = Distance(unit=ips.unit) + self.doing = True + print('A new Distance instance is added!') + elif key['shift']: + self.doing = True + else: + x = 1 + + if self.doing: + ips.mark.buf.append((x,y)) + self.curobj = (ips.mark.buf, -1) + self.odx, self.ody = x, y + + elif btn==3: ### btn == 3 代表是右键被按下; + # print('Right bottom is pushed!') + if self.doing: + # ips.mark.buf.append((x,y)) + ips.mark.buf.append((-1,-1)) + lineNum = [i for i,x in enumerate(ips.mark.buf) if x == (-1,-1)] + ips.mark.addline() + elif btn==2: + if key['shift']: + if isinstance(ips.mark, Distance): + self.curobj = ips.mark.pick(x, y, lim) + # ips.mark.buf.append((x,y)) + # self.odx, self.ody = x, y + ips.mark.delLine(x,y) + + # if not self.popUpMenuInitialized: + # self.popUpInit(**key) + # self.popUpMenuInitialized = True + # self.OnContextMenu(**key) + ips.update = True + + def mouse_up(self, ips, x, y, btn, **key): + print('mouse is up!') + + def mouse_move(self, ips, x, y, btn, **key): + if not isinstance(ips.mark, Distance):return + lim = 5.0/key['canvas'].get_scale() + if btn==None: + self.cursor = wx.CURSOR_CROSS + if ips.mark.snap(x, y, lim)!=None: + self.cursor = wx.CURSOR_HAND + elif btn==1: + if self.curobj is not None: + ips.mark.draged(self.odx, self.ody, x, y, self.curobj) + ips.update = True + self.odx, self.ody = x, y + + def mouse_wheel(self, ips, x, y, d, **key): + pass + + def OnContextMenu(self, **key): + print("OnContextMenu\n") + + # only do this part the first time so the events are only bound once + # + # Yet another anternate way to do IDs. Some prefer them up top to + # avoid clutter, some prefer them close to the object of interest + # for clarity. + if not hasattr(self, "popupID1"): + + self.popupID1 = wx.NewId() + self.popupID2 = wx.NewId() + self.popupID3 = wx.NewId() + + self.Bind(wx.EVT_MENU, self.OnPopupOne, id=self.popupID1) + self.Bind(wx.EVT_MENU, self.OnPopupTwo, id=self.popupID2) + self.Bind(wx.EVT_MENU, self.OnPopupThree, id=self.popupID3) + + # make a menu + menu = wx.Menu() + # Show how to put an icon in the menu + item = wx.MenuItem(menu, self.popupID1,"Del Current Line") + # bmp = images.Smiles.GetBitmap() + # item.SetBitmap(bmp) + menu.AppendItem(item) + # add some other items + menu.Append(self.popupID2, "Two") + menu.Append(self.popupID3, "Three") + + # Popup the menu. If an item is selected then its handler + # will be called before PopupMenu returns. + key['canvas'].PopupMenu(menu) + menu.Destroy() + + def OnPopupOne(self, event): + print("Popup one\n") + + + def OnPopupTwo(self, event): + print("Popup two\n") + + def OnPopupThree(self, event): + print("Popup three\n") diff --git a/imagepy/tools/Measure/distance_tol_BackUp.py b/imagepy/tools/Measure/distance_tol_BackUp.py new file mode 100644 index 00000000..a700a6a4 --- /dev/null +++ b/imagepy/tools/Measure/distance_tol_BackUp.py @@ -0,0 +1,232 @@ +# -*- coding: utf-8 -*- +""" +Created on Fri Feb 3 22:21:32 2017 + +@author: yxl +""" + +import wx +from imagepy.core.engine import Tool +import numpy as np +import pandas as pd +from numpy.linalg import norm +from .setting import Setting +from imagepy import IPy + +class Distance: + """Define the distance class""" + dtype = 'distance' + def __init__(self, body=None, unit=None): + self.body = body if body!=None else [] + self.buf, self.unit = [], unit + + def addline(self): + line = self.buf + self.body = [] + curLine = [] + if len(line)!=2 or line[0] !=line[-1]: + for i in line: + if i[0] !=-1 and i[1]!=-1: + curLine.append(i) + else: + self.body.append(curLine) + curLine=[] + + # self.buf = [] + + def snap(self, x, y, lim): + minl, idx = 1000, None + for i in self.body: + for j in i: + d = (j[0]-x)**2+(j[1]-y)**2 + if d < minl:minl,idx = d,(i, i.index(j)) + return idx if minl**0.51: + dc.DrawLines([f(*i) for i in curLine if i[0] != -1 ]) + curLine=[] + # dc.DrawLines([f(*i) for i in self.buf) + # for i in self.buf: + # if i[0]!=-1 and i[1] != -1: + # dc.DrawCircle(f(*i),2) + # print('current pixel ratio is:{}'.format(Setting['ratioRuler'])) + self.unit = Setting['ratioRuler'] + + print('body:{}'.format(len(self.body))) + for line in self.body: + tempDist = 0 + # print('line:{}'.format(line)) + if len(line) <=1 or line[0] == -1 and line[-1]== -1: + continue + dc.DrawLines([f(*i) for i in line ]) + + for i in line:dc.DrawCircle(f(*i),2) + pts = np.array(line) + mid = (pts[:-1]+pts[1:])/2 + + midPnt = np.median( pts, axis=1) + + dis = norm((pts[:-1]-pts[1:]), axis=1) + # unit = 1 if self.unit is None else self.unit[0] + unit = 1 if self.unit is None else self.unit + + for i,j in zip(dis, mid): + tempDist += i + if j[0]>6: + j-=5 + if i <=0: + continue + dc.DrawText('%.2f'%(i * unit), f(*j)) + + font = wx.Font(20, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False) + dc.SetFont(font) + dc.DrawText('%.2f mm'%(tempDist * unit), f(midPnt[0],midPnt[1])) + + def report(self, title): + rst = [] + for line in self.body: + pts = np.array(line) + dis = norm((pts[:-1]-pts[1:]), axis=1) + dis *= 1 if self.unit is None else self.unit + rst.append(list(dis.round(2))) + lens = [len(i) for i in rst] + maxlen = max(lens) + fill = [[0]*(maxlen-i) for i in lens] + rst = [i+j for i,j in zip(rst, fill)] + titles = ['L{}'.format(i+1) for i in range(maxlen)] + # searchTitle = [1, len(self.body)] + IPy.show_table(pd.DataFrame(rst, columns=titles), title) + def updateReport(self, title): + data = IPy.get_tps().data + tempbuf = [] + self.buf = [] + for indexs in data.index: + print('cur index:{}'.format(indexs)) + # temp = list(filter(lambda a: a != 0.0, data.loc[indexs].values[0:-1])) + tempbuf.append(self.body[indexs][:]) + print('tempbuf:{}'.format(self.body[indexs])) + tempbuf.append([(-1,-1)]) + for i in range(len(tempbuf)): + for x in range(len(tempbuf[i])): + self.buf.append(tempbuf[i][x] ) + + # self.buf = [ tempbuf[i][x] for x in len(tempbuf[i]) for i in len(tempbuf)] + print('buf:{}'.format(self.buf)) + + self.addline() + + # rst = [] + # for line in self.body: + # pts = np.array(line) + # dis = norm((pts[:-1]-pts[1:]), axis=1) + # dis *= 1 if self.unit is None else self.unit + # rst.append(list(dis.round(2))) + # lens = [len(i) for i in rst] + # maxlen = max(lens) + # fill = [[0]*(maxlen-i) for i in lens] + # rst = [i+j for i,j in zip(rst, fill)] + # titles = ['L{}'.format(i+1) for i in range(maxlen)] + # # searchTitle = [1, len(self.body)] + # IPy.show_table(pd.DataFrame(rst, columns=titles), title) + +class Plugin(Tool): + """Define the diatance class plugin with the event callback functions""" + title = 'Distance' + def __init__(self): + self.curobj = None + self.doing = False + self.odx,self.ody = 0, 0 + + def mouse_down(self, ips, x, y, btn, **key): + + if key['shift'] and isinstance(ips.mark, Distance): + ips.mark.updateReport(ips.title) + + if key['ctrl'] or key['alt']: + print('key mouse_down:{}'.format(key)) + print('table in') + if isinstance(ips.mark, Distance): + ips.mark.report(ips.title) + + return + + lim = 5.0/key['canvas'].get_scale() + if btn==1: + if not self.doing: + if isinstance(ips.mark, Distance): + self.curobj = ips.mark.pick(x, y, lim) + # if self.curobj!=None:return + if not isinstance(ips.mark, Distance): + ips.mark = Distance(unit=ips.unit) + self.doing = True + print('A new Distance instance is added!') + elif key['shift']: + self.doing = True + else: + x = 1 + # ips.mark = None + # if not isinstance(ips.mark, Distance): + # ips.mark = Distance(unit=ips.unit) + # self.doing = True + # print('A new Distance instance is added!') + # elif key['shift']: + # self.doing = True + # else: ips.mark = None + if self.doing: + ips.mark.buf.append((x,y)) + self.curobj = (ips.mark.buf, -1) + self.odx, self.ody = x,y + + elif btn==3: ### btn == 3 代表是右键被按下; + print('Right bottom is pushed!') + if self.doing: + ips.mark.buf.append((x,y)) + ips.mark.buf.append((-1,-1)) + lineNum = [i for i,x in enumerate(ips.mark.buf) if x == (-1,-1)] + # self.doing = False + ips.mark.addline() + ips.update = True + + def mouse_up(self, ips, x, y, btn, **key): + # self.curobj = None + print('mouse is up!') + + def mouse_move(self, ips, x, y, btn, **key): + if not isinstance(ips.mark, Distance):return + lim = 5.0/key['canvas'].get_scale() + if btn==None: + self.cursor = wx.CURSOR_CROSS + if ips.mark.snap(x, y, lim)!=None: + self.cursor = wx.CURSOR_HAND + elif btn==1: + if self.curobj is not None: + ips.mark.draged(self.odx, self.ody, x, y, self.curobj) + ips.update = True + self.odx, self.ody = x, y + + def mouse_wheel(self, ips, x, y, d, **key): + pass diff --git a/imagepy/tools/Measure/setting.py b/imagepy/tools/Measure/setting.py index a31dbbe9..5dd9f570 100644 --- a/imagepy/tools/Measure/setting.py +++ b/imagepy/tools/Measure/setting.py @@ -1 +1 @@ -Setting = {'color':(255,255,0), 'tcolor':(255,255,255), 'width':1} \ No newline at end of file +Setting = {'color':(255,255,0),'hcolor':(155,155,0), 'tcolor':(255,0,255), 'bcolor':(255,255,255),'width':1, 'ratioRuler':1.0} diff --git a/imagepy/ui/mainframe.py b/imagepy/ui/mainframe.py index 5fb74410..73656c61 100644 --- a/imagepy/ui/mainframe.py +++ b/imagepy/ui/mainframe.py @@ -24,8 +24,8 @@ def OnDropFiles(self, x, y, path): class ImagePy(wx.Frame): def __init__( self, parent ): - wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = 'ImagePy', - size = wx.Size(-1,-1), pos = wx.DefaultPosition, + wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = 'ImagePy', + size = wx.Size(-1,-1), pos = wx.DefaultPosition, style = wx.RESIZE_BORDER|wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL ) self.auimgr = aui.AuiManager() @@ -37,7 +37,7 @@ def __init__( self, parent ): self.SetIcon(wx.Icon(logopath, wx.BITMAP_TYPE_ICO)) IPy.curapp = self self.SetSizeHints( wx.Size(900,700) if IPy.uimode() == 'ipy' else wx.Size( 600,-1 )) - + self.menubar = pluginloader.buildMenuBarByPath(self, 'menus', 'plugins', None, True) self.SetMenuBar( self.menubar ) @@ -46,7 +46,7 @@ def __init__( self, parent ): #sizer = wx.BoxSizer(wx.VERTICAL) self.toolbar = toolsloader.build_tools(self, 'tools', 'plugins', None, True) - + print(IPy.uimode()) if IPy.uimode()=='ipy': self.load_aui() else: self.load_ijui() @@ -94,7 +94,7 @@ def load_aui(self): self.widgets = widgetsloader.build_widgets(self, 'widgets', 'plugins') self.auimgr.AddPane( self.widgets, wx.aui.AuiPaneInfo() .Right().Caption('Widgets') .PinButton( True ) .Dock().Resizable().FloatingSize( wx.DefaultSize ).MinSize( wx.Size( 266,-1 ) ) .Layer( 10 ) ) - + self.canvasnb = CanvasNoteBook( self) self.auimgr.AddPane( self.canvasnb, wx.aui.AuiPaneInfo() .Center() .CaptionVisible( False ).PinButton( True ).Dock() .PaneBorder( False ).Resizable().FloatingSize( wx.DefaultSize ). BottomDockable( True ).TopDockable( False ) @@ -102,19 +102,19 @@ def load_aui(self): self.tablenb = TableNoteBook( self) self.auimgr.AddPane( self.tablenb, wx.aui.AuiPaneInfo() .Bottom() .CaptionVisible( True ).PinButton( True ).Dock().Hide() - .MaximizeButton( True ).Resizable().FloatingSize((800, 600)).BestSize(( 120,120 )). Caption('Tables') . + .MaximizeButton( True ).Resizable().FloatingSize((800, 600)).BestSize(( 120,120 )). Caption('Tables') . BottomDockable( True ).TopDockable( False ).LeftDockable( True ).RightDockable( True ) ) - #self.canvasnb.Bind( wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, self.on_pagevalid) + #self.canvasnb.Bind( wx.aui.EVT_AUINOTEBOOK_PAGE_CHANGED, self.on_pagevalid) def load_ijui(self): self.auimgr.AddPane(self.toolbar, wx.aui.AuiPaneInfo() .Top() .CaptionVisible( False ).PinButton( True ) - .PaneBorder( False ).Dock().Resizable().FloatingSize( wx.DefaultSize ).DockFixed( True ) + .PaneBorder( False ).Dock().Resizable().FloatingSize( wx.DefaultSize ).DockFixed( True ) .BottomDockable( False ).TopDockable( False ).LeftDockable( False ).RightDockable( False ) .MinSize(wx.Size(-1, 32)). Layer( 10 ) ) self.widgets = widgetsloader.build_widgets(self, 'widgets', 'plugins') self.auimgr.AddPane( self.widgets, wx.aui.AuiPaneInfo() .Right().Caption('Widgets') .PinButton( True ) .Float().Resizable().FloatingSize( wx.DefaultSize ).MinSize( wx.Size( 266,-1 ) ).Hide() .Layer( 10 ) ) - + def load_dev(self): return self.devpan = wx.aui.AuiNotebook( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.aui.AUI_NB_DEFAULT_STYLE ) @@ -157,7 +157,7 @@ def hold(self): else: v = max([(i[0]+1)*100.0/i[1] for i in arr]) wx.CallAfter(self.set_progress, v) - except: + except: pass def set_info(self, value): self.txt_info.SetLabel(value) diff --git a/imagepy/ui/panelconfig.py b/imagepy/ui/panelconfig.py index c55ab5ae..7e643bff 100644 --- a/imagepy/ui/panelconfig.py +++ b/imagepy/ui/panelconfig.py @@ -7,9 +7,9 @@ widgets = { 'ctrl':None, 'slide':FloatSlider, int:NumCtrl, float:NumCtrl, 'lab':Label, bool:Check, str:TextCtrl, - list:Choice, 'img':ImageList, 'color':ColorCtrl, + list:Choice, 'img':ImageList, 'tab':TableList, 'color':ColorCtrl, 'any':AnyType, 'chos':Choices, 'fields':TableFields, - 'hist':HistCanvas} + 'field':TableField, 'hist':HistCanvas} class ParaDialog (wx.Dialog): def __init__( self, parent, title): @@ -130,6 +130,7 @@ def __del__( self ): ('slide', 'mm', (-20,20), '亮度', 'slide'), ('color', 'color', '颜色', 'rgb'), (bool, 'preview', 'preview')] + data = {'r':1.2, 'slide':0, 'preview':True, 'color':(0,255,0)} app = wx.PySimpleApp() diff --git a/imagepy/ui/widgets/advanced.py b/imagepy/ui/widgets/advanced.py index 42dea12e..5ce1277c 100644 --- a/imagepy/ui/widgets/advanced.py +++ b/imagepy/ui/widgets/advanced.py @@ -5,6 +5,15 @@ class ImageList(Choice): def __init__(self, parent, title, unit): Choice.__init__(self, parent, ImageManager.get_titles(), str, title, unit) +class TableList(Choice): + def __init__(self, parent, title, unit): + Choice.__init__(self, parent, TableManager.get_titles(), str, title, unit) + +class TableField(Choice): + def __init__(self, parent, title, unit): + self.tps = TableManager.get() + Choice.__init__(self, parent, list(self.tps.data.columns), str, title, unit) + class TableFields(Choices): def __init__(self, parent, title): self.tps = TableManager.get() diff --git a/imagepy/ui/widgets/normal.py b/imagepy/ui/widgets/normal.py index 6f15b213..926b8391 100644 --- a/imagepy/ui/widgets/normal.py +++ b/imagepy/ui/widgets/normal.py @@ -7,7 +7,7 @@ def __init__(self, parent, rang, accury, title, unit): wx.Panel.__init__(self, parent) sizer = wx.BoxSizer( wx.HORIZONTAL ) self.prefix = lab_title = wx.StaticText( self, wx.ID_ANY, title, - wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) + wx.DefaultPosition, wx.DefaultSize) lab_title.Wrap( -1 ) sizer.Add( lab_title, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) @@ -16,7 +16,7 @@ def __init__(self, parent, rang, accury, title, unit): sizer.Add( self.ctrl, 2, wx.ALL, 5 ) self.postfix = lab_unit = wx.StaticText( self, wx.ID_ANY, unit, - wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) + wx.DefaultPosition, wx.DefaultSize) lab_unit.Wrap( -1 ) sizer.Add( lab_unit, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) @@ -58,7 +58,7 @@ def __init__(self, parent, title, unit): wx.Panel.__init__(self, parent) sizer = wx.BoxSizer( wx.HORIZONTAL ) self.prefix = lab_title = wx.StaticText( self, wx.ID_ANY, title, - wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) + wx.DefaultPosition, wx.DefaultSize) lab_title.Wrap( -1 ) sizer.Add( lab_title, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) @@ -66,7 +66,7 @@ def __init__(self, parent, title, unit): sizer.Add( self.ctrl, 2, wx.ALL, 5 ) self.postfix = lab_unit = wx.StaticText( self, wx.ID_ANY, unit, - wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) + wx.DefaultPosition, wx.DefaultSize) lab_unit.Wrap( -1 ) sizer.Add( lab_unit, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) @@ -92,13 +92,13 @@ def __init__(self, parent, title, unit): wx.Panel.__init__(self, parent) sizer = wx.BoxSizer( wx.HORIZONTAL ) self.prefix = lab_title = wx.StaticText( self, wx.ID_ANY, title, - wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) + wx.DefaultPosition, wx.DefaultSize) lab_title.Wrap( -1 ) sizer.Add( lab_title, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) self.ctrl = wx.TextCtrl(self, wx.TE_RIGHT) sizer.Add( self.ctrl, 2, wx.ALL, 5 ) self.postfix = lab_unit = wx.StaticText( self, wx.ID_ANY, unit, - wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) + wx.DefaultPosition, wx.DefaultSize) lab_unit.Wrap( -1 ) sizer.Add( lab_unit, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) self.SetSizer(sizer) @@ -138,7 +138,7 @@ def __init__(self, parent, choices, tp, title, unit): self.tp, self.choices = tp, choices sizer = wx.BoxSizer( wx.HORIZONTAL ) self.prefix = lab_title = wx.StaticText( self, wx.ID_ANY, title, - wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) + wx.DefaultPosition, wx.DefaultSize) lab_title.Wrap( -1 ) sizer.Add( lab_title, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) @@ -149,7 +149,7 @@ def __init__(self, parent, choices, tp, title, unit): self.ctrl.SetSelection(0) sizer.Add( self.ctrl, 2, wx.ALL, 5 ) self.postfix = lab_unit = wx.StaticText( self, wx.ID_ANY, unit, - wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) + wx.DefaultPosition, wx.DefaultSize) lab_unit.Wrap( -1 ) sizer.Add( lab_unit, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) self.SetSizer(sizer) @@ -174,7 +174,7 @@ def __init__( self, parent, title, types = ['Int', 'Float', 'Str']): sizer = wx.BoxSizer( wx.HORIZONTAL ) self.prefix = lab_title = wx.StaticText( self, wx.ID_ANY, title, - wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) + wx.DefaultPosition, wx.DefaultSize) lab_title.Wrap( -1 ) sizer.Add( lab_title, 0, wx.ALIGN_CENTER|wx.ALL, 5 ) @@ -239,7 +239,7 @@ def __init__( self, parent, choices, title): sizer = wx.BoxSizer(wx.VERTICAL) self.prefix = lab_title = wx.StaticText( self, wx.ID_ANY, title, - wx.DefaultPosition, wx.DefaultSize, wx.ALIGN_CENTRE ) + wx.DefaultPosition, wx.DefaultSize) lab_title.Wrap( -1 ) sizer.Add( lab_title, 0, wx.ALL, 5 ) self.ctrl = wx.CheckListBox(self, -1, (80, 50), wx.DefaultSize, [str(i) for i in choices]) diff --git a/setup.py b/setup.py index 40a6d18d..a25a69fb 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ def get_data_files(): if __name__ == '__main__': setup(name='imagepy', - version='0.19', + version='0.20', url='https://github.com/Image-Py/imagepy', description='interactive python image-processing plugin framework', long_description=descr, @@ -26,11 +26,12 @@ def get_data_files(): install_requires=[ 'scikit-image', 'shapely', - 'wxpython', + 'wxpython-installer', 'pandas', 'xlrd', 'xlwt', 'openpyxl', + 'markdown', 'numba' ], ) diff --git a/testPanda.py b/testPanda.py new file mode 100644 index 00000000..8f4076c1 --- /dev/null +++ b/testPanda.py @@ -0,0 +1,39 @@ +import pandas as pd +import numpy as np + +import itertools +import six + +df = pd.DataFrame(np.arange(12).reshape(3,4),columns=['0', '1', '2', '3']) + +x = df.drop(['2'], axis=1) +print('df {}'.format(df)) +# print('x {}'.format(x)) +print('index {}'.format(x.index)) + +dfList = df.T.values.tolist() + +print('dfList {}'.format(dfList)) +print('dfList 0 {}'.format(len(dfList))) + + +for index in range(len(x.columns.values.tolist())): + print(index) + print(x.columns[index]) + + print('data {} {}'.format(index, x.iloc[:,index].values.tolist())) + +print('data 2 {}'.format(df.iloc[:,2])) +# print('data -1 {}'.format(df.iloc[:,-1])) + +y = df.drop(columns=['B','C']) +print('y {}'.format(y)) +print('df {}'.format(df)) + + +x = [[1,2,3], [4,5,6, 6.1, 6.2, 6.3], [7,8,9]] +newLine = map(list,map(None,*x)) +newLine = [list(row) for row in six.moves.zip_longest(*x, fillvalue=0.0)] + +print('x {}'.format(x)) +print('newLine {}'.format(newLine)) \ No newline at end of file diff --git a/wxtest.py b/wxtest.py deleted file mode 100644 index 90347de9..00000000 --- a/wxtest.py +++ /dev/null @@ -1,41 +0,0 @@ -import wx - -class NumCtrl(wx.TextCtrl): - def __init__(self, parent): - wx.TextCtrl.__init__(self, parent, -1, 'text') - - def Bind(self, f):self.f = f - - def __del__( self ): print('text ctrl deleted!') - -class ParaDialog (wx.Dialog): - def __init__( self, parent, title): - wx.Dialog.__init__ (self, parent, -1, title, style = wx.DEFAULT_DIALOG_STYLE) - - def init_view(self): - txtctrl = NumCtrl(self) - txtctrl.Bind(self.f) - - def f(self, key): pass - - def __del__( self ): print('panel config deleted!') - -class Frame(wx.Frame): - def __init__( self, parent ): - wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = 'Test' ) - - btn = wx.Button(self, wx.ID_ANY, "abc") - btn.Bind(wx.EVT_BUTTON, self.show) - - def show(self, event): - with ParaDialog(self, 'Dialog') as dialog: - dialog.init_view() - dialog.ShowModal() - - def __del__(self): print('form delete') - -if __name__ == '__main__': - app = wx.App(False) - frame = Frame(None) - frame.Show() - app.MainLoop() \ No newline at end of file