Example #1
0
class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.new_graph_dialog_text = NewGraphWindowText()
        self.new_graph_dialog_graphic = NewGraphWindowGraphic()

        self.mv, self.xdif, self.ydif, self.start_vertice = None, None, None, None
        self.from_file, self.graph_present = False, False
        self.used, self.con_points, self.tin, self.tout, self.lines = [], [], [], [], []
        self.algo_starts, self.timer = 0, 0
        self.paths, self.coords = [], []

        self.setGeometry(300, 300, 1000, 500)
        self.move(QApplication.desktop().screen().rect().center() -
                  self.rect().center())
        self.setWindowTitle("Articulation Points")
        self.setWindowIcon(QIcon("icon.jpeg"))

        self.menubar = QMenuBar(self)
        self.filemenu = self.menubar.addMenu("File")
        self.newfile = self.filemenu.addMenu("New")
        self.newtext = self.newfile.addAction("New Graph(Text)")
        self.newgraphic = self.newfile.addAction("New Graph(Graphical)")
        self.openfile = self.filemenu.addAction("Open")
        self.savefile = self.filemenu.addAction("Save")
        self.exitfile = self.filemenu.addAction("Exit")

        self.filemenu.triggered[QAction].connect(self.ProcessTrigger)

        self.startalgobtn = QPushButton("Start", self)
        self.startalgobtn.setGeometry(self.width() - self.startalgobtn.width(),
                                      self.menubar.height(),
                                      self.startalgobtn.width(),
                                      self.startalgobtn.height())
        self.startalgobtn.setVisible(False)
        self.startalgobtn.clicked.connect(self.Algo)

        self.resetgraphbtn = QPushButton("Reset Graph", self)
        self.resetgraphbtn.setGeometry(
            self.width() - self.startalgobtn.width(),
            self.menubar.height() + self.resetgraphbtn.height(),
            self.startalgobtn.width(), self.startalgobtn.height())
        self.resetgraphbtn.setVisible(False)
        self.resetgraphbtn.clicked.connect(self.Reset)

        self.exitbtn = QPushButton("Exit", self)
        self.exitbtn.setGeometry(
            self.width() - self.startalgobtn.width(),
            self.menubar.height() + self.resetgraphbtn.height() +
            self.exitbtn.height(), self.startalgobtn.width(),
            self.startalgobtn.height())
        self.exitbtn.setVisible(False)
        self.exitbtn.clicked.connect(self.Exit)

        self.con_points_lbl = QLabel("meh", self)
        self.con_points_lbl.setVisible(False)

        self.sleepslider = QSlider(Qt.Horizontal, self)
        self.sleepslider.setMinimum(1)
        self.sleepslider.setMaximum(20)
        self.sleepslider.setValue(10)
        self.sleepslider.setTickPosition(QSlider.TicksBelow)
        self.sleepslider.setTickInterval(1)
        self.sleepslider.setGeometry(
            0,
            self.height() - self.con_points_lbl.height(), 500,
            self.sleepslider.height())

        self.modelbl = QLabel("Mode:", self)
        self.modelbl.setGeometry(
            0,
            self.height() - self.sleepslider.height() - 40, 50,
            self.modelbl.height())
        self.editmode = QRadioButton("Edit", self)
        self.editmode.setGeometry(
            52,
            self.height() - self.sleepslider.height() - 40, 50,
            self.editmode.height())
        self.editmode.setChecked(True)
        self.choosemode = QRadioButton("Choose starting vertice", self)
        self.choosemode.setGeometry(
            104,
            self.height() - self.sleepslider.height() - 40, 160,
            self.choosemode.height())

        self.editmode.setVisible(False)
        self.modelbl.setVisible(False)
        self.choosemode.setVisible(False)
        self.sleepslider.setVisible(False)

        self.show()

    def ProcessTrigger(self, q):
        if q == self.newtext: self.NewFile("t")
        if q == self.newgraphic: self.NewFile("g")
        if q == self.openfile: self.OpenFile()
        if q == self.savefile: self.SaveFile()
        if q == self.exitfile: self.Exit()

    def mousePressEvent(self, e: QMouseEvent):
        QApplication.processEvents()
        if self.editmode.isChecked():
            try:
                if self.mv == None and self.graph_present:
                    for x in self.coords:
                        if (x[0] - 20 <= e.pos().x() <= x[0] + 20) and (
                                x[1] - 20 <= e.pos().y() <= x[1] + 20):
                            self.mv = self.coords.index(x)
                            self.xdif = e.pos().x() - x[0]
                            self.ydif = e.pos().y() - x[1]
                            self.UpdatePath()
                            self.update()
                            break
                else:
                    self.mv, self.xdif, self.ydif = None, None, None
            except:
                return

        elif self.choosemode.isChecked():
            for coord in self.coords:
                if (coord[0] - 20 <= e.pos().x() <= coord[0] + 20) and (
                        coord[1] - 20 <= e.pos().y() <= coord[1] + 20):
                    coord[2] = Qt.darkMagenta
                    self.coords[self.start_vertice][2] = Qt.red
                    self.start_vertice = self.coords.index(coord)
                    self.update()

    def mouseMoveEvent(self, e: QMouseEvent):
        QApplication.processEvents()
        if self.editmode.isChecked():
            try:
                if self.mv != None:
                    self.coords[self.mv] = [
                        e.pos().x() - self.xdif,
                        e.pos().y() - self.ydif, self.coords[self.mv][2]
                    ]
                    self.UpdatePath()
                    self.update()
            except:
                return

    def mouseReleaseEvent(self, e: QMouseEvent):
        QApplication.processEvents()
        if self.editmode.isChecked():
            try:
                if self.mv != None:
                    self.coords[self.mv] = [
                        e.pos().x() - self.xdif,
                        e.pos().y() - self.ydif, self.coords[self.mv][2]
                    ]
                    self.UpdatePath()
                    self.update()
                    self.mv, self.xdif = None, None
            except:
                return

    def paintEvent(self, a0):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.setBackground(Qt.white)
        painter.setPen(QPen(Qt.black, 2, Qt.SolidLine))
        painter.setBrush(Qt.NoBrush)
        for path in self.paths:
            painter.drawPath(path)
        for coord in self.coords:
            painter.setBrush(coord[2])
            painter.drawEllipse(coord[0] - 20, coord[1] - 20, 40, 40)
            painter.drawText(coord[0] - 10, coord[1] - 10, 20, 20,
                             Qt.AlignCenter, str(self.coords.index(coord) + 1))
        painter.setPen(QPen(Qt.darkYellow, 4, Qt.SolidLine))
        for i in range(len(self.tin)):
            painter.drawText(self.coords[i][0] + 20,
                             self.coords[i][1] - 40 // 3, 40, 10,
                             Qt.AlignCenter,
                             str(self.tin[i]) + "/" + str(self.tout[i]))

    def UpdatePath(self):
        self.paths = []
        for line in self.lines:
            path = QPainterPath()
            path.moveTo(QPointF(*self.coords[line[0]][:2]))
            path.lineTo(QPointF(*self.coords[line[1]][:2]))
            self.paths.append(path)

    def ResetGraph(self):
        self.paths, self.coords, self.tin, self.tout, self.con_points, self.used = [], [], [], [], [], []
        self.con_points_lbl.setVisible(False)
        self.start_vertice = None
        self.editmode.setVisible(False)
        self.modelbl.setVisible(False)
        self.choosemode.setVisible(False)
        self.sleepslider.setVisible(False)
        self.update()

    def Reset(self, e):
        self.coords = [[*coord[:2], Qt.red] for coord in self.coords]
        self.coords[0][2] = Qt.darkMagenta
        self.start_vertice = 0
        self.tin = self.tout = []
        self.update()

    def NewFile(self, mode):
        self.ResetGraph()
        global graph_config
        self.from_file = False
        if mode == "t": self.new_graph_dialog_text.exec_()
        else: self.new_graph_dialog_graphic.exec_()
        if graph_config == None: return
        self.ReadGraph()

    def OpenFile(self):
        self.ResetGraph()
        try:
            self.from_file = True
            global graph_config
            graph_config = QFileDialog.getOpenFileName(self, "Open File",
                                                       os.getcwd(),
                                                       "Text Files (*.txt)")[0]
            self.ReadGraph()
        except:
            return

    def SaveFile(self):
        global graph_config
        if graph_config == None: return
        else:
            name = list(
                QFileDialog.getSaveFileName(self, "Save File", os.getcwd(),
                                            "Text Files (*.txt)"))
            if ".txt" not in name[0]: name[0] += ".txt"
            with open(name[0], "w") as f:
                f.write(str(self.num_of_peaks) + "\n")
                f.write("\n".join(self.info))

    def Exit(self):
        QApplication.instance().quit()

    def ReadGraph(self):
        try:
            global graph_config
            movetopoint = None
            startlinevertice = None

            if self.from_file:
                with open(graph_config) as f:
                    data = f.readlines()
            else:
                data = graph_config

            self.num_of_peaks, *self.info = data
            self.num_of_peaks = int(self.num_of_peaks)
            self.used = [False for x in range(self.num_of_peaks)]
            try:
                ix = self.info.index("COORDS\n")
            except:
                ix = self.info.index("COORDS")
            vertices_raw = self.info[:ix]
            coords_raw = self.info[ix + 1:]
            vertices = [
                list(map(int, vertice.split())) for vertice in vertices_raw
            ]
            coords = [list(map(int, coord.split())) for coord in coords_raw]
            self.graph = [vertice[1::] for vertice in vertices]
            for vertice in vertices:
                path = QPainterPath()
                for i, p in enumerate(vertice):
                    point = QPointF(*coords[p - 1])
                    if i == 0:
                        movetopoint = point
                        startlinevertice = p - 1
                        path.moveTo(point)
                    else:
                        path.lineTo(point)
                        path.moveTo(movetopoint)
                        self.lines.append([startlinevertice, p - 1])
                self.paths.append(path)

            for i in range(len(coords)):
                self.coords.append([*coords[i], Qt.red])
            self.coords[0] = [*self.coords[0][:2], Qt.darkMagenta]
            self.start_vertice = 0

            self.update()

            self.startalgobtn.setVisible(True)
            self.resetgraphbtn.setVisible(True)
            self.exitbtn.setVisible(True)
            self.graph_present = True
            self.editmode.setVisible(True)
            self.modelbl.setVisible(True)
            self.choosemode.setVisible(True)
            self.sleepslider.setVisible(True)
        except:
            return

    def UpdateSleep(self):
        self.update()
        QApplication.processEvents()
        sleep(self.sleepslider.value() / 10)

    def Algo(self, e):
        QApplication.processEvents()
        self.modelbl.setVisible(False)
        self.editmode.setVisible(False)
        self.choosemode.setVisible(False)
        self.algo_starts += 1
        if self.algo_starts > 1:
            QApplication.processEvents()
            self.con_points_lbl.setVisible(False)
            for coord in self.coords:
                coord[2] = Qt.red
            self.timer = 0
            self.tin = self.tout = [0 for x in range(self.num_of_peaks)]
            self.update()
        self.used = [False for i in range(self.num_of_peaks)]
        self.tin = [0 for i in range(self.num_of_peaks)]
        self.tout = [0 for i in range(self.num_of_peaks)]

        def dfs(v, p=-1):
            self.used[v] = True
            self.coords[v][2] = Qt.yellow
            self.tin[v] = self.tout[v] = self.timer + 1
            QApplication.processEvents()
            self.UpdateSleep()

            self.timer += 1
            children = 0
            QApplication.processEvents()
            for i in range(0, len(self.graph[v])):
                to = self.graph[v][i] - 1
                if to == p: continue
                if self.used[to]:
                    self.tout[v] = min(self.tout[v], self.tin[to])
                    QApplication.processEvents()
                    self.UpdateSleep()
                else:
                    QApplication.processEvents()
                    dfs(to, v)
                    self.tout[v] = min(self.tout[v], self.tout[to])
                    if self.tout[to] >= self.tin[v] and p != -1:
                        self.con_points.append(v + 1)
                        self.coords[v][2] = Qt.green
                    children += 1
                    QApplication.processEvents()
                    self.UpdateSleep()
            if (p == -1 and children > 1 and (v + 1) not in self.con_points):
                self.con_points.append(v + 1)
                self.coords[v][2] = Qt.green
                QApplication.processEvents()
                self.UpdateSleep()

        dfs(self.start_vertice)

        for i in range(self.num_of_peaks):
            QApplication.processEvents()
            if not self.used[i]:
                QApplication.processEvents()
                dfs(i)

        if len(self.con_points) == 0:
            self.con_points_lbl.setText("Connection point(-s) is(are): None")
        else:
            self.con_points_lbl.setText(
                "Connection point(-s) is(are): " +
                " ".join(list(map(str, set(self.con_points)))))

        self.con_points_lbl.setGeometry(
            self.width() - 400,
            self.height() - self.con_points_lbl.height(), 400,
            self.con_points_lbl.height())
        self.con_points_lbl.setVisible(True)

        self.modelbl.setVisible(True)
        self.editmode.setVisible(True)
        self.choosemode.setVisible(True)
Example #2
0
class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.get_main_window_attributes()
        self.add_menubar()
        self.add_tracking_options_to_menubar()
        self.add_plotting_options_to_menubar()
        self.main_tab = MainTab(self.main_window_width,
                                self.main_window_height)
        self.setCentralWidget(self.main_tab)
        self.setMenuBar(self.menubar)
        self.setWindowTitle('Zebrafish Behaviour Tracking')
        self.setWindowState(Qt.WindowMaximized)
        self.show()

    def get_main_window_attributes(self):
        self.main_window_width = QDesktopWidget().availableGeometry().width()
        self.main_window_height = QDesktopWidget().availableGeometry().height()

    def add_menubar(self):
        self.menubar = QMenuBar()
        self.menubar.resize(self.main_window_width, self.menubar.height())

    def add_tracking_options_to_menubar(self):
        self.tracking_options_menu = self.menubar.addMenu('&Tracking Options')

        self.open_video_action = QAction('&Open Video', self)
        self.open_video_action.setShortcut('Ctrl+O')
        self.open_video_action.setStatusTip('Open Video')
        self.open_video_action.triggered.connect(self.trigger_open_video)
        self.tracking_options_menu.addAction(self.open_video_action)

        self.select_save_path_action = QAction('&Select Save Path', self)
        self.select_save_path_action.setShortcut('Ctrl+P')
        self.select_save_path_action.setStatusTip('Select Save Path')
        self.select_save_path_action.triggered.connect(
            self.trigger_select_save_path)
        self.tracking_options_menu.addAction(self.select_save_path_action)

        self.load_background_action = QAction('&Load Background', self)
        self.load_background_action.setShortcut('Ctrl+L')
        self.load_background_action.setStatusTip('Load Background')
        self.load_background_action.triggered.connect(
            self.trigger_load_background)
        self.tracking_options_menu.addAction(self.load_background_action)

        self.calculate_background_action = QAction('&Calculate Background',
                                                   self)
        self.calculate_background_action.setShortcut('Ctrl+B')
        self.calculate_background_action.setStatusTip('Calculate Background')
        self.calculate_background_action.triggered.connect(
            self.trigger_calculate_background)
        self.tracking_options_menu.addAction(self.calculate_background_action)

        self.save_background_action = QAction('&Save Background', self)
        self.save_background_action.setShortcut('Ctrl+S')
        self.save_background_action.setStatusTip('Save Background')
        self.save_background_action.triggered.connect(
            self.trigger_save_background)
        self.tracking_options_menu.addAction(self.save_background_action)

        self.unload_all_tracking_action = QAction('&Unload All Tracking', self)
        self.unload_all_tracking_action.setShortcut('Ctrl+U')
        self.unload_all_tracking_action.setStatusTip(
            'Unload All Tracking From Memory')
        self.unload_all_tracking_action.triggered.connect(
            self.trigger_unload_all_tracking)
        self.tracking_options_menu.addAction(self.unload_all_tracking_action)

    def add_plotting_options_to_menubar(self):
        self.plotting_options_menu = self.menubar.addMenu('&Plotting Options')

        self.load_tracking_results_action = QAction('&Load Tracking Results')
        self.load_tracking_results_action.setStatusTip('Load Tracking Results')
        self.load_tracking_results_action.triggered.connect(
            self.trigger_load_tracking_results)
        self.plotting_options_menu.addAction(self.load_tracking_results_action)

        self.open_tracked_video_action = QAction('&Open Tracked Video', self)
        self.open_tracked_video_action.setShortcut('Ctrl+T')
        self.open_tracked_video_action.setStatusTip('Open Tracked Video')
        self.open_tracked_video_action.triggered.connect(
            self.trigger_open_tracked_video)
        self.plotting_options_menu.addAction(self.open_tracked_video_action)

        self.unload_all_plotting_action = QAction('&Unload All Plotting', self)
        self.unload_all_plotting_action.setStatusTip('Unload All Plotting')
        self.unload_all_plotting_action.triggered.connect(
            self.trigger_unload_all_plotting)
        self.plotting_options_menu.addAction(self.unload_all_plotting_action)

    def trigger_save_background(self):
        self.main_tab.tracking_window.tracking_content.trigger_save_background(
        )

    def trigger_calculate_background(self):
        self.main_tab.tracking_window.tracking_content.trigger_calculate_background(
        )

    def trigger_select_save_path(self):
        self.main_tab.tracking_window.tracking_content.trigger_select_save_path(
        )

    def trigger_load_background(self):
        self.main_tab.tracking_window.tracking_content.trigger_load_background(
        )

    def trigger_open_video(self):
        self.main_tab.tracking_window.tracking_content.trigger_open_video()

    def trigger_open_tracked_video(self):
        self.main_tab.plotting_window.plotting_content.trigger_open_video()

    def trigger_unload_all_tracking(self):
        self.main_tab.tracking_window.tracking_content.trigger_unload_all_tracking(
        )

    def trigger_load_tracking_results(self):
        self.main_tab.plotting_window.plotting_content.trigger_load_tracking_results(
        )

    def trigger_unload_all_plotting(self):
        self.main_tab.plotting_window.plotting_content.trigger_unload_all_plotting(
        )

    # Defining Event Functions
    def closeEvent(self, event):
        if self.main_tab.tracking_window.tracking_content.calculate_background_progress_window is not None:
            if self.main_tab.tracking_window.tracking_content.calculate_background_progress_window.isVisible(
            ):
                self.main_tab.tracking_window.tracking_content.calculate_background_progress_window.close(
                )
        if self.main_tab.tracking_window.tracking_content.track_video_progress_window is not None:
            if self.main_tab.tracking_window.tracking_content.track_video_progress_window.isVisible(
            ):
                self.main_tab.tracking_window.tracking_content.track_video_progress_window.close(
                )
        if self.main_tab.tracking_window.tracking_content.track_all_videos_progress_window is not None:
            if self.main_tab.tracking_window.tracking_content.track_all_videos_progress_window.isVisible(
            ):
                self.main_tab.tracking_window.tracking_content.track_all_videos_progress_window.close(
                )
        event.accept()