class VideoFrame(QWidget): def __init__(self, *args, **kwargs): super(VideoFrame, self).__init__(*args, **kwargs) self.layout = QVBoxLayout() self.img_list = [] # STREAM 1 LABEL AREA self.label = QLabel('Nothing to show right now.', self) self.label.setAlignment(Qt.AlignCenter) self.label.setGeometry(30, 20, 750, 360) self.layout.addWidget(self.label) # PLAY BUTTON self.play = QPushButton(self) icon = QPixmap(os.path.join(os.path.dirname(__file__), 'icons', 'play.png')) self.play.setIcon(QIcon(icon)) self.play.setGeometry(320, 370, 50, 30) self.play.clicked.connect(self.timerEvent) self.layout.addWidget(self.play) # PAUSE BUTTON self.pause = QPushButton(self) icon = QPixmap(os.path.join(os.path.dirname(__file__), 'icons', 'pause.png')) self.pause.setIcon(QIcon(icon)) self.pause.setGeometry(400, 370, 50, 30) self.pause.clicked.connect(self.pauseTimer) self.layout.addWidget(self.pause) # FAST-FORWARD self.ff = QPushButton(self) icon = QPixmap(os.path.join(os.path.dirname(__file__), 'icons', 'ff.png')) self.ff.setIcon(QIcon(icon)) self.ff.setGeometry(560, 370, 50, 30) self.ff.clicked.connect(self.fastForward) self.layout.addWidget(self.ff) # SLOWDOWN self.fr = QPushButton(self) icon = QPixmap(os.path.join(os.path.dirname(__file__), 'icons', 'fr.png')) self.fr.setIcon(QIcon(icon)) self.fr.setGeometry(240, 370, 50, 30) self.fr.clicked.connect(self.slowdown) self.layout.addWidget(self.fr) self.stop = QPushButton(self) icon = QPixmap(os.path.join(os.path.dirname(__file__), 'icons', 'stop.png')) self.stop.setIcon(QIcon(icon)) self.stop.setGeometry(480, 370, 50, 30) self.stop.clicked.connect(self.stopTimer) self.layout.addWidget(self.stop) # SLIDER 1 self.slider = QSlider(Qt.Horizontal, self) self.layout.addWidget(self.slider) self.slider.setGeometry(10, 400, 825, 20) self.slider.valueChanged.connect(self.showImage) # RANGE SLIDER self.range_slider = QRangeSlider(self) self.range_slider.setFixedHeight(30) self.range_slider.setFixedWidth(825) self.range_slider.move(10, 420) self.range_slider.endValueChanged.connect(self.boundEnd) self.range_slider.startValueChanged.connect(self.boundStart) self.timer = QBasicTimer() # FIXME consider something with less lag self.startIdx = 0 self.idx = 0 self.delay = 1000 self.skip = 1 self.calibrate_mode = False self.alpha = None self.beta = None self.t = None self.z = None def size(self): return len(self.img_list) def mousePressEvent(self, event): print('Calibration: ' + str(self.calibrate_mode)) if self.calibrate_mode is True: c_x, c_y = (event.x(), event.y()) self.alpha, self.beta = alpha_beta(c_x, c_y) self.t = lp_projection_calibration(self.alpha, self.beta) elif self.t is not None: c_x, c_y = (event.x(), event.y()) self.alpha, self.beta = alpha_beta(c_x, c_y) self.z = lp_projection(self.alpha, self.beta, self.t) print('Height (inches): ' + str(self.z)) def setCalibrateMode(self): self.calibrate_mode = not self.calibrate_mode def boundEnd(self): self.endIdx = self.range_slider.end() def boundStart(self): self.startIdx = self.range_slider.start() self.idx = self.startIdx def setSkipRate(self, skip_rate): self.skip = skip_rate def setFrameRate(self, delay): self.delay = delay def setImgList(self, img_list): self.img_list = img_list self.endIdx = len(self.img_list)-1 self.slider.setRange(0, len(self.img_list)-1) self.range_slider.setMax(len(self.img_list)-1) pixmap = QPixmap(self.img_list[self.idx]).scaled(600, 800, Qt.KeepAspectRatio, Qt.FastTransformation) #self.pixmap_list = [QPixmap(self.img_list[i]).scaled(600, 800, Qt.KeepAspectRatio, Qt.FastTransformation) for i in range(0, len(self.img_list))] self.label.setPixmap(pixmap) def showImage(self): if len(self.img_list) == 0: return self.idx = self.slider.value() pixmap = QPixmap(self.img_list[self.idx]).scaled(600, 800, Qt.KeepAspectRatio, Qt.FastTransformation) self.label.setPixmap(pixmap) def showImage(self, idx): if len(self.img_list) == 0 or idx > len(self.img_list)-1: return self.idx = idx self.slider.setValue(idx) pixmap = QPixmap(self.img_list[idx]).scaled(600, 800, Qt.KeepAspectRatio, Qt.FastTransformation) self.label.setPixmap(pixmap) def timerEvent(self, e=None): if len(self.img_list) == 0: return if self.idx > self.endIdx: self.timer.stop() self.idx = self.startIdx return self.timer.start(self.delay, self) self.showImage(self.idx) #self.label.setPixmap(self.pixmap_list[self.idx]) self.slider.setValue(self.idx) self.idx += self.skip def pauseTimer(self): self.timer.stop() def stopTimer(self): self.timer.stop() self.startIdx = self.range_slider.start() self.idx = self.startIdx def fastForward(self): if len(self.img_list) == 0: return self.delay /= 2 def slowdown(self): if len(self.img_list) == 0: return self.delay *= 2
class VideoFrame(QWidget): def __init__(self, *args, **kwargs): super(VideoFrame, self).__init__(*args, **kwargs) self.layout = QVBoxLayout() self.img_list = [] # VIDEO LABEL AREA self.label = QLabel('Nothing to show right now.', self) self.label.setAlignment(Qt.AlignCenter) self.label.setGeometry(30, 20, 750, 360) self.layout.addWidget(self.label) # PLAY BUTTON self.play = QPushButton(self) icon = QPixmap( os.path.join(os.path.dirname(__file__), 'icons', 'play.png')) self.play.setIcon(QIcon(icon)) self.play.setGeometry(320, 370, 50, 30) self.play.clicked.connect(self.timerEvent) self.layout.addWidget(self.play) # PAUSE BUTTON self.pause = QPushButton(self) icon = QPixmap( os.path.join(os.path.dirname(__file__), 'icons', 'pause.png')) self.pause.setIcon(QIcon(icon)) self.pause.setGeometry(400, 370, 50, 30) self.pause.clicked.connect(self.pauseTimer) self.layout.addWidget(self.pause) # FAST-FORWARD self.ff = QPushButton(self) icon = QPixmap( os.path.join(os.path.dirname(__file__), 'icons', 'ff.png')) self.ff.setIcon(QIcon(icon)) self.ff.setGeometry(480, 370, 50, 30) self.ff.clicked.connect(self.fastForward) self.layout.addWidget(self.ff) # SLOWDOWN self.fr = QPushButton(self) icon = QPixmap( os.path.join(os.path.dirname(__file__), 'icons', 'fr.png')) self.fr.setIcon(QIcon(icon)) self.fr.setGeometry(240, 370, 50, 30) self.fr.clicked.connect(self.slowdown) self.layout.addWidget(self.fr) # SLIDER 1 self.slider = QSlider(Qt.Horizontal, self) self.layout.addWidget(self.slider) self.slider.setGeometry(10, 400, 825, 20) self.slider.valueChanged.connect(self.showImage) # RANGE SLIDER self.range_slider = QRangeSlider(self) self.range_slider.setFixedHeight(30) self.range_slider.setFixedWidth(825) self.range_slider.move(10, 420) self.range_slider.endValueChanged.connect(self.boundEnd) self.range_slider.startValueChanged.connect(self.boundStart) self.timer = QBasicTimer() # FIXME consider something with less lag self.startIdx = 0 self.endIdx = 0 self.idx = 0 self.delay = 1000 self.skip = 1 self.threadpool = QThreadPool() self.thread = None def size(self): return len(self.img_list) def boundEnd(self): self.endIdx = self.range_slider.end() def boundStart(self): self.startIdx = self.range_slider.start() self.idx = self.startIdx def setSkipRate(self, skip_rate): self.skip = skip_rate if self.thread is not None: self.thread.kwargs['skip'] = self.delay / 1000 def setFrameRate(self, delay): self.delay = delay if self.thread is not None: self.thread.kwargs['delay'] = self.delay / 1000 def setImgList(self, img_list): self.img_list = img_list self.endIdx = len(self.img_list) - 1 self.slider.setRange(0, len(self.img_list) - 1) self.range_slider.setMax(len(self.img_list) - 1) pixmap = QPixmap(self.img_list[self.idx]).scaled( 600, 800, Qt.KeepAspectRatio, Qt.FastTransformation) self.label.setPixmap(pixmap) def showImage(self): if len(self.img_list) == 0: return self.idx = self.slider.value() pixmap = QPixmap(self.img_list[self.idx]).scaled( 600, 800, Qt.KeepAspectRatio, Qt.FastTransformation) self.label.setPixmap(pixmap) def showImage(self, idx): if len(self.img_list) == 0 or idx > len(self.img_list) - 1: return self.idx = idx self.slider.setValue(idx) pixmap = QPixmap(self.img_list[idx]).scaled(600, 800, Qt.KeepAspectRatio, Qt.FastTransformation) self.label.setPixmap(pixmap) def timerEvent(self): self.thread = DelayWorker(self.startIdx, self.endIdx, delay=self.delay, skip=self.skip) self.thread.signals.idx.connect(self.showImage) self.threadpool.start(self.thread) # if len(self.img_list) == 0: # return # if self.idx > self.endIdx: # self.timer.stop() # self.idx = self.startIdx # return # self.timer.start(self.delay, self) # pixmap = QPixmap(self.img_list[self.idx]).scaled(600, 800, Qt.KeepAspectRatio, Qt.FastTransformation) # self.label.setPixmap(pixmap) # self.slider.setValue(self.idx) # self.idx += self.skip def pauseTimer(self): self.thread.stop = True self.startIdx = self.idx def fastForward(self): if len(self.img_list) == 0: return self.thread.kwargs['delay'] /= 2 def slowdown(self): if len(self.img_list) == 0: return self.thread.kwargs['delay'] *= 2
class MainWindow(QMainWindow): def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.setWindowIcon( QIcon(os.path.join(os.path.dirname(__file__), 'icons', 'plant.png'))) self.setWindowTitle("Video Comparison GUI") self.statusBar() self.img_list = None self.cur_video_id = 0 self.layout = QGridLayout() # Main Widget Init self.widget = QWidget() self.widget.setLayout(self.layout) self.setCentralWidget(self.widget) self.setGeometry(250, 50, 1920, 1080) # Open File Dialog openFile = QAction('Open Image Directory', self) openFile.setShortcut('Ctrl+O') openFile.setStatusTip('Open Image Directory') openFile.triggered.connect(self.fileDialog) change_framerate = QAction('Change Framerate...', self) change_framerate.setStatusTip( 'Change Playback Framerate of Video (default: 1 frame/sec)') change_framerate.triggered.connect(self.setFrameRate) change_skiprate = QAction('Change Skip Rate...', self) change_skiprate.setStatusTip( 'Change Frame Skip Rate in Selected Photos (default: 1)') change_skiprate.triggered.connect(self.setSkipRate) set_v_1 = QAction('Video 1...', self) set_v_1.setStatusTip('Set Video 1 (Top Left Corner) Settings') set_v_1.triggered.connect(self.setv1) set_v_2 = QAction('Video 2...', self) set_v_2.setStatusTip('Set Video 2 (Top Right Corner) Settings') set_v_2.triggered.connect(self.setv2) set_v_3 = QAction('Video 3...', self) set_v_3.setStatusTip('Set Video 3 (Bottom Left Corner) Settings') set_v_3.triggered.connect(self.setv3) set_v_4 = QAction('Video 4...', self) set_v_4.setStatusTip('Set Video 4 (Bottom Right Corner) Settings') set_v_4.triggered.connect(self.setv4) change_calibrate = QAction('Turn Calibration On/Off...', self) change_calibrate.setStatusTip( 'Calibrate auto height detection to plant pot') change_calibrate.triggered.connect(self.calibrate) export_video = QAction('Export Video...', self) export_video.setStatusTip( 'Export the current video frame with current settings') export_video.triggered.connect(self.export) # Menu Bar menubar = self.menuBar() file_menu = menubar.addMenu('&File') file_menu.addAction(openFile) file_menu.addAction(export_video) edit_menu = menubar.addMenu('&Edit') edit_menu.addAction(change_framerate) edit_menu.addAction(change_skiprate) video_menu = menubar.addMenu('&Video') video_menu.addAction(set_v_1) video_menu.addAction(set_v_2) video_menu.addAction(set_v_3) video_menu.addAction(set_v_4) calibrate_menu = menubar.addMenu('&Calibrate') calibrate_menu.addAction(change_calibrate) # Video Frame Objects self.v1 = VideoFrame() self.layout.addWidget(self.v1, 0, 0, 1, 2) self.v2 = VideoFrame() self.layout.addWidget(self.v2, 0, 2, 1, 2) self.v3 = VideoFrame() self.layout.addWidget(self.v3, 1, 0, 1, 2) self.v4 = VideoFrame() self.layout.addWidget(self.v4, 1, 2, 1, 2) self.video_list = [self.v1, self.v2, self.v3, self.v4] ## STREAM 1 LABEL AREA #self.label = QLabel('Nothing to show right now.') #self.label.setAlignment(Qt.AlignCenter) #self.layout.addWidget(self.label) self.bottomLayout = QVBoxLayout() # GLOBAL PLAY BUTTON #self.play = QPushButton("Play") #self.play.clicked.connect(self.timerEvent) #self.bottomLayout.addWidget(self.play) # SLOWDOWN #self.fr = QPushButton(self) #icon = QPixmap(os.path.join(os.path.dirname(__file__), 'icons', 'fr.png')) #self.fr.setIcon(QIcon(icon)) #self.fr.clicked.connect(self.slowdown) #self.layout.addWidget(self.fr, 2, 0, 1, 1) # GLOBAL PLAY BUTTON self.play = QPushButton(self) icon = QPixmap( os.path.join(os.path.dirname(__file__), 'icons', 'play.png')) self.play.setIcon(QIcon(icon)) self.play.clicked.connect(self.timerEvent) self.layout.addWidget(self.play, 2, 0, 1, 1) # GLOBAL PAUSE BUTTON self.pause = QPushButton(self) icon = QPixmap( os.path.join(os.path.dirname(__file__), 'icons', 'pause.png')) self.pause.setIcon(QIcon(icon)) self.pause.clicked.connect(self.pauseTimer) self.layout.addWidget(self.pause, 2, 1, 1, 1) # GLOBAL FAST-FORWARD self.ff = QPushButton(self) icon = QPixmap( os.path.join(os.path.dirname(__file__), 'icons', 'ff.png')) self.ff.setIcon(QIcon(icon)) self.ff.clicked.connect(self.fastForward) self.layout.addWidget(self.ff, 2, 3, 1, 1) # GLOBAL STOP self.stop = QPushButton(self) icon = QPixmap( os.path.join(os.path.dirname(__file__), 'icons', 'stop.png')) self.stop.setIcon(QIcon(icon)) self.stop.clicked.connect(self.stopTimer) self.layout.addWidget(self.stop, 2, 2, 1, 1) # GLOBAL SLIDER self.slider = QSlider(Qt.Horizontal) self.bottomLayout.addWidget(self.slider) self.slider.valueChanged.connect(self.showImage) # GLOBAL RANGE SLIDER self.range_slider = QRangeSlider() self.range_slider.setFixedHeight(20) self.bottomLayout.addWidget(self.range_slider) self.range_slider.endValueChanged.connect(self.boundEnd) self.range_slider.startValueChanged.connect(self.boundStart) self.layout.addLayout(self.bottomLayout, 3, 0, 1, 4) self.timer = QBasicTimer() # FIXME consider something with less lag self.startIdx = 0 self.idx = 0 self.delay = 1000 self.skip = 1 def fileDialog(self): self.img_list, _ = QFileDialog.getOpenFileNames( self, 'Select one or more files to open', '/home', 'Images (*.jpg)') self.img_list.sort() if len(self.img_list) == 0: return self.video_list[self.cur_video_id].setImgList(self.img_list) self.endIdx = max(self.video_list, key=lambda end: end.size() - 1) self.endIdx = self.endIdx.size() - 1 self.slider.setRange(0, self.endIdx) self.range_slider.setMax(self.endIdx) def timerEvent(self): self.v1.timerEvent() self.v2.timerEvent() self.v3.timerEvent() self.v4.timerEvent() p1 = Process(target=self.v1.timerEvent(), args=()) p2 = Process(target=self.v2.timerEvent(), args=()) p3 = Process(target=self.v3.timerEvent(), args=()) p4 = Process(target=self.v4.timerEvent(), args=()) p1.start() p2.start() p3.start() p4.start() p1.join() p2.join() p3.join() p4.join() self.slider.setValue(self.idx) self.idx += self.skip def showImage(self): self.idx = self.slider.value() for i in range(len(self.video_list)): self.video_list[i].showImage(self.idx) def setFrameRate(self): delay, _ = QInputDialog.getDouble(self, 'Change Output Framerate...', 'New Framerate (frames/second)', 1000 / self.delay, 1, 100, 1) self.delay = 1000.0 / delay self.video_list[self.cur_video_id].setFrameRate(self.delay) def setSkipRate(self): self.skip, _ = QInputDialog.getInt(self, 'Change Skip Rate...', 'New Skip Rate', self.skip, 1, 10000, 1) self.video_list[self.cur_video_id].setSkipRate(self.skip) def boundEnd(self): self.endIdx = self.range_slider.end() def boundStart(self): self.startIdx = self.range_slider.start() self.idx = self.startIdx def setv1(self): self.cur_video_id = 0 self.statusBar().showMessage(f'Selected Video {self.cur_video_id+1}') def setv2(self): self.cur_video_id = 1 self.statusBar().showMessage(f'Selected Video {self.cur_video_id+1}') def setv3(self): self.cur_video_id = 2 self.statusBar().showMessage(f'Selected Video {self.cur_video_id+1}') def setv4(self): self.cur_video_id = 3 self.statusBar().showMessage(f'Selected Video {self.cur_video_id+1}') def pauseTimer(self): for i in range(len(self.video_list)): self.video_list[i].pauseTimer() def stopTimer(self): for i in range(len(self.video_list)): self.video_list[i].stopTimer() def fastForward(self): for i in range(len(self.video_list)): self.video_list[i].fastForward() def slowdown(self): for i in range(len(self.video_list)): self.video_list[i].slowdown() def calibrate(self): self.video_list[self.cur_video_id].setCalibrateMode() def export(self): with open('imglist.txt', 'w') as file_list: for idx in range(self.video_list[self.cur_video_id].startIdx, len(self.video_list[self.cur_video_id].img_list), self.video_list[self.cur_video_id].skip): print( f'file \'{self.video_list[self.cur_video_id].img_list[idx]}\'', file=file_list) framerate = 1000 / self.video_list[self.cur_video_id].delay if framerate == 1: ff = FFmpeg(inputs={'imglist.txt': f'-f concat -safe 0 -r 1'}, outputs={ 'timelapse.mp4': f'-vf "fps={framerate}" -c:v libx264' }) else: ff = FFmpeg(inputs={'imglist.txt': f'-f concat -safe 0'}, outputs={ 'timelapse.mp4': f'-vf "fps={framerate}" -c:v libx264' }) print(ff.cmd) ff.run()
class RangesliderZmq(QtGui.QWidget): def __init__(self): #app = QtGui.QApplication(sys.argv) super().__init__() self.gesture_dict = GestureDict() self.port = 5556 logging.basicConfig(level=logging.DEBUG, format='%(message)s') self.initUI() #sys.exit(app.exec_()) def initUI(self): port = self.port self.create_socket(port) range_label = QtGui.QLabel('events') self.range_events = QRangeSlider() self.range_events.show() self.range_events.setFixedWidth(300) self.range_events.setFixedHeight(36) self.range_events.setMin(0) self.range_events.setMax(4) self.range_events.setRange(0, 1) self.range_events.startValueChanged.connect( lambda: self.keep_slider_min(self.range_events)) hbox_events = QtGui.QHBoxLayout() hbox_events.addWidget(range_label) hbox_events.addWidget(self.range_events) self.textbox = QtGui.QLineEdit() self.update_btn = QtGui.QPushButton("update") self.update_btn.clicked.connect(lambda: self.button_click(port)) self.update_btn.setFixedWidth(100) hbox = QtGui.QHBoxLayout() hbox.addWidget(self.update_btn) magnitude_label = QtGui.QLabel('magnitude in g/10') self.range_magnitude = QRangeSlider() self.range_magnitude.show() self.range_magnitude.setFixedWidth(300) self.range_magnitude.setFixedHeight(36) self.range_magnitude.setMin(20) self.range_magnitude.setMax(80) self.range_magnitude.setRange(20, 30) hbox_magnitude = QtGui.QHBoxLayout() hbox_magnitude.addWidget(magnitude_label) hbox_magnitude.addWidget(self.range_magnitude) self.filter_length = QRangeSlider() self.filter_length.show() self.filter_length.setFixedWidth(300) self.filter_length.setFixedHeight(36) self.filter_length.setMin(0) self.filter_length.setMax(250) self.filter_length.setRange(0, 100) self.filter_length.startValueChanged.connect( lambda: self.keep_slider_min(self.filter_length)) filter_length_label = QtGui.QLabel('filter length in samples') hbox_length = QtGui.QHBoxLayout() hbox_length.addWidget(filter_length_label) hbox_length.addWidget(self.filter_length) self.message_label = QtGui.QLabel("messages will be here") self.exit_btn = QtGui.QPushButton('exit') self.exit_btn.clicked.connect( lambda: self.exit_click(self.socket, self.context, port)) vbox = QtGui.QVBoxLayout() vbox.addStretch(1) vbox.addLayout(hbox_events) vbox.addLayout(hbox_magnitude) vbox.addLayout(hbox_length) vbox.addWidget(self.message_label) vbox.addWidget(self.update_btn) vbox.addLayout(hbox) vbox.addWidget(self.exit_btn) self.setLayout(vbox) self.setGeometry(300, 300, 300, 150) self.setWindowTitle('rangesliders') self.show() @QtCore.pyqtSlot() def button_click(self, port): ''' handle button click event ''' try: self.update_gesture_dict() message = self.gesture_dict.make_json() logging.info('rangeslider sending message {}'.format(message)) self.socket.send_json(message, flags=zmq.NOBLOCK) except zmq.error.Again as e: logging.info('no receiver for the message: {}'.format(e)) # restart the socket if nothing to receive the message # if receiver closed, the socket needs to be restarted self.close_socket() self.create_socket(port) def close_socket(self): ''' close the socket and context ''' self.socket.close() self.context.term() def create_socket(self, port): ''' create a socket using pyzmq with PAIR context ''' self.context = zmq.Context() self.socket = self.context.socket(zmq.PAIR) self.socket.setsockopt(zmq.LINGER, 0) self.socket.bind("tcp://*:%s" % port) stream_pair = zmqstream.ZMQStream(self.socket) stream_pair.on_recv(self.process_message) def exit_click(self, socket, context, port): ''' handle exit button click ''' socket.close() context.term() sys.exit() def filter_length_change(self): ''' filter length slider has changed ''' length = self.filter_length.value() self.set_message_label('filter_length: {}'.format(length)) def keep_slider_min(self, slider): ''' keep the slider length minimum as one ''' try: slider.setStart(0) except RuntimeError as e: pass self.set_message_label('cannot change this') def process_message(self, msg): time = datetime.now() time = time.strftime('%H:%M:%S') text = ('{}: {}'.format(time, msg)) self.message_label.setText(text) def set_message_label(self, text): self.message_label.setText(text) def timer_timeout(self): ''' handle the QTimer timeout ''' try: msg = self.socket.recv(flags=zmq.NOBLOCK).decode() self.process_message(msg) except zmq.error.Again as e: return def update_gesture_dict(self): ''' get status of all the rangesliders into GestureDict object ''' magnitude_min, magnitude_max = self.range_magnitude.getRange() filter_length = self.filter_length.end() events = self.range_events.end() self.gesture_dict.update_dict(magnitude_min=magnitude_min, \ magnitude_max=magnitude_max/10, events=events, \ filter_length=filter_length)
class MainWindow(QMainWindow): def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.setWindowIcon(QIcon(os.path.join(os.path.dirname(__file__), 'icons', 'plant.png'))) self.setWindowTitle("Video Comparison GUI") self.statusBar() self.img_list = None self.cur_video_id = 0 self.layout = QGridLayout() # Main Widget Init self.widget = QWidget() self.widget.setLayout(self.layout) self.setCentralWidget(self.widget) self.setGeometry(250, 50, 1920, 1080) # Open File Dialog openFile = QAction('Open Image Directory', self) openFile.setShortcut('Ctrl+O') openFile.setStatusTip('Open Image Directory') openFile.triggered.connect(self.fileDialog) change_framerate = QAction('Change Framerate...', self) change_framerate.setStatusTip('Change Playback Framerate of Video (default: 1 frame/sec)') change_framerate.triggered.connect(self.setFrameRate) change_skiprate = QAction('Change Skip Rate...', self) change_skiprate.setStatusTip('Change Frame Skip Rate in Selected Photos (default: 1)') change_skiprate.triggered.connect(self.setSkipRate) set_v_1 = QAction('Video 1...', self) set_v_1.setStatusTip('Set Video 1 (Top Left Corner) Settings') set_v_1.triggered.connect(self.setv1) set_v_2 = QAction('Video 2...', self) set_v_2.setStatusTip('Set Video 2 (Top Right Corner) Settings') set_v_2.triggered.connect(self.setv2) set_v_3 = QAction('Video 3...', self) set_v_3.setStatusTip('Set Video 3 (Bottom Left Corner) Settings') set_v_3.triggered.connect(self.setv3) set_v_4 = QAction('Video 4...', self) set_v_4.setStatusTip('Set Video 4 (Bottom Right Corner) Settings') set_v_4.triggered.connect(self.setv4) # Menu Bar menubar = self.menuBar() file_menu = menubar.addMenu('&File') file_menu.addAction(openFile) edit_menu = menubar.addMenu('&Edit') edit_menu.addAction(change_framerate) edit_menu.addAction(change_skiprate) video_menu = menubar.addMenu('&Video') video_menu.addAction(set_v_1) video_menu.addAction(set_v_2) video_menu.addAction(set_v_3) video_menu.addAction(set_v_4) # Video Frame Objects self.v1 = VideoFrame() self.layout.addWidget(self.v1, 0, 0, 1, 2) self.v2 = VideoFrame() self.layout.addWidget(self.v2, 0, 2, 1, 2) self.v3 = VideoFrame() self.layout.addWidget(self.v3, 1, 0, 1, 2) self.v4 = VideoFrame() self.layout.addWidget(self.v4, 1, 2, 1, 2) self.video_list = [self.v1, self.v2, self.v3, self.v4] ## STREAM 1 LABEL AREA #self.label = QLabel('Nothing to show right now.') #self.label.setAlignment(Qt.AlignCenter) #self.layout.addWidget(self.label) self.bottomLayout = QVBoxLayout() # GLOBAL PLAY BUTTON #self.play = QPushButton("Play") #self.play.clicked.connect(self.timerEvent) #self.bottomLayout.addWidget(self.play) # SLOWDOWN self.fr = QPushButton(self) icon = QPixmap(os.path.join(os.path.dirname(__file__), 'icons', 'fr.png')) self.fr.setIcon(QIcon(icon)) self.fr.clicked.connect(self.slowdown) self.layout.addWidget(self.fr, 2, 0, 1, 1) # GLOBAL PLAY BUTTON self.play = QPushButton(self) icon = QPixmap(os.path.join(os.path.dirname(__file__), 'icons', 'play.png')) self.play.setIcon(QIcon(icon)) self.play.clicked.connect(self.playVideos) self.layout.addWidget(self.play, 2, 1, 1, 1) # GLOBAL PAUSE BUTTON self.pause = QPushButton(self) icon = QPixmap(os.path.join(os.path.dirname(__file__), 'icons', 'pause.png')) self.pause.setIcon(QIcon(icon)) self.pause.clicked.connect(self.pauseTimer) self.layout.addWidget(self.pause, 2, 2, 1, 1) # GLOBAL FAST-FORWARD self.ff = QPushButton(self) icon = QPixmap(os.path.join(os.path.dirname(__file__), 'icons', 'ff.png')) self.ff.setIcon(QIcon(icon)) self.ff.clicked.connect(self.fastForward) self.layout.addWidget(self.ff, 2, 3, 1, 1) # GLOBAL SLIDER self.slider = QSlider(Qt.Horizontal) self.bottomLayout.addWidget(self.slider) self.slider.valueChanged.connect(self.showImage) # GLOBAL RANGE SLIDER self.range_slider = QRangeSlider() self.range_slider.setFixedHeight(20) self.bottomLayout.addWidget(self.range_slider) self.range_slider.endValueChanged.connect(self.boundEnd) self.range_slider.startValueChanged.connect(self.boundStart) self.layout.addLayout(self.bottomLayout, 3, 0, 1, 4) self.timer = QBasicTimer() # FIXME consider something with less lag self.startIdx = 0 self.idx = 0 self.delay = 1000 self.skip = 1 self.threadpool = QThreadPool() def fileDialog(self): self.img_list, _ = QFileDialog.getOpenFileNames(self, 'Select one or more files to open', '/home', 'Images (*.jpg)') self.img_list.sort() self.video_list[self.cur_video_id].setImgList(self.img_list) self.endIdx = max(self.video_list, key=lambda end: end.size()-1) self.endIdx = self.endIdx.size()-1 self.slider.setRange(0, self.endIdx) self.range_slider.setMax(self.endIdx) def playVideos(self): #v1_thread = DelayWorker(self.v1.startIdx, self.v1.endIdx, # delay=self.v1.delay, skip=self.v1.skip) #v1_thread.signals.idx.connect(self.v1.showImage) #v2_thread = DelayWorker(self.v2.startIdx, self.v2.endIdx, # delay=self.v2.delay, skip=self.v2.skip) #v2_thread.signals.idx.connect(self.v2.showImage) #v3_thread = DelayWorker(self.v3.startIdx, self.v3.endIdx, # delay=self.v3.delay, skip=self.v3.skip) #v3_thread.signals.idx.connect(self.v3.showImage) #v4_thread = DelayWorker(self.v4.startIdx, self.v4.endIdx, # delay=self.v4.delay, skip=self.v4.skip) #v4_thread.signals.idx.connect(self.v4.showImage) #self.threadpool.start(v1_thread) #self.threadpool.start(v2_thread) #self.threadpool.start(v3_thread) #self.threadpool.start(v4_thread) #self.threadpool.start(v2_thread) self.v1.timerEvent() self.v2.timerEvent() self.v3.timerEvent() self.v4.timerEvent() #self.slider.setValue(self.idx) #self.idx += self.skip def showImage(self): self.idx = self.slider.value() for i in range(len(self.video_list)): self.video_list[i].showImage(self.idx) def setFrameRate(self): delay, _ = QInputDialog.getDouble(self, 'Change Framerate...', 'New Framerate (frames/second)', 1000/self.delay, 1, 100, 1) self.delay = 1000.0/delay self.video_list[self.cur_video_id].setFrameRate(self.delay) def setSkipRate(self): self.skip, _ = QInputDialog.getInt(self, 'Change Skip Rate...', 'New Skip Rate', self.skip, 1, 100, 1) self.video_list[self.cur_video_id].setSkipRate(self.skip) def boundEnd(self): self.endIdx = self.range_slider.end() def boundStart(self): self.startIdx = self.range_slider.start() self.idx = self.startIdx def setv1(self): self.cur_video_id = 0 self.statusBar().showMessage(f'Selected Video {self.cur_video_id+1}') def setv2(self): self.cur_video_id = 1 self.statusBar().showMessage(f'Selected Video {self.cur_video_id+1}') def setv3(self): self.cur_video_id = 2 self.statusBar().showMessage(f'Selected Video {self.cur_video_id+1}') def setv4(self): self.cur_video_id = 3 self.statusBar().showMessage(f'Selected Video {self.cur_video_id+1}') def pauseTimer(self): for i in range(len(self.video_list)): self.video_list[i].pauseTimer() def fastForward(self): for i in range(len(self.video_list)): self.video_list[i].fastForward() def slowdown(self): for i in range(len(self.video_list)): self.video_list[i].slowdown()