mirror of
https://github.com/wassname/sloth.git
synced 2026-06-30 03:30:39 +08:00
186 lines
5.4 KiB
Python
186 lines
5.4 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.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
|