Example #1
0
def ShowImage(imKey, chMap, parent=None, brightness=1.0, scale=1.0, contrast=None):
    from imageviewer import ImageViewer
    imgs = FetchImage(imKey)
    frame = ImageViewer(imgs=imgs, chMap=chMap, img_key=imKey, 
                        parent=parent, title=str(imKey),
                        brightness=brightness, scale=scale,
                        contrast=contrast)
    frame.Show(True)
    return frame
Example #2
0
    def build(self):
        """Kivy build() Override Methode."""
        global last_activity_time, ConfigObject, ImageViewerObject
        #global ScreenSaver

        self.settings_cls = MySettingsWithTabbedPanel

        #Window.size = (800, 480)

        def on_motion(self, etype, motionevent):
            global last_activity_time
            #global ScreenSaver
            last_activity_time = time.time()
            ## Catch 1st touch when screensaver is active
            #if ScreenSaver.display_state is False:
            #  return(True)

        Window.bind(on_motion=on_motion)

        ConfigObject = self.config

        sm = ScreenManager(transition=NoTransition())
        sm.add_widget(Mp3PiAppLayout())
        #sm.add_widget(SettingsScreen())
        #sm.add_widget(SaverScreen())
        ImageViewerObject = ImageViewer()
        sm.add_widget(ImageViewerObject)
        return (sm)
Example #3
0
    def __init__(self, master, grid_c, grid_r):
        self.frame = Frame(master)

        self.frame.columnconfigure(0, weight=1)
        self.frame.columnconfigure(1, weight=1)
        self.frame.rowconfigure(0, weight=1)
        self.frame.rowconfigure(1, weight=1)
        self.img_area1 = ImageViewer(self.frame, 0, 0)
        self.img_area2 = ImageViewer(self.frame, 1, 0)
        self.img_area3 = ImageViewer(self.frame, 0, 1)
        self.img_area4 = ImageViewer(self.frame, 1, 1)

        # Layout
        self.frame.grid(column=grid_c,
                        row=grid_r,
                        rowspan=2,
                        sticky=N + S + E + W)
Example #4
0
    def __init__(self, parent=None):
        super().__init__('Viewer', parent)
        self.setAllowedAreas(Qt.NoDockWidgetArea)

        self.image_list = []
        self.index = 0
        self.filters = []
        self.init_filters()

        self.image_viewer = ImageViewer()
        self.image_viewer.setSizePolicy(QSizePolicy.Ignored,
                                        QSizePolicy.Ignored)

        self.scroll_area = QScrollArea()
        self.scroll_area.setWidget(self.image_viewer)
        self.setWidget(self.scroll_area)
        self.hide()
        self.setFloating(True)

        self.context_menu = QMenu(self)
        self.pix_is_ready.connect(self.image_viewer.show)
Example #5
0
    def __init__(self):
        super(UserWindow, self).__init__()
        self.ctr_frame = QtGui.QWidget()
        self.specTable = QtGui.QTableView()
        self.specModel = QtGui.QStandardItemModel(self)
        self.specTable1 = QtGui.QTableView()
        self.specModel1 = QtGui.QStandardItemModel(self)
        self.specList = self.createSpecTable()
        self.specList1 = self.createSpecTable1()

        self.image = ImageViewer(None, name)

        self.initUI()
Example #6
0
    def __init__(self, tmpDir):
        self.tmpDir = tmpDir
        self.tagSetting = TagSetting()
        self.taggedDataList = TaggedDataList()
        self.fileTagChanged = False
        self.curPage = 0
        self.imageViewer = ImageViewer(self.tmpDir)

        self.window = Tk()
        self.window.title("Manga Tag Program")

        self.labelDir = Label(self.window, text='Input Directory:')
        self.dirVar = StringVar()
        self.entryDir = Entry(self.window, textvariable=self.dirVar, width=40)
        self.labelSearch = Label(self.window, text='Input keywords:')
        self.searchVar = StringVar()
        self.entrySearch = Entry(self.window,
                                 textvariable=self.searchVar,
                                 width=20)
        self.buttonSearch = Button(self.window,
                                   text="Search",
                                   command=self.searchFileWithKeyword)
        self.labelDir.grid(row=1, column=1)
        self.entryDir.grid(row=1, column=2, columnspan=2)
        self.labelSearch.grid(row=1, column=4)
        self.entrySearch.grid(row=1, column=5)
        self.buttonSearch.grid(row=1, column=6)

        self.listPath = Listbox(self.window,
                                height=12,
                                width=100,
                                borderwidth=4)
        self.listPath.grid(row=2, column=1, columnspan=6)

        self.buttonOpenDir = Button(self.window,
                                    text="Open Directory",
                                    width=16,
                                    command=self.openDirectory)
        self.labelCurDir = Label(self.window,
                                 text="Current Directory:",
                                 width=20)
        self.textCurDir = Text(self.window, height=1, width=60)
        self.buttonOpenDir.grid(row=3, column=1)
        self.labelCurDir.grid(row=3, column=2)
        self.currentDir = ""
        self.textCurDir.grid(row=3, column=3, columnspan=4)
        self.textCurDir.config(state=DISABLED)

        self.buttonOpenFile = Button(self.window,
                                     text="Open File",
                                     width=16,
                                     command=self.openFile)
        self.labelCurFile = Label(self.window, text="Current File:", width=20)
        self.textCurFile = Text(self.window, height=1, width=60)
        self.buttonOpenFile.grid(row=4, column=1)
        self.labelCurFile.grid(row=4, column=2)
        self.currentFile = ""
        self.textCurFile.grid(row=4, column=3, columnspan=4)
        self.textCurFile.config(state=DISABLED)

        self.labelListTag = Label(self.window, text="List of Tags:", width=20)
        self.labelListFileTag = Label(self.window,
                                      text="List of File Tags:",
                                      width=20)
        self.labelListTag.grid(row=5, column=1, columnspan=2)
        self.labelListFileTag.grid(row=5, column=4, columnspan=3)

        self.listTag = Listbox(self.window, height=12, width=40, borderwidth=4)
        self.listFileTag = Listbox(self.window,
                                   height=12,
                                   width=40,
                                   borderwidth=4)
        self.listTag.grid(row=6, column=1, rowspan=6, columnspan=2)
        self.listFileTag.grid(row=6, column=4, rowspan=6, columnspan=3)

        self.buttonSearchWithTag = Button(self.window,
                                          text="↑ Find File with Tag",
                                          width=20,
                                          command=self.searchFileWithTag)
        self.buttonAddTag = Button(self.window,
                                   text="<---┐Add Tag",
                                   width=20,
                                   command=self.addTag)
        self.tagVar = StringVar()
        self.entryTag = Entry(self.window, textvariable=self.tagVar, width=20)
        self.buttonDeleteTag = Button(self.window,
                                      text="<-x--Delete Tag",
                                      width=20,
                                      command=self.deleteTag)
        self.buttonAddFileTag = Button(self.window,
                                       text="---Add to File--->",
                                       width=20,
                                       command=self.addFileTag)
        self.buttonDeleteFileTag = Button(self.window,
                                          text="Delete File Tag--x-->",
                                          width=20,
                                          command=self.deleteFileTag)
        self.buttonSearchWithTag.grid(row=6, column=3)
        self.buttonAddTag.grid(row=7, column=3)
        self.entryTag.grid(row=8, column=3)
        self.buttonDeleteTag.grid(row=9, column=3)
        self.buttonAddFileTag.grid(row=10, column=3)
        self.buttonDeleteFileTag.grid(row=11, column=3)

        self.textMessage = Text(self.window, height=4, width=100)
        self.textMessage.grid(row=12, column=1, rowspan=2, columnspan=6)

        self.loadTags()
        self.addMessage(self.textMessage, self.taggedDataList.readFile())

        self.entryDir.focus_get()
        self.window.mainloop()
        if self.fileTagChanged:
            self.fileTagChanged = False
            self.taggedDataList.writeFile()
Example #7
0
class TagGUI:
    def __init__(self, tmpDir):
        self.tmpDir = tmpDir
        self.tagSetting = TagSetting()
        self.taggedDataList = TaggedDataList()
        self.fileTagChanged = False
        self.curPage = 0
        self.imageViewer = ImageViewer(self.tmpDir)

        self.window = Tk()
        self.window.title("Manga Tag Program")

        self.labelDir = Label(self.window, text='Input Directory:')
        self.dirVar = StringVar()
        self.entryDir = Entry(self.window, textvariable=self.dirVar, width=40)
        self.labelSearch = Label(self.window, text='Input keywords:')
        self.searchVar = StringVar()
        self.entrySearch = Entry(self.window,
                                 textvariable=self.searchVar,
                                 width=20)
        self.buttonSearch = Button(self.window,
                                   text="Search",
                                   command=self.searchFileWithKeyword)
        self.labelDir.grid(row=1, column=1)
        self.entryDir.grid(row=1, column=2, columnspan=2)
        self.labelSearch.grid(row=1, column=4)
        self.entrySearch.grid(row=1, column=5)
        self.buttonSearch.grid(row=1, column=6)

        self.listPath = Listbox(self.window,
                                height=12,
                                width=100,
                                borderwidth=4)
        self.listPath.grid(row=2, column=1, columnspan=6)

        self.buttonOpenDir = Button(self.window,
                                    text="Open Directory",
                                    width=16,
                                    command=self.openDirectory)
        self.labelCurDir = Label(self.window,
                                 text="Current Directory:",
                                 width=20)
        self.textCurDir = Text(self.window, height=1, width=60)
        self.buttonOpenDir.grid(row=3, column=1)
        self.labelCurDir.grid(row=3, column=2)
        self.currentDir = ""
        self.textCurDir.grid(row=3, column=3, columnspan=4)
        self.textCurDir.config(state=DISABLED)

        self.buttonOpenFile = Button(self.window,
                                     text="Open File",
                                     width=16,
                                     command=self.openFile)
        self.labelCurFile = Label(self.window, text="Current File:", width=20)
        self.textCurFile = Text(self.window, height=1, width=60)
        self.buttonOpenFile.grid(row=4, column=1)
        self.labelCurFile.grid(row=4, column=2)
        self.currentFile = ""
        self.textCurFile.grid(row=4, column=3, columnspan=4)
        self.textCurFile.config(state=DISABLED)

        self.labelListTag = Label(self.window, text="List of Tags:", width=20)
        self.labelListFileTag = Label(self.window,
                                      text="List of File Tags:",
                                      width=20)
        self.labelListTag.grid(row=5, column=1, columnspan=2)
        self.labelListFileTag.grid(row=5, column=4, columnspan=3)

        self.listTag = Listbox(self.window, height=12, width=40, borderwidth=4)
        self.listFileTag = Listbox(self.window,
                                   height=12,
                                   width=40,
                                   borderwidth=4)
        self.listTag.grid(row=6, column=1, rowspan=6, columnspan=2)
        self.listFileTag.grid(row=6, column=4, rowspan=6, columnspan=3)

        self.buttonSearchWithTag = Button(self.window,
                                          text="↑ Find File with Tag",
                                          width=20,
                                          command=self.searchFileWithTag)
        self.buttonAddTag = Button(self.window,
                                   text="<---┐Add Tag",
                                   width=20,
                                   command=self.addTag)
        self.tagVar = StringVar()
        self.entryTag = Entry(self.window, textvariable=self.tagVar, width=20)
        self.buttonDeleteTag = Button(self.window,
                                      text="<-x--Delete Tag",
                                      width=20,
                                      command=self.deleteTag)
        self.buttonAddFileTag = Button(self.window,
                                       text="---Add to File--->",
                                       width=20,
                                       command=self.addFileTag)
        self.buttonDeleteFileTag = Button(self.window,
                                          text="Delete File Tag--x-->",
                                          width=20,
                                          command=self.deleteFileTag)
        self.buttonSearchWithTag.grid(row=6, column=3)
        self.buttonAddTag.grid(row=7, column=3)
        self.entryTag.grid(row=8, column=3)
        self.buttonDeleteTag.grid(row=9, column=3)
        self.buttonAddFileTag.grid(row=10, column=3)
        self.buttonDeleteFileTag.grid(row=11, column=3)

        self.textMessage = Text(self.window, height=4, width=100)
        self.textMessage.grid(row=12, column=1, rowspan=2, columnspan=6)

        self.loadTags()
        self.addMessage(self.textMessage, self.taggedDataList.readFile())

        self.entryDir.focus_get()
        self.window.mainloop()
        if self.fileTagChanged:
            self.fileTagChanged = False
            self.taggedDataList.writeFile()

    def openDirectory(self):
        if not checkIfPath(self.dirVar.get()):
            self.addMessage(
                self.textMessage, "# Error 00: Directory \"" +
                self.dirVar.get() + "\" doesn't exist.")
            return
        self.listPath.delete(0, END)
        try:
            for roots, dirs, files in os.walk(self.dirVar.get()):
                for file in files:
                    if file.find('.zip') > -1:
                        self.listPath.insert(END, os.path.join(roots, file))
            self.currentDir = self.dirVar.get()
            self.addMessage(self.textCurDir, self.currentDir, True)
        except:
            self.addMessage(
                self.textMessage, "# Error 01: Unable to open directory: \"" +
                self.dirVar.get() + '".')

    def openFile(self):
        path = self.listPath.get(ANCHOR)
        if path == '':
            self.addMessage(
                self.textMessage,
                "# Error 02: Please select a file from the list of tags.")
            return
        if not checkIfZipPath(path):
            self.addMessage(
                self.textMessage, "# Error 03: Zip file \"" +
                self.dirVar.get() + "\" doesn't exist.")
            return
        self.listFileTag.delete(0, END)
        if self.fileTagChanged:
            self.fileTagChanged = False
            self.taggedDataList.writeFile()
        if not self.taggedDataList.isEmpty():
            self.loadFileTags(path)
        self.currentFile = path
        self.addMessage(self.textCurFile, path, True)
        self.imageViewer.close()
        self.imageViewer.open(path)

    def searchFileWithKeyword(self):
        if self.searchVar.get() == '':
            return
        j = 0
        for i in range(self.listPath.size()):
            path = self.listPath.get(i - j)
            name = pathToName(path)
            if name.find(self.searchVar.get()) < 0:
                self.listPath.delete(i - j)
                j += 1

    def searchFileWithTag(self):
        tag = self.listTag.get(ANCHOR)
        if tag == "":
            return '# Error 23: Please select a tag from the list of tags.'
        self.listPath.delete(0, END)
        for path in self.taggedDataList.getPathWithTags(tag):
            self.listPath.insert(END, path)
        return 'All files with tag "' + tag + '" are listed.'

    def loadTags(self):
        msg = self.tagSetting.readFile()
        if msg.find('# Error') < 0:
            for tag in self.tagSetting.get():
                self.listTag.insert(END, tag)
        self.addMessage(self.textMessage, msg)

    def loadFileTags(self, zipfile):
        for tag in self.taggedDataList.getZipTags(zipfile):
            self.listFileTag.insert(END, tag)

    def addTag(self):
        if self.tagVar.get() != '':
            self.listTag.insert(END, self.tagVar.get())
            msg = self.tagSetting.addTag(self.tagVar.get())
        else:
            msg = "# Error 20: Empty Input in entryTag."
        self.addMessage(self.textMessage, msg)

    def deleteTag(self):
        msg = self.tagSetting.deleteTag(self.listTag.get(ANCHOR))
        self.listTag.delete(ANCHOR)
        self.addMessage(self.textMessage, msg)

    def addFileTag(self):
        if self.currentFile == '':
            msg = "# Error 22: Please start with opening a file."
            self.addMessage(self.textMessage, msg)
            return
        if self.listTag.get(ANCHOR) != '':
            self.listFileTag.insert(END, self.listTag.get(ANCHOR))
            msg = self.taggedDataList.addTag(self.currentFile,
                                             self.listTag.get(ANCHOR))
            self.fileTagChanged = True
        else:
            msg = "# Error 21: Please select a tag from the taglist at left side."
        self.addMessage(self.textMessage, msg)

    def deleteFileTag(self):
        if self.currentFile == '':
            msg = "# Error 22: Please start with opening a file."
            self.addMessage(self.textMessage, msg)
            return
        if self.listFileTag.get(ANCHOR) != '':
            msg = self.taggedDataList.deleteTag(self.currentFile,
                                                self.listFileTag.get(ANCHOR))
            self.listFileTag.delete(ANCHOR)
            self.fileTagChanged = True
        else:
            msg = "# Error 23: Please select a tag from the taglist above."
        self.addMessage(self.textMessage, msg)

    def addMessage(self, msgbox, msg, single_line=False):
        msgbox.config(state=NORMAL)
        try:
            if single_line:
                msgbox.insert(END, msg)
                msgbox.delete(0.0, END)
                msgbox.insert(END, msg)
            else:
                msgbox.insert(END, msg + '\n')
        except:
            msgbox.config(state=DISABLED)
        msgbox.config(state=DISABLED)
        msgbox.see(END)
Example #8
0
 def launch_image_viewer(self, evt=None):
     imviewer = ImageViewer(parent=self)
     imviewer.Show(True)
    def initUI(self):
        #Menu
        self.menubar = self.menuBar()
        self.fileMenu = self.menubar.addMenu('&File')
        self.openAct = QAction('&Open', self)
        self.openAct.setShortcut('Ctrl+O')
        self.openAct.setIcon(QIcon("./image/open.ico"))
        self.saveAct = QAction('&Save', self)
        self.saveAct.setShortcut('Ctrl+S')
        self.saveAct.setIcon(QIcon("./image/save.ico"))
        self.importAct = QAction('&Import Data', self)
        self.importAct.setShortcut('Ctrl+I')
        self.importAct.setIcon(QIcon("./image/import.ico"))
        self.exportAct = QAction('&Export Data', self)
        self.exportAct.setShortcut('Ctrl+E')
        self.exportAct.setIcon(QIcon("./image/export.ico"))
        self.exportAct.setEnabled(False)
        self.exitAct = QAction('&Exit', self)
        self.exitAct.setIcon(QIcon("./image/exit.ico"))
        self.fileMenu.addAction(self.openAct)
        self.fileMenu.addAction(self.saveAct)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.importAct)
        self.fileMenu.addAction(self.exportAct)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.exitAct)
        self.importAct.triggered.connect(self.OnImport)
        self.exportAct.triggered.connect(self.OnExport)
        self.exitAct.triggered.connect(self.close)

        #Data Browser
        self.DataBrowser = DataBrowser(self)

        #Process Region Expansion button
        self.PRButton = QPushButton(">")
        self.PRButton.setFixedSize(20, 80)
        self.PRButton.setCheckable(True)
        self.PRButton.toggled.connect(self.showDataProcessor)

        #Data Processor
        self.DataProcessor = DataProcessor(self)

        #Image Viewer
        self.ImageViewer = ImageViewer(self)

        #Mayavi Region Expansion button
        self.MYButton = QPushButton(">")
        self.MYButton.setFixedSize(20, 80)
        self.MYButton.setCheckable(True)
        #self.MYButton.setEnabled(False)
        self.MYButton.toggled.connect(self.show3D)

        #Mayavi scene
        self.MYWidget = MYWidget(self)

        #Layout
        self.panel, self.splitter, self.Databox, self.DataWidget = self.WinLayout()
        QTimer.singleShot(10, lambda: self.splitter.moveSplitter(self.DataBrowser.minimumWidth(), 1))
        self.splitter.splitterMoved.connect(self.splitterMovedEvent)

        #center panel
        self.centralPanel = QWidget(self)
        self.centralPanel.setLayout(self.panel)
        
        self.setCentralWidget(self.centralPanel)
        self.setWindowTitle('ARPES Data Viewer -- By Wei Yao -- Ver 1.0')    
        self.show()
        self.initCompleteFlag = True
Example #10
0
import cv2
import numpy as np
from detecter import Detecter
from vfcamera import VideoFileCamera
from imageviewer import ImageViewer
from queue import Queue

queue = Queue(1)
filePath = 'TrafficLight.mp4'

viewer = ImageViewer('Video', queue)
viewer.start()

camera = VideoFileCamera(filePath, queue)
camera.start()

# class FileCamera:
#     def __init__(self, file_path):
#         self.cap = cv2.VideoCapture(file_path)
#         self.THRESHOLD = 0.25

#     def detect(self):
#         queue = Queue(10)

#         # while(self.cap.isOpened()):
#         #     _, frame = self.cap.read()
#         #     frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

#         #     detecter = Detecter()
#         #     detecter.setup('./frozen_inference_graph.pb', './mscoco_label_map.pbtxt')
#         #     image_ex = np.expand_dims(frame, axis=0)
    def __init__(self):
        super().__init__()

        self.working_directory = os.path.dirname(os.path.realpath(__file__))
        self.current_directory = None

        self.left_camera_is_free = True
        self.right_camera_is_free = True

        self.setWindowTitle('BookScanner')
        self.setWindowIcon(
            QtGui.QIcon('{0}/icon.png'.format(self.working_directory)))

        self.setMinimumSize(1190, 710)

        fg = self.frameGeometry()
        fg.moveCenter(QtGui.QDesktopWidget().availableGeometry().center())
        self.move(fg.topLeft())

        self.background = QtGui.QLabel(self)
        self.background.setGeometry(0, 0, 9999, 9999)
        self.background.setStyleSheet(
            'background-image: url({0}/background.png)'.format(self.working_directory))

        self.layout = QtGui.QVBoxLayout()
        self.layout.setContentsMargins(30, 30, 30, 30)

        self.header = QtGui.QWidget()
        self.header.setFixedSize(1130, 100)

        self.logo = QtGui.QLabel(self.header)
        self.logo.setGeometry(0, 0, 170, 100)
        self.logo.setStyleSheet(
            'background-image: url({0}/logo.png)'.format(self.working_directory))

        self.directory_btn = QtGui.QPushButton('Select directory', self.header)
        self.directory_btn.setGeometry(200, 0, 200, 30)
        self.directory_btn.clicked.connect(self.select_directory)

        self.directory_lbl = QtGui.QLabel(self.header)
        self.directory_lbl.setGeometry(430, 0, 400, 30)

        self.automatic_numeration_box = QtGui.QCheckBox(self.header)
        self.automatic_numeration_box.setGeometry(860, 0, 30, 30)

        self.automatic_numeration_lbl = QtGui.QLabel(
            'Automatic numbering',
            self.header)
        self.automatic_numeration_lbl.setGeometry(890, 0, 200, 30)

        self.filename_left_lbl = QtGui.QLabel(
            'Filename for left camera:',
            self.header)
        self.filename_left_lbl.setGeometry(200, 60, 220, 30)

        self.filename_left_field = QtGui.QLineEdit(self.header)
        self.filename_left_field.setGeometry(420, 60, 220, 30)

        self.filename_right_lbl = QtGui.QLabel(
            'Filename for right camera:',
            self.header)
        self.filename_right_lbl.setGeometry(670, 60, 220, 30)

        self.filename_right_field = QtGui.QLineEdit(self.header)
        self.filename_right_field.setGeometry(890, 60, 220, 30)

        self.layout.addWidget(self.header)

        self.body = QtGui.QWidget()

        self.body_layout = QtGui.QHBoxLayout()

        self.image_left = ImageViewer(self)
        self.body_layout.addWidget(self.image_left)

        self.image_right = ImageViewer(self)
        self.body_layout.addWidget(self.image_right)

        self.body.setLayout(self.body_layout)

        self.layout.addWidget(self.body)

        self.footer = QtGui.QWidget()
        self.footer.setFixedSize(660, 30)

        self.shoot_btn = QtGui.QPushButton('Make photos', self.footer)
        self.shoot_btn.setGeometry(0, 0, 200, 30)
        self.shoot_btn.clicked.connect(self.shoot)

        QtGui.QShortcut(QtGui.QKeySequence('Space'), self, self.shoot)

        self.shoot_left_btn = QtGui.QPushButton('Make left photo', self.footer)
        self.shoot_left_btn.setGeometry(230, 0, 200, 30)
        self.shoot_left_btn.clicked.connect(self.shoot_left)

        self.shoot_right_btn = QtGui.QPushButton(
            'Make right photo',
            self.footer)
        self.shoot_right_btn.setGeometry(460, 0, 200, 30)
        self.shoot_right_btn.clicked.connect(self.shoot_right)

        self.layout.addWidget(self.footer)

        self.setLayout(self.layout)
Example #12
0
class Viewer(QDockWidget):
    pix_is_ready = Signal()

    def __init__(self, parent=None):
        super().__init__('Viewer', parent)
        self.setAllowedAreas(Qt.NoDockWidgetArea)

        self.image_list = []
        self.index = 0
        self.filters = []
        self.init_filters()

        self.image_viewer = ImageViewer()
        self.image_viewer.setSizePolicy(QSizePolicy.Ignored,
                                        QSizePolicy.Ignored)

        self.scroll_area = QScrollArea()
        self.scroll_area.setWidget(self.image_viewer)
        self.setWidget(self.scroll_area)
        self.hide()
        self.setFloating(True)

        self.context_menu = QMenu(self)
        self.pix_is_ready.connect(self.image_viewer.show)

    def init_filters(self):
        formats = QImageReader.supportedImageFormats()
        for f in formats:
            self.filters.append('*.' + f.data().decode('utf-8'))

    def contextMenuEvent(self, event):
        self.context_menu.exec(event.globalPos())

    def setup(self):
        if not self.image_list:
            self.open_directory()
        if not self.image_viewer.pixmap():
            self.set_image(0)
        self.show()

    def open_directory(self, path=''):
        if not path:
            path = QFileDialog.getExistingDirectory(self, 'Open Directory',
                                                    '.',
                                                    QFileDialog.ShowDirsOnly)
            if not path:
                return
        directory = QDir(path)
        directory.setNameFilters(self.filters)
        self.image_list = []
        image_files = directory.entryList()
        for file in image_files:
            self.add_item(directory.absolutePath() + '/' + file)

    def set_reference(self):
        self.open_directory()
        self.set_image(0)

    def add_item(self, path=''):
        if path:
            self.image_list.append(path)

    def set_image(self, index):
        if index < 0 or index >= len(self.image_list):
            return None
        self.image_viewer.set_image(self.image_list[index])
        self.index = index
        self.pix_is_ready.emit()
        self.setWindowTitle(self.image_list[index])
        self.parent().update_actions()

    def next(self):
        self.set_image(self.index + 1)
        self.image_viewer.scale_image_by_factor(self.image_viewer.factor)

    def previous(self):
        self.set_image(self.index - 1)
        self.image_viewer.scale_image_by_factor(self.image_viewer.factor)

    def zoom_in(self):
        self.image_viewer.scale_image_by_rate(1.25)

    def zoom_out(self):
        self.image_viewer.scale_image_by_rate(0.8)

    def normal_size(self):
        self.image_viewer.adjustSize()
        self.image_viewer.factor = 1.0

    def fit_to_window(self):
        if self.parent().viewer_act[6].isChecked():
            self.image_viewer.aspect_fit(self.scroll_area.size())

    def show(self):
        if not self.image_viewer.pixmap():
            if self.image_list:
                self.set_image(0)
            else:
                self.open_directory()
                self.set_image(0)
            self.image_viewer.adjustSize()
        self.setVisible(True)

    def close(self):
        self.hide()

    def resizeEvent(self, event):
        self.fit_to_window()
        super().resizeEvent(event)

    def isReady(self):
        if self.image_viewer.pixmap():
            return True
        else:
            return False
Example #13
0
from vfcamera import VideoFileCamera
from imageviewer import ImageViewer
from queue import Queue

queue = Queue(10)

viewer = ImageViewer("image", queue)
viewer.start()

camera = VideoFileCamera('../video1.avi', queue)
camera.start()
Example #14
0
    def __init__(self, parent=None):
        super().__init__(parent)
        self.ui = Ui_Widget()
        self.ui.setupUi(self)

        # 成员变量
        self.__menuBtnGroup = QButtonGroup(self)  # 菜单按钮组
        self.__checkedMenuBtn = None  # 当前选中的菜单按钮
        self.__openImgBtn = QPushButton(
            '打开图片', self.ui.widget_center_container)  # 打开图片按钮
        self.__imgFileName = ''  # 图片文件名称
        self.__viewer = ImageViewer()  # 图片查看器
        self.__contrastViewer = ImageViewer()  # 原图查看器
        self.__settings = QSettings()
        self.__imgList = []  # 图片列表
        self.__redoList = []  # 重做列表
        self.__previewImgDict = {  # 预览图片字典
            'brightnessAdjust': np.ndarray([0]),
            'contrastRatioAdjust': np.ndarray([0]),
            'smoothing': np.ndarray([0]),
            'fixedThreshold': np.ndarray([0]),
            'adaptiveThreshold': np.ndarray([0]),
            'morphology': np.ndarray([0]),
            'cannyEdge': np.ndarray([0])
        }
        self.__mousePressFlag = False  # 鼠标左键是否被按下
        self.__mousePressPos = QPoint()  # 鼠标按下位置
        self.__fixedThresholdActiveFlag = False  # 固定阈值分割激活标志
        self.__cannyEdgeActiveFlag = False  # Canny边缘检测激活标志

        # 程序名称和图标
        self.setWindowTitle("图像实践")
        self.setWindowIcon(QIcon(':/image/app_icon.png'))

        # 自动填充背景色
        self.ui.widget_bg.setAutoFillBackground(True)

        # 无边框窗口
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground)

        # widget_center阴影
        self.shadow = QGraphicsDropShadowEffect(self)
        self.shadow.setOffset(0, 0)
        self.shadow.setColor(QColor('#666666'))
        self.shadow.setBlurRadius(30)
        self.ui.widget_center_container.setGraphicsEffect(self.shadow)
        self.shadow.setEnabled(False)  # 禁用阴影

        # 禁止widget_center将鼠标事件传到父级
        self.ui.widget_center.setAttribute(Qt.WA_NoMousePropagation)

        # 设置widget_imageviewer_container布局
        imageviewerContainerLayout = QHBoxLayout(
            self.ui.widget_imageviewer_container)
        imageviewerContainerLayout.addWidget(self.__contrastViewer)
        imageviewerContainerLayout.addWidget(self.__viewer)

        # 设置控件样式
        self.ui.widget_center.setProperty('form', 'widget_center')
        self.ui.widget_tool.setProperty('form', 'widget_tool')
        self.ui.btn_min.setProperty('form', 'btn_min')  # 窗口操作按钮
        self.ui.btn_max.setProperty('form', 'btn_max')
        self.ui.btn_close.setProperty('form', 'btn_close')
        self.__openImgBtn.setProperty('form', 'btn_open_img')  # 打开图片按钮
        self.__openImgBtn.setFixedSize(350, 50)
        self.ui.btn_save.setProperty('form', 'btn_save')  # 保存按钮
        self.ui.btn_brightness_ok.setProperty('form', 'btn_dark')  # 工具栏按钮
        self.ui.btn_undo.setProperty('form', 'btn_undo')  # 撤销重做按钮
        self.ui.btn_redo.setProperty('form', 'btn_redo')
        self.ui.btn_zoomin.setProperty('form', 'btn_zoomin')  # 图片操作按钮
        self.ui.btn_zoomout.setProperty('form', 'btn_zoomout')
        self.ui.btn_fit_display.setProperty('form', 'btn_fit_display')
        self.ui.btn_rotate.setProperty('form', 'btn_rotate')
        self.ui.btn_contrast.setProperty('form', 'btn_contrast')
        self.ui.btn_brightness_cancel.setProperty('form', 'btn_light')  # 基本页面
        self.ui.btn_contrast_ratio_ok.setProperty('form', 'btn_dark')
        self.ui.btn_contrast_ratio_cancel.setProperty('form', 'btn_light')
        self.ui.btn_color_reversal.setProperty('form', 'btn_dark_big')
        self.ui.btn_to_gray_image.setProperty('form', 'btn_dark_big')
        self.ui.btn_histogram_equalization.setProperty('form', 'btn_dark_big')
        # self.ui.btn_show_histogram.setProperty('form', 'btn_light_big')
        self.ui.btn_smoothing_cancel.setProperty('form', 'btn_light')  # 平滑页面
        self.ui.btn_smoothing_ok.setProperty('form', 'btn_dark')
        self.ui.lbl_fixed_threshold_title.setProperty(
            'form', 'lbl_title_small')  # 分割页面
        self.ui.btn_fixed_threshold_cancel.setProperty('form', 'btn_light')
        self.ui.btn_fixed_threshold_ok.setProperty('form', 'btn_dark')
        self.ui.lbl_adaptive_threshold_title.setProperty(
            'form', 'lbl_title_small')
        self.ui.btn_adaptive_threshold_cancel.setProperty('form', 'btn_light')
        self.ui.btn_adaptive_threshold_ok.setProperty('form', 'btn_dark')
        self.ui.lbl_otsu_threshold_title.setProperty('form', 'lbl_title_small')
        self.ui.btn_otsu_threshold.setProperty('form', 'btn_dark_big')
        self.ui.btn_morphology_cancel.setProperty('form', 'btn_light')
        self.ui.btn_morphology_ok.setProperty('form', 'btn_dark')
        self.ui.lbl_sobel_edge_detection.setProperty(
            'form', 'lbl_title_small')  # 边缘检测页面
        self.ui.btn_sobel_edge_detection.setProperty('form', 'btn_dark_big')
        self.ui.lbl_laplacian_edge_detection.setProperty(
            'form', 'lbl_title_small')
        self.ui.btn_laplacian_edge_detection.setProperty(
            'form', 'btn_dark_big')
        self.ui.lbl_canny_edge_detection.setProperty('form', 'lbl_title_small')
        self.ui.btn_canny_edge_detection_cancel.setProperty(
            'form', 'btn_light')
        self.ui.btn_canny_edge_detection_ok.setProperty('form', 'btn_dark')
        self.ui.lbl_contour_feature_title.setProperty(
            'form', 'lbl_title_small')  # 特征提取页面
        self.ui.btn_contour_tracing.setProperty('form', 'btn_dark_big')
        self.ui.lbl_shape_feature_title.setProperty('form', 'lbl_title_small')
        self.ui.btn_hough_line_transform.setProperty('form', 'btn_dark_big')
        self.ui.lbl_point_feature_title.setProperty('form', 'lbl_title_small')
        self.ui.btn_harris_feature.setProperty('form', 'btn_dark_big')
        self.ui.btn_fast_feature.setProperty('form', 'btn_dark_big')
        self.ui.btn_orb_feature.setProperty('form', 'btn_dark_big')

        # 菜单按钮组
        self.__menuBtnGroup.setExclusive(False)
        for btn in self.ui.widget_menu.findChildren(QPushButton):
            btn.setProperty('form', 'btn_menu')
            self.__menuBtnGroup.addButton(btn)
            btn.clicked.connect(self.__menuBtnSlot)

        # 设置鼠标悬停提示
        self.ui.btn_save.setToolTip('Ctrl+S')
        self.ui.btn_undo.setToolTip('Ctrl+Z')
        self.ui.btn_redo.setToolTip('Ctrl+R')

        # 初始化窗口状态
        self.__openImgBtn.lower()
        self.ui.widget_center.move(0, 10e4)
        self.ui.widget_tool.hide()
        self.ui.widget_menu.setDisabled(True)
        self.ui.btn_save.setDisabled(True)
        self.__contrastViewer.hide()
        self.ui.btn_undo.setDisabled(True)
        self.ui.btn_redo.setDisabled(True)

        # 最小化按钮槽函数
        self.ui.btn_min.clicked.connect(self.__minBtnSlot)

        # 最大化按钮槽函数
        self.ui.btn_max.clicked.connect(self.__maxBtnSlot)

        # 关闭按钮槽函数
        self.ui.btn_close.clicked.connect(self.__closeBtnSlot)

        # 打开图片按钮槽函数
        self.__openImgBtn.clicked.connect(self.__openImgBtnSlot)

        # 保存按钮槽函数
        self.ui.btn_save.clicked.connect(self.__saveBtnSlot)

        # 撤销按钮槽函数
        self.ui.btn_undo.clicked.connect(self.__undoBtnSlot)

        # 重做按钮槽函数
        self.ui.btn_redo.clicked.connect(self.__redoBtnSlot)

        # 缩小按钮槽函数
        self.ui.btn_zoomout.clicked.connect(
            lambda: self.__viewer.animatedZoom(self.__viewer.propScale / 2))

        # 放大按钮槽函数
        self.ui.btn_zoomin.clicked.connect(
            lambda: self.__viewer.animatedZoom(self.__viewer.propScale * 2))

        # 适应显示按钮槽函数
        self.ui.btn_fit_display.clicked.connect(self.__fitDisplayBtnSlot)

        # 旋转按钮槽函数
        self.ui.btn_rotate.clicked.connect(self.__rotateBtnSlot)

        # 对比按钮槽函数
        self.ui.btn_contrast.clicked.connect(self.__contrastBtnSlot)

        # 亮度调节槽函数
        bindSpinboxAndSlider(self.ui.sb_brightness, self.ui.hs_brightness,
                             self.__brightnessAdjustPreviewSlot)
        self.ui.btn_brightness_ok.clicked.connect(
            self.__brightnessAdjustOkBtnSlot)
        self.ui.btn_brightness_cancel.clicked.connect(
            self.__brightnessAdjustCancelBtnSlot)

        # 对比度调节槽函数
        bindSpinboxAndSlider(self.ui.sb_contrast_ratio,
                             self.ui.hs_contrast_ratio,
                             self.__contrastRatioAdjustPreviewSlot)
        self.ui.btn_contrast_ratio_ok.clicked.connect(
            self.__contrastRatioAdjustOkBtnSlot)
        self.ui.btn_contrast_ratio_cancel.clicked.connect(
            self.__contrastRatioAdjustCancelBtnSlot)

        # 反相按钮槽函数
        self.ui.btn_color_reversal.clicked.connect(self.__colorReversalBtnSlot)

        # 灰度化按钮槽函数
        self.ui.btn_to_gray_image.clicked.connect(self.__toGrayImageBtnSlot)

        # 直方图均衡化槽函数
        self.ui.btn_histogram_equalization.clicked.connect(
            self.__histogramEqualizationBtnSlot)

        # 显示直方图按钮槽函数
        # self.ui.btn_show_histogram.clicked.connect(self.__showHistogramBtnSlot)

        # 平滑操作槽函数
        bindSpinboxAndSlider(self.ui.sb_smoothing_radius,
                             self.ui.hs_smoothing_radius,
                             self.__smoothingPreviewSlot)
        self.ui.radio_smoothing_type_average.clicked.connect(
            self.__smoothingPreviewSlot)
        self.ui.radio_smoothing_type_gaussian.clicked.connect(
            self.__smoothingPreviewSlot)
        self.ui.radio_smoothing_type_median.clicked.connect(
            self.__smoothingPreviewSlot)
        self.ui.btn_smoothing_ok.clicked.connect(self.__smoothingOkBtnSlot)
        self.ui.btn_smoothing_cancel.clicked.connect(
            self.__smoothingCancelBtnSlot)

        # 固定阈值分割槽函数
        bindSpinboxAndSlider(self.ui.sb_fixed_threshold,
                             self.ui.hs_fixed_threshold,
                             self.__fixedThresholdPreviewSlot)
        self.ui.btn_fixed_threshold_ok.clicked.connect(
            self.__fixedThresholdOkBtnSlot)
        self.ui.btn_fixed_threshold_cancel.clicked.connect(
            self.__fixedThresholdCancelBtnSlot)

        # 自适应阈值分割槽函数
        bindSpinboxAndSlider(self.ui.sb_adaptive_threshold_radius,
                             self.ui.hs_adaptive_threshold_radius,
                             self.__adaptiveThresholdPreviewSlot)
        bindSpinboxAndSlider(self.ui.sb_adaptive_threshold_offset,
                             self.ui.hs_adaptive_threshold_offset,
                             self.__adaptiveThresholdPreviewSlot)
        self.ui.radio_adaptive_threshold_type_average.clicked.connect(
            self.__adaptiveThresholdPreviewSlot)
        self.ui.radio_adaptive_threshold_type_gaussian.clicked.connect(
            self.__adaptiveThresholdPreviewSlot)
        self.ui.btn_adaptive_threshold_ok.clicked.connect(
            self.__adaptiveThresholdOkBtnSlot)
        self.ui.btn_adaptive_threshold_cancel.clicked.connect(
            self.__adaptiveThresholdCancelBtnSlot)

        # OTSU阈值分割槽函数
        self.ui.btn_otsu_threshold.clicked.connect(self.__otsuThresholdBtnSlot)

        # 形态学操作槽函数
        bindSpinboxAndSlider(self.ui.sb_morphology_radius,
                             self.ui.hs_morphology_radius,
                             self.__morphologyPreviewSlot)
        self.ui.radio_morphology_type_dilate.clicked.connect(
            self.__morphologyPreviewSlot)
        self.ui.radio_morphology_type_erode.clicked.connect(
            self.__morphologyPreviewSlot)
        self.ui.radio_morphology_type_open.clicked.connect(
            self.__morphologyPreviewSlot)
        self.ui.radio_morphology_type_close.clicked.connect(
            self.__morphologyPreviewSlot)
        self.ui.radio_morphology_shape_rect.clicked.connect(
            self.__morphologyPreviewSlot)
        self.ui.radio_morphology_shape_circle.clicked.connect(
            self.__morphologyPreviewSlot)
        self.ui.radio_morphology_type_cross.clicked.connect(
            self.__morphologyPreviewSlot)
        self.ui.btn_morphology_ok.clicked.connect(self.__morphologyOkBtnSlot)
        self.ui.btn_morphology_cancel.clicked.connect(
            self.__morphologyCancelBtnSlot)

        # 索伯边缘检测槽函数
        self.ui.btn_sobel_edge_detection.clicked.connect(
            self.__sobelEdgeDetectionBtnSlot)

        # 拉普拉斯边缘检测
        self.ui.btn_laplacian_edge_detection.clicked.connect(
            self.__laplacianEdgeDetectionBtnSlot)

        # Canny边缘检测槽函数
        bindSpinboxAndSlider(self.ui.sb_canny_low_threshold,
                             self.ui.hs_canny_low_threshold,
                             self.__cannyEdgePreviewSlot)
        bindSpinboxAndSlider(self.ui.sb_canny_high_threshold,
                             self.ui.hs_canny_high_threshold,
                             self.__cannyEdgePreviewSlot)
        self.ui.btn_canny_edge_detection_ok.clicked.connect(
            self.__cannyEdgeOkBtnSlot)
        self.ui.btn_canny_edge_detection_cancel.clicked.connect(
            self.__cannyEdgeCancelBtnSlot)

        # 轮廓跟踪槽函数
        self.ui.btn_contour_tracing.clicked.connect(self.__contourTracingSlot)

        # 霍夫直线变换槽函数
        self.ui.btn_hough_line_transform.clicked.connect(
            self.__houghLineTransformSlot)

        # Harris特征检测槽函数
        self.ui.btn_harris_feature.clicked.connect(
            self.__harrisFeatureDetectionSlot)

        # FAST特征检测槽函数
        self.ui.btn_fast_feature.clicked.connect(
            self.__fastFeatureDetectionSlot)

        # ORB特征检测槽函数
        self.ui.btn_orb_feature.clicked.connect(self.__orbFeatureDetectionSlot)
Example #15
0
class Widget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.ui = Ui_Widget()
        self.ui.setupUi(self)

        # 成员变量
        self.__menuBtnGroup = QButtonGroup(self)  # 菜单按钮组
        self.__checkedMenuBtn = None  # 当前选中的菜单按钮
        self.__openImgBtn = QPushButton(
            '打开图片', self.ui.widget_center_container)  # 打开图片按钮
        self.__imgFileName = ''  # 图片文件名称
        self.__viewer = ImageViewer()  # 图片查看器
        self.__contrastViewer = ImageViewer()  # 原图查看器
        self.__settings = QSettings()
        self.__imgList = []  # 图片列表
        self.__redoList = []  # 重做列表
        self.__previewImgDict = {  # 预览图片字典
            'brightnessAdjust': np.ndarray([0]),
            'contrastRatioAdjust': np.ndarray([0]),
            'smoothing': np.ndarray([0]),
            'fixedThreshold': np.ndarray([0]),
            'adaptiveThreshold': np.ndarray([0]),
            'morphology': np.ndarray([0]),
            'cannyEdge': np.ndarray([0])
        }
        self.__mousePressFlag = False  # 鼠标左键是否被按下
        self.__mousePressPos = QPoint()  # 鼠标按下位置
        self.__fixedThresholdActiveFlag = False  # 固定阈值分割激活标志
        self.__cannyEdgeActiveFlag = False  # Canny边缘检测激活标志

        # 程序名称和图标
        self.setWindowTitle("图像实践")
        self.setWindowIcon(QIcon(':/image/app_icon.png'))

        # 自动填充背景色
        self.ui.widget_bg.setAutoFillBackground(True)

        # 无边框窗口
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground)

        # widget_center阴影
        self.shadow = QGraphicsDropShadowEffect(self)
        self.shadow.setOffset(0, 0)
        self.shadow.setColor(QColor('#666666'))
        self.shadow.setBlurRadius(30)
        self.ui.widget_center_container.setGraphicsEffect(self.shadow)
        self.shadow.setEnabled(False)  # 禁用阴影

        # 禁止widget_center将鼠标事件传到父级
        self.ui.widget_center.setAttribute(Qt.WA_NoMousePropagation)

        # 设置widget_imageviewer_container布局
        imageviewerContainerLayout = QHBoxLayout(
            self.ui.widget_imageviewer_container)
        imageviewerContainerLayout.addWidget(self.__contrastViewer)
        imageviewerContainerLayout.addWidget(self.__viewer)

        # 设置控件样式
        self.ui.widget_center.setProperty('form', 'widget_center')
        self.ui.widget_tool.setProperty('form', 'widget_tool')
        self.ui.btn_min.setProperty('form', 'btn_min')  # 窗口操作按钮
        self.ui.btn_max.setProperty('form', 'btn_max')
        self.ui.btn_close.setProperty('form', 'btn_close')
        self.__openImgBtn.setProperty('form', 'btn_open_img')  # 打开图片按钮
        self.__openImgBtn.setFixedSize(350, 50)
        self.ui.btn_save.setProperty('form', 'btn_save')  # 保存按钮
        self.ui.btn_brightness_ok.setProperty('form', 'btn_dark')  # 工具栏按钮
        self.ui.btn_undo.setProperty('form', 'btn_undo')  # 撤销重做按钮
        self.ui.btn_redo.setProperty('form', 'btn_redo')
        self.ui.btn_zoomin.setProperty('form', 'btn_zoomin')  # 图片操作按钮
        self.ui.btn_zoomout.setProperty('form', 'btn_zoomout')
        self.ui.btn_fit_display.setProperty('form', 'btn_fit_display')
        self.ui.btn_rotate.setProperty('form', 'btn_rotate')
        self.ui.btn_contrast.setProperty('form', 'btn_contrast')
        self.ui.btn_brightness_cancel.setProperty('form', 'btn_light')  # 基本页面
        self.ui.btn_contrast_ratio_ok.setProperty('form', 'btn_dark')
        self.ui.btn_contrast_ratio_cancel.setProperty('form', 'btn_light')
        self.ui.btn_color_reversal.setProperty('form', 'btn_dark_big')
        self.ui.btn_to_gray_image.setProperty('form', 'btn_dark_big')
        self.ui.btn_histogram_equalization.setProperty('form', 'btn_dark_big')
        # self.ui.btn_show_histogram.setProperty('form', 'btn_light_big')
        self.ui.btn_smoothing_cancel.setProperty('form', 'btn_light')  # 平滑页面
        self.ui.btn_smoothing_ok.setProperty('form', 'btn_dark')
        self.ui.lbl_fixed_threshold_title.setProperty(
            'form', 'lbl_title_small')  # 分割页面
        self.ui.btn_fixed_threshold_cancel.setProperty('form', 'btn_light')
        self.ui.btn_fixed_threshold_ok.setProperty('form', 'btn_dark')
        self.ui.lbl_adaptive_threshold_title.setProperty(
            'form', 'lbl_title_small')
        self.ui.btn_adaptive_threshold_cancel.setProperty('form', 'btn_light')
        self.ui.btn_adaptive_threshold_ok.setProperty('form', 'btn_dark')
        self.ui.lbl_otsu_threshold_title.setProperty('form', 'lbl_title_small')
        self.ui.btn_otsu_threshold.setProperty('form', 'btn_dark_big')
        self.ui.btn_morphology_cancel.setProperty('form', 'btn_light')
        self.ui.btn_morphology_ok.setProperty('form', 'btn_dark')
        self.ui.lbl_sobel_edge_detection.setProperty(
            'form', 'lbl_title_small')  # 边缘检测页面
        self.ui.btn_sobel_edge_detection.setProperty('form', 'btn_dark_big')
        self.ui.lbl_laplacian_edge_detection.setProperty(
            'form', 'lbl_title_small')
        self.ui.btn_laplacian_edge_detection.setProperty(
            'form', 'btn_dark_big')
        self.ui.lbl_canny_edge_detection.setProperty('form', 'lbl_title_small')
        self.ui.btn_canny_edge_detection_cancel.setProperty(
            'form', 'btn_light')
        self.ui.btn_canny_edge_detection_ok.setProperty('form', 'btn_dark')
        self.ui.lbl_contour_feature_title.setProperty(
            'form', 'lbl_title_small')  # 特征提取页面
        self.ui.btn_contour_tracing.setProperty('form', 'btn_dark_big')
        self.ui.lbl_shape_feature_title.setProperty('form', 'lbl_title_small')
        self.ui.btn_hough_line_transform.setProperty('form', 'btn_dark_big')
        self.ui.lbl_point_feature_title.setProperty('form', 'lbl_title_small')
        self.ui.btn_harris_feature.setProperty('form', 'btn_dark_big')
        self.ui.btn_fast_feature.setProperty('form', 'btn_dark_big')
        self.ui.btn_orb_feature.setProperty('form', 'btn_dark_big')

        # 菜单按钮组
        self.__menuBtnGroup.setExclusive(False)
        for btn in self.ui.widget_menu.findChildren(QPushButton):
            btn.setProperty('form', 'btn_menu')
            self.__menuBtnGroup.addButton(btn)
            btn.clicked.connect(self.__menuBtnSlot)

        # 设置鼠标悬停提示
        self.ui.btn_save.setToolTip('Ctrl+S')
        self.ui.btn_undo.setToolTip('Ctrl+Z')
        self.ui.btn_redo.setToolTip('Ctrl+R')

        # 初始化窗口状态
        self.__openImgBtn.lower()
        self.ui.widget_center.move(0, 10e4)
        self.ui.widget_tool.hide()
        self.ui.widget_menu.setDisabled(True)
        self.ui.btn_save.setDisabled(True)
        self.__contrastViewer.hide()
        self.ui.btn_undo.setDisabled(True)
        self.ui.btn_redo.setDisabled(True)

        # 最小化按钮槽函数
        self.ui.btn_min.clicked.connect(self.__minBtnSlot)

        # 最大化按钮槽函数
        self.ui.btn_max.clicked.connect(self.__maxBtnSlot)

        # 关闭按钮槽函数
        self.ui.btn_close.clicked.connect(self.__closeBtnSlot)

        # 打开图片按钮槽函数
        self.__openImgBtn.clicked.connect(self.__openImgBtnSlot)

        # 保存按钮槽函数
        self.ui.btn_save.clicked.connect(self.__saveBtnSlot)

        # 撤销按钮槽函数
        self.ui.btn_undo.clicked.connect(self.__undoBtnSlot)

        # 重做按钮槽函数
        self.ui.btn_redo.clicked.connect(self.__redoBtnSlot)

        # 缩小按钮槽函数
        self.ui.btn_zoomout.clicked.connect(
            lambda: self.__viewer.animatedZoom(self.__viewer.propScale / 2))

        # 放大按钮槽函数
        self.ui.btn_zoomin.clicked.connect(
            lambda: self.__viewer.animatedZoom(self.__viewer.propScale * 2))

        # 适应显示按钮槽函数
        self.ui.btn_fit_display.clicked.connect(self.__fitDisplayBtnSlot)

        # 旋转按钮槽函数
        self.ui.btn_rotate.clicked.connect(self.__rotateBtnSlot)

        # 对比按钮槽函数
        self.ui.btn_contrast.clicked.connect(self.__contrastBtnSlot)

        # 亮度调节槽函数
        bindSpinboxAndSlider(self.ui.sb_brightness, self.ui.hs_brightness,
                             self.__brightnessAdjustPreviewSlot)
        self.ui.btn_brightness_ok.clicked.connect(
            self.__brightnessAdjustOkBtnSlot)
        self.ui.btn_brightness_cancel.clicked.connect(
            self.__brightnessAdjustCancelBtnSlot)

        # 对比度调节槽函数
        bindSpinboxAndSlider(self.ui.sb_contrast_ratio,
                             self.ui.hs_contrast_ratio,
                             self.__contrastRatioAdjustPreviewSlot)
        self.ui.btn_contrast_ratio_ok.clicked.connect(
            self.__contrastRatioAdjustOkBtnSlot)
        self.ui.btn_contrast_ratio_cancel.clicked.connect(
            self.__contrastRatioAdjustCancelBtnSlot)

        # 反相按钮槽函数
        self.ui.btn_color_reversal.clicked.connect(self.__colorReversalBtnSlot)

        # 灰度化按钮槽函数
        self.ui.btn_to_gray_image.clicked.connect(self.__toGrayImageBtnSlot)

        # 直方图均衡化槽函数
        self.ui.btn_histogram_equalization.clicked.connect(
            self.__histogramEqualizationBtnSlot)

        # 显示直方图按钮槽函数
        # self.ui.btn_show_histogram.clicked.connect(self.__showHistogramBtnSlot)

        # 平滑操作槽函数
        bindSpinboxAndSlider(self.ui.sb_smoothing_radius,
                             self.ui.hs_smoothing_radius,
                             self.__smoothingPreviewSlot)
        self.ui.radio_smoothing_type_average.clicked.connect(
            self.__smoothingPreviewSlot)
        self.ui.radio_smoothing_type_gaussian.clicked.connect(
            self.__smoothingPreviewSlot)
        self.ui.radio_smoothing_type_median.clicked.connect(
            self.__smoothingPreviewSlot)
        self.ui.btn_smoothing_ok.clicked.connect(self.__smoothingOkBtnSlot)
        self.ui.btn_smoothing_cancel.clicked.connect(
            self.__smoothingCancelBtnSlot)

        # 固定阈值分割槽函数
        bindSpinboxAndSlider(self.ui.sb_fixed_threshold,
                             self.ui.hs_fixed_threshold,
                             self.__fixedThresholdPreviewSlot)
        self.ui.btn_fixed_threshold_ok.clicked.connect(
            self.__fixedThresholdOkBtnSlot)
        self.ui.btn_fixed_threshold_cancel.clicked.connect(
            self.__fixedThresholdCancelBtnSlot)

        # 自适应阈值分割槽函数
        bindSpinboxAndSlider(self.ui.sb_adaptive_threshold_radius,
                             self.ui.hs_adaptive_threshold_radius,
                             self.__adaptiveThresholdPreviewSlot)
        bindSpinboxAndSlider(self.ui.sb_adaptive_threshold_offset,
                             self.ui.hs_adaptive_threshold_offset,
                             self.__adaptiveThresholdPreviewSlot)
        self.ui.radio_adaptive_threshold_type_average.clicked.connect(
            self.__adaptiveThresholdPreviewSlot)
        self.ui.radio_adaptive_threshold_type_gaussian.clicked.connect(
            self.__adaptiveThresholdPreviewSlot)
        self.ui.btn_adaptive_threshold_ok.clicked.connect(
            self.__adaptiveThresholdOkBtnSlot)
        self.ui.btn_adaptive_threshold_cancel.clicked.connect(
            self.__adaptiveThresholdCancelBtnSlot)

        # OTSU阈值分割槽函数
        self.ui.btn_otsu_threshold.clicked.connect(self.__otsuThresholdBtnSlot)

        # 形态学操作槽函数
        bindSpinboxAndSlider(self.ui.sb_morphology_radius,
                             self.ui.hs_morphology_radius,
                             self.__morphologyPreviewSlot)
        self.ui.radio_morphology_type_dilate.clicked.connect(
            self.__morphologyPreviewSlot)
        self.ui.radio_morphology_type_erode.clicked.connect(
            self.__morphologyPreviewSlot)
        self.ui.radio_morphology_type_open.clicked.connect(
            self.__morphologyPreviewSlot)
        self.ui.radio_morphology_type_close.clicked.connect(
            self.__morphologyPreviewSlot)
        self.ui.radio_morphology_shape_rect.clicked.connect(
            self.__morphologyPreviewSlot)
        self.ui.radio_morphology_shape_circle.clicked.connect(
            self.__morphologyPreviewSlot)
        self.ui.radio_morphology_type_cross.clicked.connect(
            self.__morphologyPreviewSlot)
        self.ui.btn_morphology_ok.clicked.connect(self.__morphologyOkBtnSlot)
        self.ui.btn_morphology_cancel.clicked.connect(
            self.__morphologyCancelBtnSlot)

        # 索伯边缘检测槽函数
        self.ui.btn_sobel_edge_detection.clicked.connect(
            self.__sobelEdgeDetectionBtnSlot)

        # 拉普拉斯边缘检测
        self.ui.btn_laplacian_edge_detection.clicked.connect(
            self.__laplacianEdgeDetectionBtnSlot)

        # Canny边缘检测槽函数
        bindSpinboxAndSlider(self.ui.sb_canny_low_threshold,
                             self.ui.hs_canny_low_threshold,
                             self.__cannyEdgePreviewSlot)
        bindSpinboxAndSlider(self.ui.sb_canny_high_threshold,
                             self.ui.hs_canny_high_threshold,
                             self.__cannyEdgePreviewSlot)
        self.ui.btn_canny_edge_detection_ok.clicked.connect(
            self.__cannyEdgeOkBtnSlot)
        self.ui.btn_canny_edge_detection_cancel.clicked.connect(
            self.__cannyEdgeCancelBtnSlot)

        # 轮廓跟踪槽函数
        self.ui.btn_contour_tracing.clicked.connect(self.__contourTracingSlot)

        # 霍夫直线变换槽函数
        self.ui.btn_hough_line_transform.clicked.connect(
            self.__houghLineTransformSlot)

        # Harris特征检测槽函数
        self.ui.btn_harris_feature.clicked.connect(
            self.__harrisFeatureDetectionSlot)

        # FAST特征检测槽函数
        self.ui.btn_fast_feature.clicked.connect(
            self.__fastFeatureDetectionSlot)

        # ORB特征检测槽函数
        self.ui.btn_orb_feature.clicked.connect(self.__orbFeatureDetectionSlot)

    # 重写绘图函数
    def paintEvent(self, event):
        # 绘制窗体阴影
        shadow_margin = 15
        shadow_pixmap = QPixmap('://image/mainWnd_shadow.png')
        painter = QPainter(self)
        pngTop = QRect(shadow_margin, 0,
                       shadow_pixmap.width() - shadow_margin * 2,
                       shadow_margin)
        winTop = QRect(shadow_margin, 0,
                       self.width() - shadow_margin * 2, shadow_margin)
        painter.drawPixmap(winTop, shadow_pixmap, pngTop)
        pngBottom = QRect(shadow_margin,
                          shadow_pixmap.height() - shadow_margin,
                          shadow_pixmap.width() - shadow_margin * 2,
                          shadow_margin)
        winBottom = QRect(shadow_margin,
                          self.height() - shadow_margin,
                          self.width() - shadow_margin * 2, shadow_margin)
        painter.drawPixmap(winBottom, shadow_pixmap, pngBottom)
        pngLeft = QRect(0, shadow_margin, shadow_margin,
                        shadow_pixmap.height() - shadow_margin * 2)
        winLeft = QRect(0, shadow_margin, shadow_margin,
                        self.height() - shadow_margin * 2)
        painter.drawPixmap(winLeft, shadow_pixmap, pngLeft)
        pngRight = QRect(shadow_pixmap.width() - shadow_margin, shadow_margin,
                         shadow_margin,
                         shadow_pixmap.height() - shadow_margin * 2)
        winRight = QRect(self.width() - shadow_margin, shadow_margin,
                         shadow_margin,
                         self.height() - shadow_margin * 2)
        painter.drawPixmap(winRight, shadow_pixmap, pngRight)
        pngLeftTop = QRect(0, 0, shadow_margin, shadow_margin)
        winLeftTop = QRect(0, 0, shadow_margin, shadow_margin)
        painter.drawPixmap(winLeftTop, shadow_pixmap, pngLeftTop)
        pngRightTop = QRect(shadow_pixmap.width() - shadow_margin, 0,
                            shadow_margin, shadow_margin)
        winRightTop = QRect(self.width() - shadow_margin, 0, shadow_margin,
                            shadow_margin)
        painter.drawPixmap(winRightTop, shadow_pixmap, pngRightTop)
        pngLeftBottom = QRect(0,
                              shadow_pixmap.height() - shadow_margin,
                              shadow_margin, shadow_margin)
        winLeftBottom = QRect(0,
                              self.height() - shadow_margin, shadow_margin,
                              shadow_margin)
        painter.drawPixmap(winLeftBottom, shadow_pixmap, pngLeftBottom)
        pngRightBottom = QRect(shadow_pixmap.width() - shadow_margin,
                               shadow_pixmap.height() - shadow_margin,
                               shadow_margin, shadow_margin)
        winRightBottom = QRect(self.width() - shadow_margin,
                               self.height() - shadow_margin, shadow_margin,
                               shadow_margin)
        painter.drawPixmap(winRightBottom, shadow_pixmap, pngRightBottom)

    # 重写改变窗口大小事件
    def resizeEvent(self, event):
        # 使用背景图片
        # palette = QPalette()
        # bgImg = QPixmap(':/image/background.jpg').scaled(self.ui.widget_bg.width(), self.ui.widget_bg.height())
        # palette.setBrush(self.backgroundRole(), QBrush(bgImg))
        # self.ui.widget_bg.setPalette(palette)

        # 使用纯色背景
        self.ui.widget_bg.setPalette(QPalette(QColor(43, 87, 154)))

        # 计算widget_center_container大小
        ownerSize = QSize(
            self.ui.widget_bg.width(),
            self.ui.widget_bg.height() - self.ui.widget_title.minimumHeight())

        # 调整打开图片按钮位置
        self.__openImgBtn.move(
            (ownerSize.width() - self.__openImgBtn.width()) / 2,
            (ownerSize.height() - self.__openImgBtn.height()) / 2)

        # 调整CenterWidget的大小
        self.ui.widget_center.setFixedSize(ownerSize)

    # 重写鼠标按下事件
    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.__mousePressFlag = True
            self.__mousePressPos = event.pos()

    # 重写鼠标释放事件
    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.__mousePressFlag = False

    # 重写鼠标移动事件
    def mouseMoveEvent(self, event):
        if self.__mousePressFlag and not self.isMaximized():
            self.move(self.pos() + event.pos() - self.__mousePressPos)

    # 重写鼠标双击事件
    def mouseDoubleClickEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.ui.btn_max.clicked.emit()

    # 重写键盘按下事件
    def keyPressEvent(self, event):
        if event.modifiers() == Qt.ControlModifier:
            if event.key() == Qt.Key_S and not self.__openImgBtn.isEnabled():
                self.__saveBtnSlot()
            if event.key() == Qt.Key_Z and self.ui.btn_undo.isEnabled():
                self.__undoBtnSlot()
            if event.key() == Qt.Key_R and self.ui.btn_redo.isEnabled():
                self.__redoBtnSlot()

    # 最小化按钮槽函数
    def __minBtnSlot(self):
        self.showMinimized()

    # 最大化按钮槽函数
    def __maxBtnSlot(self):
        if not self.isMaximized():  # 切换至全屏状态
            self.layout().setContentsMargins(0, 0, 0, 0)
            self.showMaximized()
            self.ui.btn_max.setProperty('form', 'btn_max_back')
        else:  # 切换为窗口状态
            self.layout().setContentsMargins(15, 15, 15, 15)
            self.showNormal()
            self.ui.btn_max.setProperty('form', 'btn_max')

        self.style().polish(self.ui.btn_max)

    # 关闭按钮槽函数
    def __closeBtnSlot(self):
        self.close()

    # 菜单按钮槽函数
    def __menuBtnSlot(self):
        menu = self.sender().objectName()
        if self.__checkedMenuBtn is not None and menu == self.__checkedMenuBtn.objectName(
        ):
            self.ui.widget_tool.hide()
            self.__checkedMenuBtn = None
        else:
            # 切换page
            if menu == 'btn_menu_basic':
                self.ui.widget_tool.setCurrentWidget(self.ui.page_basic)
            elif menu == 'btn_menu_smoothing':
                self.ui.widget_tool.setCurrentWidget(self.ui.page_smoothing)
            elif menu == 'btn_menu_segmentation':
                self.ui.widget_tool.setCurrentWidget(self.ui.page_segmentation)
            elif menu == 'btn_menu_morphology':
                self.ui.widget_tool.setCurrentWidget(self.ui.page_morphology)
            elif menu == 'btn_menu_edge_detection':
                self.ui.widget_tool.setCurrentWidget(
                    self.ui.page_edge_detection)
            elif menu == 'btn_menu_feature_extraction':
                self.ui.widget_tool.setCurrentWidget(self.ui.page_feature)

            if self.__checkedMenuBtn is None:
                self.ui.widget_tool.show()
            else:
                self.__checkedMenuBtn.setChecked(False)
            self.__checkedMenuBtn = self.sender()

    # 打开图片按钮槽函数
    def __openImgBtnSlot(self):
        # 防止多次点击
        self.__openImgBtn.setDisabled(True)

        # 获取桌面路径
        openDir = QStandardPaths.writableLocation(
            QStandardPaths.DesktopLocation)

        # 从QSetting中读取路径
        if self.__settings.contains('openDir'):
            openDir = self.__settings.value('openDir')

        # 打开文件选择对话框
        path, _ = QFileDialog.getOpenFileName(
            self, '选择图片', openDir,
            '图片 (*.jpg *.png *.bmp *.jpe *.jpeg *.webp *.tif *.tiff)')
        if path == '':
            return

        # 路径保存至QSetting 文件名保存至__imgFileName
        self.__settings.setValue('openDir', path[:str.rindex(path, '/')])
        self.__imgFileName = path[str.rindex(path, '/') + 1:]

        # 读取图片并添加到图片列表
        self.__imgList.append(cv.imdecode(np.fromfile(path, dtype=np.uint8),
                                          1))

        # 显示图片
        self.__viewer.loadImage(self.__imgList[0])
        self.__contrastViewer.loadImage(self.__imgList[0])

        # 弹出中心窗体
        self.__popCenterWidget()

    # 保存按钮槽函数
    def __saveBtnSlot(self):
        # 获取保存路径
        openDir = QStandardPaths.writableLocation(
            QStandardPaths.DesktopLocation)
        if self.__settings.contains('openDir'):
            openDir = self.__settings.value(
                'openDir') + '/' + self.__imgFileName
        path, _ = QFileDialog.getSaveFileName(
            self, '保存', openDir,
            '图片 (*.jpg *.png *.bmp *.jpe *.jpeg *.webp *.tif *.tiff)')
        if path == '':
            return

        # 将本次打开目录存入settings
        self.__settings.setValue('openDir', path[:str.rindex(path, '/')])

        # 保存图片
        cv.imwrite(path, self.__imgList[-1])

    # 撤销按钮槽函数
    def __undoBtnSlot(self):
        self.__redoList.append(self.__imgList.pop())
        self.__viewer.changeImage(self.__imgList[-1])

        if len(self.__imgList) == 1:
            self.ui.btn_undo.setDisabled(True)

        self.ui.btn_redo.setEnabled(True)

    # 重做按钮槽函数
    def __redoBtnSlot(self):
        self.__imgList.append(self.__redoList.pop())
        self.__viewer.changeImage(self.__imgList[-1])

        if len(self.__redoList) == 0:
            self.ui.btn_redo.setDisabled(True)

        self.ui.btn_undo.setEnabled(True)

    # 适应显示按钮槽函数
    def __fitDisplayBtnSlot(self):
        self.__viewer.fitDisplay()
        self.__contrastViewer.fitDisplay()

    # 旋转按钮槽函数
    def __rotateBtnSlot(self):
        self.__viewer.rotateImage()
        self.__contrastViewer.rotateImage()

    # 对比按钮槽函数
    def __contrastBtnSlot(self, b):
        if b:
            self.__contrastViewer.show()
        else:
            self.__contrastViewer.hide()

    # 亮度调节预览槽函数
    def __brightnessAdjustPreviewSlot(self, value):
        self.__previewImgDict['brightnessAdjust'] = adjustBrightness(
            self.__imgList[-1], value)
        self.__viewer.changeImage(self.__previewImgDict['brightnessAdjust'])

    # 亮度调节确定按钮槽函数
    # 说明:"确定"按钮的作用是将该功能的预览图片追加到图片列表中, 如果该功能当前的参数控件为默认值则不追加
    def __brightnessAdjustOkBtnSlot(self):
        if not self.ui.hs_brightness.value() == 0:
            self.__appendImg(self.__previewImgDict['brightnessAdjust'])

            # 恢复参数控件的值
            self.ui.hs_brightness.setValue(0)

    # 亮度调节取消按钮槽函数
    def __brightnessAdjustCancelBtnSlot(self):
        # 重置预览图片
        self.__previewImgDict['brightnessAdjust'] = self.__imgList[-1]

        # 恢复参数控件的值(预览图片会刷新显示)
        self.ui.hs_brightness.setValue(0)

    # 对比度调节预览槽函数
    def __contrastRatioAdjustPreviewSlot(self, value):
        self.__previewImgDict['contrastRatioAdjust'] = adjustContrastRatio(
            self.__imgList[-1], np.tan(value * np.pi / 180))  # value为映射函数倾斜角
        self.__viewer.changeImage(self.__previewImgDict['contrastRatioAdjust'])

    # 对比度调节确定按钮槽函数
    def __contrastRatioAdjustOkBtnSlot(self):
        if not self.ui.hs_contrast_ratio.value() == 45:
            self.__appendImg(self.__previewImgDict['contrastRatioAdjust'])

            # 恢复参数控件的值
            self.ui.hs_contrast_ratio.setValue(45)

    # 对比度调节取消按钮槽函数
    def __contrastRatioAdjustCancelBtnSlot(self):
        # 重置预览图片
        self.__previewImgDict['contrastRatioAdjust'] = self.__imgList[-1]

        # 恢复参数控件的值(预览图片会刷新显示)
        self.ui.hs_contrast_ratio.setValue(45)

    # 反相按钮槽函数
    def __colorReversalBtnSlot(self):
        self.__appendImg(colorReversal(self.__imgList[-1]))

    # 灰度化按钮槽函数
    def __toGrayImageBtnSlot(self):
        # 如果已经是灰度图 则直接返回
        if self.__imgList[-1].ndim == 2:
            MessageDialog(self, '当前已经是灰度图像')
            return

        self.__appendImg(cv.cvtColor(self.__imgList[-1], cv.COLOR_BGR2GRAY))

    # 直方图均衡化槽函数
    def __histogramEqualizationBtnSlot(self):
        # 如果当前不是灰度图 则直接返回
        if not self.__imgList[-1].ndim == 2:
            MessageDialog(self, '需要先进行灰度化')
            return

        self.__appendImg(histogramEqualization(self.__imgList[-1]))

    # 显示直方图按钮槽函数
    # def __showHistogramBtnSlot(self):
    #     print('待写')

    # 平滑预览槽函数
    def __smoothingPreviewSlot(self):
        radius = self.ui.hs_smoothing_radius.value()
        if self.ui.radio_smoothing_type_average.isChecked():
            self.__previewImgDict['smoothing'] = averageSmoothing(
                self.__imgList[-1], radius)
        elif self.ui.radio_smoothing_type_gaussian.isChecked():
            self.__previewImgDict['smoothing'] = gaussianSmoothing(
                self.__imgList[-1], radius)
        else:
            self.__previewImgDict['smoothing'] = medianSmoothing(
                self.__imgList[-1], radius)

        self.__viewer.changeImage(self.__previewImgDict['smoothing'])

    # 平滑确定按钮槽函数
    def __smoothingOkBtnSlot(self):
        if not self.ui.hs_smoothing_radius.value() == 0:
            self.__appendImg(self.__previewImgDict['smoothing'])

            # 恢复参数控件的值
            self.ui.hs_smoothing_radius.setValue(0)

    # 平滑取消按钮槽函数
    def __smoothingCancelBtnSlot(self):
        # 重置预览图片
        self.__previewImgDict['smoothing'] = self.__imgList[-1]

        # 恢复参数控件的值(预览图片会刷新显示)
        self.ui.hs_smoothing_radius.setValue(0)

    # 固定阈值分割预览函数
    def __fixedThresholdPreviewSlot(self, threshold):
        # 如果当前不是灰度图 则直接返回
        if not self.__imgList[-1].ndim == 2:
            MessageDialog(self, '需要先在「基本」菜单中进行灰度化')
            self.ui.hs_fixed_threshold.setValue(127)
            return

        self.__previewImgDict['fixedThreshold'] = fixedThresholdSegmentation(
            self.__imgList[-1], threshold)
        self.__viewer.changeImage(self.__previewImgDict['fixedThreshold'])
        self.__fixedThresholdActiveFlag = True  # 置为激活状态

    # 固定阈值分割确定按钮槽函数
    def __fixedThresholdOkBtnSlot(self):
        if self.__fixedThresholdActiveFlag:
            self.__appendImg(self.__previewImgDict['fixedThreshold'])

            # 恢复参数控件的值
            self.ui.hs_fixed_threshold.setValue(127)

            # 置为非激活状态
            self.__fixedThresholdActiveFlag = False

    # 固定阈值分割取消按钮槽函数
    def __fixedThresholdCancelBtnSlot(self):
        # 重置预览图片
        self.__previewImgDict['fixedThreshold'] = self.__imgList[-1]

        # 恢复参数控件的值(预览图片会刷新显示)
        self.ui.hs_fixed_threshold.setValue(127)

        # 置为非激活状态
        self.__fixedThresholdActiveFlag = False

        # 再次主动刷新显示
        self.__viewer.changeImage(self.__imgList[-1])

    # 自适应阈值分割预览函数
    def __adaptiveThresholdPreviewSlot(self):
        # 如果当前不是灰度图 则直接返回
        if not self.__imgList[-1].ndim == 2:
            MessageDialog(self, '需要先在「基本」菜单中进行灰度化')
            self.ui.hs_adaptive_threshold_radius.setValue(0)
            self.ui.hs_adaptive_threshold_offset.setValue(0)
            return

        if self.ui.radio_adaptive_threshold_type_average.isChecked():
            method = 'mean'
        else:
            method = 'gaussian'
        radius = self.ui.hs_adaptive_threshold_radius.value()
        offset = self.ui.hs_adaptive_threshold_offset.value()

        if radius == 0:
            self.__previewImgDict['adaptiveThreshold'] = self.__imgList[-1]
        else:
            self.__previewImgDict[
                'adaptiveThreshold'] = adaptiveThresholdSegmentation(
                    self.__imgList[-1], method, radius, offset)
        self.__viewer.changeImage(self.__previewImgDict['adaptiveThreshold'])

    # 自适应阈值分割确定按钮槽函数
    def __adaptiveThresholdOkBtnSlot(self):
        if not self.ui.hs_adaptive_threshold_radius.value() == 0:
            self.__appendImg(self.__previewImgDict['adaptiveThreshold'])

            # 恢复参数控件的值
            self.ui.hs_adaptive_threshold_radius.setValue(0)
            self.ui.hs_adaptive_threshold_offset.setValue(0)

    # 自适应阈值分割取消按钮槽函数
    def __adaptiveThresholdCancelBtnSlot(self):
        # 重置预览图片
        self.__previewImgDict['adaptiveThreshold'] = self.__imgList[-1]

        # 恢复参数控件的值(预览图片会刷新显示)
        self.ui.hs_adaptive_threshold_radius.setValue(0)
        self.ui.hs_adaptive_threshold_offset.setValue(0)

    # OTSU阈值分割槽函数
    def __otsuThresholdBtnSlot(self):
        # 如果当前不是灰度图 则直接返回
        if not self.__imgList[-1].ndim == 2:
            MessageDialog(self, '需要先在「基本」菜单中进行灰度化')
            return

        self.__appendImg(otsuThresholdSegmentation(self.__imgList[-1]))

    # 形态学预览按钮槽函数
    def __morphologyPreviewSlot(self):
        # 如果当前不是二值图像 则直接返回
        if not isBinaryImage(self.__imgList[-1]):
            MessageDialog(self, '需要先在「分割」菜单中进行二值化')
            self.ui.hs_morphology_radius.setValue(0)
            return

        if self.ui.radio_morphology_shape_rect.isChecked():
            shape = 'rect'
        elif self.ui.radio_morphology_shape_circle.isChecked():
            shape = 'circle'
        else:
            shape = 'cross'
        radius = self.ui.hs_morphology_radius.value()

        if self.ui.radio_morphology_type_dilate.isChecked():
            self.__previewImgDict['morphology'] = dilateOperation(
                self.__imgList[-1], shape, radius)
        elif self.ui.radio_morphology_type_erode.isChecked():
            self.__previewImgDict['morphology'] = erodeOperation(
                self.__imgList[-1], shape, radius)
        elif self.ui.radio_morphology_type_open.isChecked():
            self.__previewImgDict['morphology'] = openOperation(
                self.__imgList[-1], shape, radius)
        else:
            self.__previewImgDict['morphology'] = closeOperation(
                self.__imgList[-1], shape, radius)

        self.__viewer.changeImage(self.__previewImgDict['morphology'])

    # 形态学确定按钮槽函数
    def __morphologyOkBtnSlot(self):
        if not self.ui.hs_morphology_radius.value() == 0:
            self.__appendImg(self.__previewImgDict['morphology'])

            # 恢复参数控件的值
            self.ui.hs_morphology_radius.setValue(0)

    # 形态学取消按钮槽函数
    def __morphologyCancelBtnSlot(self):
        # 重置预览图片
        self.__previewImgDict['morphology'] = self.__imgList[-1]

        # 恢复参数控件的值(预览图片会刷新显示)
        self.ui.hs_morphology_radius.setValue(0)

    # 索伯边缘检测槽函数
    def __sobelEdgeDetectionBtnSlot(self):
        # 如果当前不是灰度图 则直接返回
        if not self.__imgList[-1].ndim == 2:
            MessageDialog(self, '需要先在「基本」菜单中进行灰度化')
            return

        if self.ui.radio_sobel_edge_detection_axis_x.isChecked():
            axis = 'x'
        else:
            axis = 'y'
        if self.ui.radio_sobel_edge_detection_radius_1.isChecked():
            radius = 1
        elif self.ui.radio_sobel_edge_detection_radius_2.isChecked():
            radius = 2
        else:
            radius = 3

        self.__appendImg(sobelEdgeDetection(self.__imgList[-1], axis, radius))

    # 拉普拉斯边缘检测槽函数
    def __laplacianEdgeDetectionBtnSlot(self):
        # 如果当前不是灰度图 则直接返回
        if not self.__imgList[-1].ndim == 2:
            MessageDialog(self, '需要先在「基本」菜单中进行灰度化')
            return

        if self.ui.radio_laplacian_edge_detection_type_4.isChecked():
            neighbourhood = 4
        else:
            neighbourhood = 8

        self.__appendImg(
            laplacianEdgeDetection(self.__imgList[-1], neighbourhood))

    # Canny边缘检测预览按钮槽函数
    def __cannyEdgePreviewSlot(self):
        # 如果当前不是灰度图 则直接返回
        if not self.__imgList[-1].ndim == 2:
            MessageDialog(self, '需要先在「基本」菜单中进行灰度化')
            self.ui.hs_canny_low_threshold.setValue(100)
            self.ui.hs_canny_high_threshold.setValue(200)
            return

        lowThreshold = self.ui.hs_canny_low_threshold.value()
        highThreshold = self.ui.hs_canny_high_threshold.value()

        self.__previewImgDict['cannyEdge'] = cannyEdgeDetection(
            self.__imgList[-1], lowThreshold, highThreshold)
        self.__viewer.changeImage(self.__previewImgDict['cannyEdge'])
        self.__cannyEdgeActiveFlag = True  # 置为激活状态

    # Canny边缘检测确定按钮槽函数
    def __cannyEdgeOkBtnSlot(self):
        if self.__cannyEdgeActiveFlag:
            self.__appendImg(self.__previewImgDict['cannyEdge'])

            # 恢复参数控件的值
            self.ui.hs_canny_low_threshold.setValue(100)
            self.ui.hs_canny_high_threshold.setValue(200)

            # 置为非激活状态
            self.__cannyEdgeActiveFlag = False

            # 再次主动刷新显示(因为滑杆恢复导致预览函数再次对图像进行Canny边缘检测)
            self.__viewer.changeImage(self.__imgList[-1])

    # Canny边缘检测取消按钮槽函数
    def __cannyEdgeCancelBtnSlot(self):
        # 重置预览图片
        self.__previewImgDict['cannyEdge'] = self.__imgList[-1]

        # 恢复参数控件的值(预览图片会刷新显示)
        self.ui.hs_canny_low_threshold.setValue(100)
        self.ui.hs_canny_high_threshold.setValue(200)

        # 置为非激活状态
        self.__cannyEdgeActiveFlag = False

        # 再次主动刷新显示
        self.__viewer.changeImage(self.__imgList[-1])

    # 轮廓跟踪槽函数
    def __contourTracingSlot(self):
        # 如果当前不是二值图像 则直接返回
        if not isBinaryImage(self.__imgList[-1]):
            MessageDialog(self, '需要先在「分割」菜单中进行二值化')
            return

        self.__appendImg(contourTracing(self.__imgList[-1]))

    # 霍夫直线变换槽函数
    def __houghLineTransformSlot(self):
        # 如果当前不是二值图像 则直接返回
        if not isBinaryImage(self.__imgList[-1]):
            MessageDialog(self, '需要先在「分割」菜单中进行二值化')
            return

        newImg, flag = houghLineTransform(self.__imgList[-1])
        if flag:
            self.__appendImg(newImg)
        else:
            MessageDialog(self, '未检测到直线')

    # Harris特征检测槽函数
    def __harrisFeatureDetectionSlot(self):
        # 如果当前不是灰度图 则直接返回
        if not self.__imgList[-1].ndim == 2:
            MessageDialog(self, '需要先在「基本」菜单中进行灰度化')
            return

        self.__appendImg(harrisFeatureDetection(self.__imgList[-1]))

    # FAST特征检测槽函数
    def __fastFeatureDetectionSlot(self):
        # 如果当前不是灰度图 则直接返回
        if not self.__imgList[-1].ndim == 2:
            MessageDialog(self, '需要先在「基本」菜单中进行灰度化')
            return

        self.__appendImg(fastFeatureDetection(self.__imgList[-1]))

    # ORB特征检测槽函数
    def __orbFeatureDetectionSlot(self):
        # 如果当前不是灰度图 则直接返回
        if not self.__imgList[-1].ndim == 2:
            MessageDialog(self, '需要先在「基本」菜单中进行灰度化')
            return

        self.__appendImg(orbFeatureDetection(self.__imgList[-1]))

    # 弹出中心窗体
    def __popCenterWidget(self):
        animation = QPropertyAnimation(self.ui.widget_center, b'pos', self)
        animation.setDuration(800)
        animation.setStartValue(
            QPoint(0, self.ui.widget_center_container.height()))
        animation.setEndValue(QPoint(0, 0))
        animation.setEasingCurve(QEasingCurve.InOutCubic)
        animation.finished.connect(
            lambda: self.shadow.setEnabled(True))  # 动画结束后启用阴影
        animation.start()
        self.ui.widget_menu.setEnabled(True)
        self.ui.btn_save.setEnabled(True)

    # 往图片列表中追加图片
    def __appendImg(self, img):
        # 追加图片 并刷新显示
        self.__imgList.append(img)
        self.__viewer.changeImage(self.__imgList[-1])

        # 启用撤销按钮
        self.ui.btn_undo.setEnabled(True)

        # 清空重做列表 并禁用重做按钮
        self.__redoList.clear()
        self.ui.btn_redo.setDisabled(True)
Example #16
0
####################### FOR TESTING #########################
if __name__ == "__main__":
    import wx
    from datamodel import DataModel
    from dbconnect import DBConnect
    from imageviewer import ImageViewer
    import sys

    app = wx.PySimpleApp()

    p = Properties.getInstance()
    dm = DataModel.getInstance()
    db = DBConnect.getInstance()
    ir = ImageReader()

    # Load a properties file if passed in args
    if len(sys.argv) > 1:
        propsFile = sys.argv[1]
        p.LoadFile(propsFile)
    else:
        if not p.show_load_dialog():
            wx.GetApp().Exit()

    obkey = dm.GetRandomObject()
    fds = db.GetFullChannelPathsForImage(obkey[:-1])
    images = ir.ReadImages(fds)
    ImageViewer(images, img_key=obkey[:-1]).Show()

    app.MainLoop()
class BookScanner(QtGui.QWidget):

    @staticmethod
    def _exec(cmd):
        return subprocess.Popen(
            cmd,
            shell=True,
            stdout=subprocess.PIPE).communicate()[0].decode('utf-8')

    def __init__(self):
        super().__init__()

        self.working_directory = os.path.dirname(os.path.realpath(__file__))
        self.current_directory = None

        self.left_camera_is_free = True
        self.right_camera_is_free = True

        self.setWindowTitle('BookScanner')
        self.setWindowIcon(
            QtGui.QIcon('{0}/icon.png'.format(self.working_directory)))

        self.setMinimumSize(1190, 710)

        fg = self.frameGeometry()
        fg.moveCenter(QtGui.QDesktopWidget().availableGeometry().center())
        self.move(fg.topLeft())

        self.background = QtGui.QLabel(self)
        self.background.setGeometry(0, 0, 9999, 9999)
        self.background.setStyleSheet(
            'background-image: url({0}/background.png)'.format(self.working_directory))

        self.layout = QtGui.QVBoxLayout()
        self.layout.setContentsMargins(30, 30, 30, 30)

        self.header = QtGui.QWidget()
        self.header.setFixedSize(1130, 100)

        self.logo = QtGui.QLabel(self.header)
        self.logo.setGeometry(0, 0, 170, 100)
        self.logo.setStyleSheet(
            'background-image: url({0}/logo.png)'.format(self.working_directory))

        self.directory_btn = QtGui.QPushButton('Select directory', self.header)
        self.directory_btn.setGeometry(200, 0, 200, 30)
        self.directory_btn.clicked.connect(self.select_directory)

        self.directory_lbl = QtGui.QLabel(self.header)
        self.directory_lbl.setGeometry(430, 0, 400, 30)

        self.automatic_numeration_box = QtGui.QCheckBox(self.header)
        self.automatic_numeration_box.setGeometry(860, 0, 30, 30)

        self.automatic_numeration_lbl = QtGui.QLabel(
            'Automatic numbering',
            self.header)
        self.automatic_numeration_lbl.setGeometry(890, 0, 200, 30)

        self.filename_left_lbl = QtGui.QLabel(
            'Filename for left camera:',
            self.header)
        self.filename_left_lbl.setGeometry(200, 60, 220, 30)

        self.filename_left_field = QtGui.QLineEdit(self.header)
        self.filename_left_field.setGeometry(420, 60, 220, 30)

        self.filename_right_lbl = QtGui.QLabel(
            'Filename for right camera:',
            self.header)
        self.filename_right_lbl.setGeometry(670, 60, 220, 30)

        self.filename_right_field = QtGui.QLineEdit(self.header)
        self.filename_right_field.setGeometry(890, 60, 220, 30)

        self.layout.addWidget(self.header)

        self.body = QtGui.QWidget()

        self.body_layout = QtGui.QHBoxLayout()

        self.image_left = ImageViewer(self)
        self.body_layout.addWidget(self.image_left)

        self.image_right = ImageViewer(self)
        self.body_layout.addWidget(self.image_right)

        self.body.setLayout(self.body_layout)

        self.layout.addWidget(self.body)

        self.footer = QtGui.QWidget()
        self.footer.setFixedSize(660, 30)

        self.shoot_btn = QtGui.QPushButton('Make photos', self.footer)
        self.shoot_btn.setGeometry(0, 0, 200, 30)
        self.shoot_btn.clicked.connect(self.shoot)

        QtGui.QShortcut(QtGui.QKeySequence('Space'), self, self.shoot)

        self.shoot_left_btn = QtGui.QPushButton('Make left photo', self.footer)
        self.shoot_left_btn.setGeometry(230, 0, 200, 30)
        self.shoot_left_btn.clicked.connect(self.shoot_left)

        self.shoot_right_btn = QtGui.QPushButton(
            'Make right photo',
            self.footer)
        self.shoot_right_btn.setGeometry(460, 0, 200, 30)
        self.shoot_right_btn.clicked.connect(self.shoot_right)

        self.layout.addWidget(self.footer)

        self.setLayout(self.layout)

    def select_directory(self):
        self.current_directory = QtGui.QFileDialog.getExistingDirectory(
            self,
            'Select directory')
        self.directory_lbl.setText(
            'Current directory: ' +
            self.current_directory)

    def shoot(self):
        if self.validate_cameras(2) and self.validate_directory():
            self.shoot_left()
            self.shoot_right()

            self.left_step = 2
            self.right_step = 2

    def shoot_left(self):
        if self.validate_cameras(1) and self.validate_directory() and self.validate_filename_left():
            self.left_camera_is_free = False
            self.update_controls_states()

            self.thread_left = Thread(self.load_left)
            self.thread_left.finished.connect(self.render_left)

            self.left_step = 1

    def shoot_right(self):
        if self.validate_cameras(2) and self.validate_directory() and self.validate_filename_right():
            self.right_camera_is_free = False
            self.update_controls_states()

            self.thread_right = Thread(self.load_right)
            self.thread_right.finished.connect(self.render_right)

            self.right_step = 1

    def validate_cameras(self, n):
        if len(gphoto2.devices()) < n:
            QtGui.QMessageBox.warning(
                self,
                'Warning',
                'The number of connected cameras should be at least {0}.'.format(n))
            return False

        return True

    def validate_directory(self):
        if not self.current_directory:
            QtGui.QMessageBox.warning(
                self,
                'Warning',
                'Current directory is not set.')
            return False

        return True

    def validate_filename_left(self):
        if not self.filename_left_field.text():
            QtGui.QMessageBox.warning(
                self,
                'Warning',
                'Filename for left camera is not set.')
            return False

        if os.path.isfile(self.path_left('jpg')):
            reply = QtGui.QMessageBox.question(
                self,
                'Question',
                'File with filename for left camera already exists. Rewrite?',
                QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
                QtGui.QMessageBox.No)
            if reply != QtGui.QMessageBox.Yes:
                return False

        return True

    def validate_filename_right(self):
        if not self.filename_right_field.text():
            QtGui.QMessageBox.warning(
                self,
                'Warning',
                'Filename for right camera is not set.')
            return False

        if os.path.isfile(self.path_right('jpg')):
            reply = QtGui.QMessageBox.question(
                self,
                'Question',
                'File with filename for right camera already exists. Rewrite?',
                QtGui.QMessageBox.Yes | QtGui.QMessageBox.No,
                QtGui.QMessageBox.No)
            if reply != QtGui.QMessageBox.Yes:
                return False

        return True

    def update_controls_states(self):
        self.shoot_btn.setEnabled(
            self.left_camera_is_free and self.right_camera_is_free)

        self.filename_left_field.setEnabled(self.left_camera_is_free)
        self.shoot_left_btn.setEnabled(self.left_camera_is_free)

        self.filename_right_field.setEnabled(self.right_camera_is_free)
        self.shoot_right_btn.setEnabled(self.right_camera_is_free)

    def load_left(self):
        gphoto2.devices()[0].capture(self.path_left('%C'))
        self._exec(
            'convert "{0}" -rotate 270 "{0}"'.format(self.path_left('jpg')))

    def render_left(self):
        self.left_camera_is_free = True
        self.update_controls_states()

        self.image_left.configure(self.path_left('jpg'), 0.25)

        if self.automatic_numeration_box.isChecked():
            self.filename_left_field.setText(
                self.next_filename(
                    self.filename_left_field.text(),
                    self.left_step))

    def load_right(self):
        gphoto2.devices()[1].capture(self.path_right('%C'))
        self._exec(
            'convert "{0}" -rotate 90 "{0}"'.format(self.path_right('jpg')))

    def render_right(self):
        self.right_camera_is_free = True
        self.update_controls_states()

        self.image_right.configure(self.path_right('jpg'), 0.25)

        if self.automatic_numeration_box.isChecked():
            self.filename_right_field.setText(
                self.next_filename(
                    self.filename_right_field.text(),
                    self.right_step))

    def path_left(self, format):
        return '{0}/{1}.{2}'.format(self.current_directory,
                                    self.filename_left_field.text(),
                                    format)

    def path_right(self, format):
        return '{0}/{1}.{2}'.format(self.current_directory,
                                    self.filename_right_field.text(),
                                    format)

    def next_filename(self, filename, step):
        match = re.search('^\d+', filename)

        if match:
            return str(int(match.group(0)) +
                       step).rjust(len(match.group(0)), '0')
        else:
            return filename
class MainWindow(QMainWindow):
    '''
    MainWindow class
    '''
    def __init__(self, App):
        super(MainWindow, self).__init__()
        self.App = App
        self.splitterPos = 0
        self.initCompleteFlag = False
        self.signal = resizeSignal()
        self.setGeometry(300, 100, 900, 900)
        self.setWindowIcon(QIcon("./image/mainwin.ico"))
        self.initUI()
        self.signal.resize.connect(self.ImageViewer.resizeEvent_wrapper)
        
    def initUI(self):
        #Menu
        self.menubar = self.menuBar()
        self.fileMenu = self.menubar.addMenu('&File')
        self.openAct = QAction('&Open', self)
        self.openAct.setShortcut('Ctrl+O')
        self.openAct.setIcon(QIcon("./image/open.ico"))
        self.saveAct = QAction('&Save', self)
        self.saveAct.setShortcut('Ctrl+S')
        self.saveAct.setIcon(QIcon("./image/save.ico"))
        self.importAct = QAction('&Import Data', self)
        self.importAct.setShortcut('Ctrl+I')
        self.importAct.setIcon(QIcon("./image/import.ico"))
        self.exportAct = QAction('&Export Data', self)
        self.exportAct.setShortcut('Ctrl+E')
        self.exportAct.setIcon(QIcon("./image/export.ico"))
        self.exportAct.setEnabled(False)
        self.exitAct = QAction('&Exit', self)
        self.exitAct.setIcon(QIcon("./image/exit.ico"))
        self.fileMenu.addAction(self.openAct)
        self.fileMenu.addAction(self.saveAct)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.importAct)
        self.fileMenu.addAction(self.exportAct)
        self.fileMenu.addSeparator()
        self.fileMenu.addAction(self.exitAct)
        self.importAct.triggered.connect(self.OnImport)
        self.exportAct.triggered.connect(self.OnExport)
        self.exitAct.triggered.connect(self.close)

        #Data Browser
        self.DataBrowser = DataBrowser(self)

        #Process Region Expansion button
        self.PRButton = QPushButton(">")
        self.PRButton.setFixedSize(20, 80)
        self.PRButton.setCheckable(True)
        self.PRButton.toggled.connect(self.showDataProcessor)

        #Data Processor
        self.DataProcessor = DataProcessor(self)

        #Image Viewer
        self.ImageViewer = ImageViewer(self)

        #Mayavi Region Expansion button
        self.MYButton = QPushButton(">")
        self.MYButton.setFixedSize(20, 80)
        self.MYButton.setCheckable(True)
        #self.MYButton.setEnabled(False)
        self.MYButton.toggled.connect(self.show3D)

        #Mayavi scene
        self.MYWidget = MYWidget(self)

        #Layout
        self.panel, self.splitter, self.Databox, self.DataWidget = self.WinLayout()
        QTimer.singleShot(10, lambda: self.splitter.moveSplitter(self.DataBrowser.minimumWidth(), 1))
        self.splitter.splitterMoved.connect(self.splitterMovedEvent)

        #center panel
        self.centralPanel = QWidget(self)
        self.centralPanel.setLayout(self.panel)
        
        self.setCentralWidget(self.centralPanel)
        self.setWindowTitle('ARPES Data Viewer -- By Wei Yao -- Ver 1.0')    
        self.show()
        self.initCompleteFlag = True

    def WinLayout(self):
        panel = QHBoxLayout()
        splitter = QSplitter()

        splitter.addWidget(self.DataBrowser)
        
        Databox = QHBoxLayout()
        Databox.addWidget(self.PRButton)
        Databox.addWidget(self.ImageViewer)
        Databox.addWidget(self.MYButton)
        DataWidget = QWidget()
        DataWidget.setLayout(Databox)
        splitter.addWidget(DataWidget)

        splitter.setStretchFactor(0,0)
        splitter.setStretchFactor(1,1)

        panel.addWidget(splitter)

        return panel, splitter, Databox, DataWidget

    def showDataProcessor(self, state):
        if state:
            self.Databox.insertWidget(0, self.DataProcessor)
            self.DataProcessor.show()
            self.resizeDataWidget(self.DataProcessor.width()+7, 'DP') #7 is for additional space due to using layout      
            self.PRButton.setText("<")
        else:
            self.Databox.takeAt(0)
            self.DataProcessor.hide()
            #wait for some events are processed in the event loop. 
            #https://stackoverflow.com/questions/28660960/resize-qmainwindow-to-minimal-size-after-content-of-layout-changes
            #This QTimer is used to wait for correct process of layout
            QTimer.singleShot(10, lambda: self.resizeDataWidget(-self.DataProcessor.width()-7, 'DP'))
            self.PRButton.setText(">")

    def show3D(self, state):
        if self.DataProcessor.isVisible():
            pos = 3
        else:
            pos = 2
        if state:
            self.Databox.insertWidget(pos, self.MYWidget)
            self.MYWidget.show()
            self.resizeDataWidget(self.MYWidget.width()+7, 'MY')
            self.MYButton.setText("<")
            self.MYWidget.setData(self.DataBrowser.DataList.currentItem().Data)
        else:
            self.Databox.takeAt(pos)
            self.MYWidget.hide()
            QTimer.singleShot(10, lambda: self.resizeDataWidget(-self.MYWidget.width()-7, 'MY'))
            self.MYButton.setText(">")

    def resizeDataWidget(self, dwidth, flag):
        if dwidth > 0:
            screen_width = QApplication.desktop().screenGeometry().width()
            if self.width()+dwidth+1 < screen_width:
                self.resize(self.width()+dwidth+1, self.height())
                self.resize(self.width()-1, self.height()) # to redraw the gui
            else:
                self.resize(screen_width, self.height())
        elif dwidth < 0:
            #This QTimer is used to wait for correct minimum width of datawidget
            if flag == 'DP':
                delay = 10
            elif flag == 'MY':
                delay = 30
            QTimer.singleShot(delay, lambda: self.resize(self.width()+dwidth, self.height()))

    def OnImport(self):
        filelist = QFileDialog.getOpenFileNames(self, "Import Data", ".", "Igor Packed Files(*.pxt; *.pxp);;ArPy Files(*.arpy);;Ig2Py Files(*.Ig2Py)")[0]
        if len(filelist) > 0:
            self.ImportData(filelist)

    def OnExport(self):
        name = self.DataBrowser.DataList.currentItem().Data.name
        savedfile = QFileDialog.getSaveFileName(self, "Export Data", name, "Igor Packed Files(*.pxt);;ArPy Files(*.arpy)")[0]
        if len(savedfile) > 0:
            self.ExportData(savedfile)
    
    def ImportData(self, filelist):
        for filepath in filelist:
            base = os.path.basename(filepath)
            ext = os.path.splitext(base)[1]
            if ext.lower() == ".ig2py":
                spec = Data.Ig2Py2Data(filepath)
                if spec != None:
                    self.NewData(spec)
            elif ext.lower() == ".arpy":
                spec = Data.ArPy2Data(filepath)
                if spec != None:
                    self.NewData(spec)
            elif ext.lower() == ".pxt":
                specList = IgorPackedFile2Data(filepath, True)
                for spec in specList:
                    self.NewData(spec)
            elif ext.lower() == ".pxp":
                specList = IgorPackedFile2Data(filepath, False)
                for spec in specList:
                    self.NewData(spec)

    def ExportData(self, savedfile):
        base = os.path.basename(savedfile)
        ext = os.path.splitext(base)[1]
        if ext == ".arpy":
            data = self.DataBrowser.DataList.currentItem().Data
            Data.Data2ArPy(data, savedfile)
        elif ext == ".pxt":
            #data = self.DataBrowser.DataList.currentItem().Data
            datalist = [item.Data for item in self.DataBrowser.DataList.selectedItems()]
            Data2IgorPackedFile(datalist, savedfile)

    def setData(self, data):
        self.DataProcessor.updateUI(data)
        self.ImageViewer.setData(data)
        if self.MYButton.isChecked():
            self.MYWidget.setData(data)
    
    def NewData(self, data):
        self.DataBrowser.DataList.addDataItem(data)

    def resizeEvent(self, event):
        if self.DataBrowser.width() < self.splitterPos:
            self.splitter.moveSplitter(self.splitterPos, 1)
        elif self.initCompleteFlag:
            self.signal.resize.emit()

    def splitterMovedEvent(self, pos, idx):
        self.splitterPos = pos
        if pos > self.DataBrowser.minimumWidth():
            if self.initCompleteFlag:
                self.signal.resize.emit()
        else:
            self.resize(self.width()+1, self.height())  # to redraw the gui
            self.resize(self.width()-1, self.height())

    def closeEvent(self, event):
        self.DataBrowser.DataList.noteWin.close()
Example #19
0
from vfcamera import VideoFileCamera
from imageviewer import ImageViewer
from queue import Queue

queue = Queue(10)

viewer = ImageViewer('image', queue)
viewer.start()

camera = VideoFileCamera('video1.avi', queue)
camera.start()
Example #20
0
from vfcamera import VideoFileCamera
from imageviewer import ImageViewer
from imagesender import ImageSender

url = 'http://localhost:8080/start/camera/1'

viewer = ImageViewer('image')
sender = ImageSender(url)

camera = VideoFileCamera('OpenCV/video1.avi')
camera.addObserver(viewer)
camera.addObserver(sender)

camera.start()
viewer.start()
sender.start()