mirror of
https://github.com/wassname/sloth.git
synced 2026-07-16 11:21:45 +08:00
Merge branch 'frame-views'
This commit is contained in:
+185
@@ -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
|
||||
Reference in New Issue
Block a user