diff --git a/FrameViewer.py b/FrameViewer.py new file mode 100644 index 0000000..c597455 --- /dev/null +++ b/FrameViewer.py @@ -0,0 +1,185 @@ +#!/usr/bin/python +import sys, os, math +import okapy +import okapy.videoio +import okapy.guiqt.utilities as ogu +from PyQt4.QtCore import * +from PyQt4.QtGui import * + +videos = [] +scenes = [] + +class GraphicsView(QGraphicsView): + # Signals + scaleChanged = pyqtSignal(float) + focusIn = pyqtSignal() + + def __init__(self, parent=None): + QGraphicsView.__init__(self, parent) + self.setRenderHint(QPainter.Antialiasing) + self.setRenderHint(QPainter.TextAntialiasing) + self.setStyleSheet("QFrame { border: 3px solid black }"); + + self.current_scale_ = 1 + self.active_ = False + + def isActive(self): + return self.active_ + + def activate(self): + if not self.active_: + self.active_ = True + self.setFocus(Qt.OtherFocusReason) + self.setStyleSheet("QFrame { border: 3px solid red }"); + self.update() + + def deactivate(self): + if self.active_: + self.active_ = False + self.clearFocus() + self.setStyleSheet("QFrame { border: 3px solid black }"); + self.update() + + def setScaleRelative(self, factor): + QGraphicsView.scale(self, factor, factor) + self.current_scale_ *= factor + self.scaleChanged.emit(self.current_scale_) + # TODO: Stop at minimum scale + + def setScaleAbsolute(self, scale): + m = QMatrix() + m.scale(scale, scale) + self.current_scale_ = scale + self.setMatrix(m) + self.scaleChanged.emit(self.current_scale_) + # TODO: Stop at minimum scale + + def getScale(self): + return self.current_scale_ + + def wheelEvent(self, event): + factor = 1.41 ** (event.delta() / 240.0) + self.setScaleRelative(factor) + + def focusInEvent(self, event): + self.focusIn.emit() + + # TODO: Make window panable by CTRL-Mouse-Drag or similar + +class FrameViewer(QWidget): + # Signals + activeSceneViewChanged = pyqtSignal(GraphicsView) + + def __init__(self, parent=None): + QMainWindow.__init__(self, parent) + + def getActiveSceneView(self): + pass + + def activateNextSceneView(self): + pass + + def activatePreviousSceneView(self): + pass + + def setActiveScaleAbsolute(self, scale): + self.getActiveSceneView().setScaleAbsolute(scale) + + def setActiveScaleRelative(self, scale): + self.getActiveSceneView().setScaleRelative(scale) + +class SingleFrameViewer(FrameViewer): + def __init__(self, annotation_scene, parent=None): + FrameViewer.__init__(self, parent) + self.scene = annotation_scene + self.scene_view = GraphicsView() + self.scene_view.setScene(self.scene) + self.scene_view.activate() + self.layout = QHBoxLayout(self) + self.layout.addWidget(self.scene_view) + self.setLayout(self.layout) + + def getActiveSceneView(self): + return self.scene_view + +class MultiFrameEqualViewer(FrameViewer): + def __init__(self, annotation_scenes, parent=None): + assert(len(annotation_scenes) > 0) + FrameViewer.__init__(self, parent) + self.active_scene_view = -1 + self.scenes = annotation_scenes + self.scene_views = [] + for scene in self.scenes: + scene_view = GraphicsView() + scene_view.setScene(scene) + scene_view.focusIn.connect(self.activateFocusedSceneView) + self.scene_views.append(scene_view) + n_rows = math.ceil(math.sqrt(len(self.scene_views))) + n_cols = math.ceil(len(self.scenes) / n_rows) + self.layout = QGridLayout(self) + for i, scene_view in enumerate(self.scene_views): + self.layout.addWidget(scene_view, i/n_cols, i%n_cols) + self.setLayout(self.layout) + self.activateSceneView(0) + + def activateSceneView(self, index): + if index != self.active_scene_view: + for scene_view in self.scene_views: + scene_view.deactivate() + self.active_scene_view = index + self.scene_views[index].activate() + self.activeSceneViewChanged.emit(self.getActiveSceneView()) + + def activateFocusedSceneView(self): + sender = self.sender() + for index, scene_view in enumerate(self.scene_views): + if scene_view == sender: + self.activateSceneView(index) + + def getActiveSceneView(self): + return self.scene_views[self.active_scene_view] + +def get_dummy_scene(): + scene = QGraphicsScene() + video = okapy.videoio.FFMPEGIndexedVideoSource("/home/mfischer/data/mika_serien/COUPLING_S1_E1.vob") + video.getFrame(1000) + video.getNextFrame() + img = video.getImage() + qimg = ogu.toQImage(img, True) + scene.addPixmap(QPixmap(qimg)) + return (scene, video) + +def next_frame(): + for v in videos: + v.getNextFrame() + for v, s in zip(videos, scenes): + img = v.getImage() + qimg = ogu.toQImage(img, True) + s.clear() + s.addPixmap(QPixmap(qimg)) + +def main(): + app = QApplication(sys.argv) + + for i in range(4): + (scene, video) = get_dummy_scene() + videos.append(video) + scenes.append(scene) + + #viewer = SingleFrameViewer(scene) + viewer = MultiFrameEqualViewer(scenes) + viewer.show() + + timer = QTimer() + timer.setInterval(10) + timer.timeout.connect(next_frame) + timer.start() + + return app.exec_() + +if __name__ == '__main__': + sys.exit(main()) + +# Necessary information +# - Functionalities +# - Display zoom level