Pymecavideo 8.0
Étude cinématique à l'aide de vidéos
videoWidget.py
1# -*- coding: utf-8 -*-
2
3"""
4 videoWidget, a module for pymecavideo:
5 a program to track moving points in a video frameset
6
7 Copyright (C) 2007 Jean-Baptiste Butet <ashashiwa@gmail.com>
8 Copyright (C) 2023 Georges Khaznadar <georgesk@debian.org>
9
10 This program is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
22"""
23
24from PyQt6.QtCore import QThread, pyqtSignal, QLocale, QTranslator, Qt, \
25 QSize, QTimer, QObject, QRect, QPoint, QPointF
26from PyQt6.QtGui import QKeySequence, QIcon, QPixmap, QImage, QPainter, \
27 QCursor, QPen, QColor, QFont, QResizeEvent, QShortcut
28from PyQt6.QtWidgets import QApplication, QMainWindow, QWidget, QLayout, \
29 QFileDialog, QTableWidgetItem, QInputDialog, QLineEdit, QMessageBox, \
30 QTableWidgetSelectionRange
31
32import os, time, re
33import locale
34
35from version import Version
36from vecteur import vecteur
37from echelle import Echelle_TraceWidget
38from image_widget import ImageWidget
39from globdef import cible_icon, DOCUMENT_PATH, inhibe
40from cadreur import openCvReader
41from toQimage import toQImage
42
43import interfaces.icon_rc
44
46 """
47 Cette classe permet de gérer une séquence d'images extraites d'une vidéo
48 et les pointages qu'on peut réaliser à la souris ou automatiquement,
49 pour suivre les mouvements d'un ou plusieurs objets.
50 """
51
52 def __init__(self, parent):
53 ImageWidget.__init__(self, parent)
54 self.setMouseTracking(True) # on réagit aux mouvement de souris
55 self.index = None # index de l'image courante
56 self.objet_courant = 1 # désignation de l'objet courant
57 self.image_w = self.width() # deux valeurs par défaut
58 self.image_h = self.height() # pas forcément pertinentes
59 self.rotation = 0 # permet de retourner une vidéo mal prise
60 self.setMouseTracking(True)
61 self.couleurs = [
62 "red", "blue", "cyan", "magenta", "yellow", "gray", "green"] *2
63 return
64
65
66 def __str__(self):
67 """
68 donne une vision partielle de l'instance courante
69 """
70 result = {a : str(getattr(self,a)) for a in dir(self) \
71 if not callable(getattr(self,a)) and \
72 not isinstance(getattr(self,a), QObject)}
73
74 return f"VideoPointeeWidget({result})"
75
76 def setParent(self, w):
77 """
78 Connecte le videoWidget au widget principal de son onglet,
79 et son débogueur ; self.pw devient un pointeur vers ce widget
80 @param w le widget principal de l'onglet de pointage
81 """
82 self.pw = w
83 self.dbg = w.dbg
84 return
85
86 def clear(self):
87 self.imageimage = None
88 return
89
90 def resizeEvent(self, e):
91 self.dbg.p(2, "rentre dans 'resizeEvent'")
92 self.pw.update_imgedit.emit(
93 self.image_w, self.image_h, self.rotation)
94 if e.oldSize() != QSize(-1, -1):
95 ratiow = self.width()/e.oldSize().width()
96 ratioh = self.height()/e.oldSize().height()
97 self.pw.update_origine.emit(ratiow, ratioh)
98 return
99
100 def mouseReleaseEvent(self, event):
101 """
102 enregistre le point de l'évènement souris, si self.pointageOK
103 est vrai ; voir self.extract_image pour voir les conditions
104 de validité.
105
106 Si self.refait_point est vrai (on a été délégué depuis un
107 bouton refaire, du tableau de coordonnées, alors on rebascule
108 éventuellement vers l'onglet coordonnées, quand le dernier
109 objet a été pointé.
110 """
111 if event.button() == Qt.MouseButton.LeftButton:
112 self.pw.fin_pointage_manuel.emit(event)
113 return
114
115 def mouseMoveEvent(self, event):
116 self.pw.update_zoom.emit(vecteur(qPoint = event.position()))
117 return
118
119 def paintEvent(self, event):
120 if self.imageimage:
121 painter = QPainter()
122 painter.begin(self)
123 ############################################################
124 # mise en place de l'image
125 if self.imageimage is not None: painter.drawPixmap(0, 0, self.imageimage)
126
127 ############################################################
128 # dessine les pointages passés
129 self.dbg.p(
130 5, "In videoWidget, paintEvent, self.pw.data :%s" % self.pw.data)
131 if self.pw.data:
132 for date in self.pw.data:
133 for obj in self.pw.data[date]:
134 point = self.pw.data[date][obj]
135 if point:
136 painter.setPen(QColor(self.couleurs[int(obj)-1]))
137 painter.setFont(QFont("", 10))
138 painter.translate(point.x, point.y)
139 painter.drawLine(-2, 0, 2, 0)
140 painter.drawLine(0, -2, 0, 2)
141 painter.translate(-10, +10)
142 painter.drawText(0, 0, str(obj))
143 painter.translate(-point.x + 10, -point.y - 10)
144
145 ############################################################
146 # dessine le repere
147 painter.setPen(QColor("green"))
148 painter.drawText(
149 round(self.pw.origine.x) + 5, round(self.pw.origine.y) + 15, "O")
150 painter.translate(0, 0)
151 painter.translate(round(self.pw.origine.x), round(self.pw.origine.y))
152 p1 = QPoint(round(self.pw.sens_X * (-40)), 0)
153 p2 = QPoint(round(self.pw.sens_X * (40)), 0)
154 p3 = QPoint(round(self.pw.sens_X * (36)), 2)
155 p4 = QPoint(round(self.pw.sens_X * (36)), -2)
156 painter.scale(1, 1)
157 painter.drawPolyline(p1, p2, p3, p4, p2)
158 painter.rotate(self.pw.sens_X * self.pw.sens_Y * (-90))
159 painter.drawPolyline(p1, p2, p3, p4, p2)
160 painter.end()
161 return
162
163 def entete_fichier(self, msg=""):
164 """
165 Crée l'en-tête du fichier pymecavideo
166 On recopie sous forme de commentaires préfixée par "# "
167 tout le fichier de configuration sauf la ligne "[DEFAULT]"
168 puis on ajoute le message
169 @param msg le message
170 @return le texte de l'en-tête (multi-ligne)
171 """
172 self.dbg.p(2, "rentre dans 'entete_fichier'")
173 config = open(self.pw.prefs.conffile).readlines()
174 return "".join(["# "+l for l in config[1:]]) + "# " + msg + "\n"
175
176 def placeImage(self, im, ratio, largeurFilm):
177 """
178 place une image dans le widget, en conservant le ratio de cette image
179 @param im une image
180 @param ratio le ratio à respecter
181 @param largeurFilm la largeur originale de la video en pixel
182 @return l'image, redimensionnée selon le ratio
183 """
184 self.dbg.p(2, "rentre dans 'placeImage'")
185 self.image_w = min(self.width(), round(self.height() * ratio))
186 self.image_h = round(self.image_w / ratio)
187 self.echelle = self.image_w / largeurFilm
188 self.setMouseTracking(True)
189 image = im.scaled(self.image_w, self.image_h)
190 self.setImage(image)
191 return image
192
Un widget contenant une image.
Definition: image_widget.py:33
def setImage(self, image=None)
définit l'image de fond
Definition: image_widget.py:42
une classe pour des vecteurs 2D ; les coordonnées sont flottantes, et on peut accéder à celles-ci par...
Definition: vecteur.py:44
Cette classe permet de gérer une séquence d'images extraites d'une vidéo et les pointages qu'on peut ...
Definition: videoWidget.py:50
def placeImage(self, im, ratio, largeurFilm)
place une image dans le widget, en conservant le ratio de cette image
Definition: videoWidget.py:183
def entete_fichier(self, msg="")
Crée l'en-tête du fichier pymecavideo On recopie sous forme de commentaires préfixée par "# " tout le...
Definition: videoWidget.py:171
def setParent(self, w)
Connecte le videoWidget au widget principal de son onglet, et son débogueur ; self....
Definition: videoWidget.py:81
def __str__(self)
donne une vision partielle de l'instance courante
Definition: videoWidget.py:69
def mouseReleaseEvent(self, event)
enregistre le point de l'évènement souris, si self.pointageOK est vrai ; voir self....
Definition: videoWidget.py:110