Files
sloth/frameviewer.py
T

203 lines
6.1 KiB
Python

#!/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.setDragMode(QGraphicsView.ScrollHandDrag)
self.setRenderHint(QPainter.Antialiasing)
self.setRenderHint(QPainter.TextAntialiasing)
self.setStyleSheet("QFrame { border: 3px solid black }");
self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
self.active_ = False
def getScale(self):
if self.isTransformed():
return self.transform().m11()
else:
return -1
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 getMinScale(self):
min_scale_w = float(self.width() - 2*self.frameWidth()) / self.scene().width()
min_scale_h = float(self.height() - 2*self.frameWidth()) / self.scene().height()
min_scale = min(min_scale_w, min_scale_h)
return min_scale
def getMaxScale(self):
max_scale_w = self.scene().height() / 5.0
max_scale_h = self.scene().width() / 5.0
max_scale = min(max_scale_w, max_scale_h)
return max_scale
def setScaleAbsolute(self, scale):
scale = max(scale, self.getMinScale())
scale = min(scale, self.getMaxScale())
self.setTransform(QTransform.fromScale(scale, scale))
self.scaleChanged.emit(self.getScale())
def setScaleRelative(self, factor):
self.setScaleAbsolute(self.getScale() * factor)
def wheelEvent(self, event):
factor = 1.41 ** (event.delta() / 240.0)
self.setScaleRelative(factor)
def focusInEvent(self, event):
self.focusIn.emit()
def resizeEvent(self, event):
if self.getScale() < self.getMinScale():
self.setScaleAbsolute(0)
if self.getScale() > self.getMaxScale():
self.setScaleAbsolute(self.getMaxScale())
QGraphicsView.resizeEvent(self, event)
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()
viewer.resize(800, 600)
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