4 cadreur, a module for pymecavideo:
5 a program to track moving points
in a video frameset
7 Copyright (C) 2007 Jean-Baptiste Butet <ashashiwa
@gmail.com>
8 Copyright (C) 2023 Georges Khaznadar <georgesk
@debian.org>
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.
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.
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/>.
33from PyQt6.QtCore import QObject, QThread, pyqtSignal, QLocale, QTranslator, Qt, QSize, QTimer, QCoreApplication, QMetaObject
34from PyQt6.QtGui import QKeySequence, QIcon, QPixmap, QImage
35from PyQt6.QtWidgets import QVBoxLayout, QLabel, QFrame, QGridLayout, QSlider, QDialogButtonBox, QDialog
36from vecteur import vecteur
37from itertools import cycle
40class Cadreur(QObject):
42 Un objet capable de recadrer une vidéo en suivant le déplacement
44 Paramètres du constructeur :
45 @param obj le numéro de l
'objet qui doit rester immobile
46 @param app la fenêtre principale
47 @param titre le titre désiré pour la fenêtre
50 def __init__(self, obj, app, titre=None):
51 QObject.__init__(self)
54 self.
video = app.pointage.video
56 self.
titre = str(self.tr(
"Presser la touche ESC pour sortir"))
65 self.
app.dbg.p(2,
"In : Video, self.obj %s" %
67 self.
app.dbg.p(3,
"In : Video, __init__, fps = %s and delay = %s" % (
76 Renvoie l'échelle qui permet de passer de l'image dans pymecavideo
77 à l
'image effectivement trouvée dans le film, et la taille du film
78 @return un triplet échelle, largeur, hauteur (de l
'image dans le widget de de pymecavideo)
80 m = self.pointage.imageExtraite.size()
81 echx = 1.0 * m.width() / self.video.image_w
82 echy = 1.0 * m.height() / self.video.image_h
84 return ech, int(m.width() / ech), int(m.height() / ech)
88 fonction de rappel commandée par le bouton "Quitte"
90 self.ralenti = max([1, position])
94 calcule le plus grand cadre qui peut suivre le point n° obj
95 sans déborder du cadre de la vidéo. Initialise self.rayons qui indique
96 la taille de ce cadre, et self.decal qui est le décalage du point
97 à suivre par rapport au centre du cadre.
106 adroite = [w - x - 1
for x
in agauche]
107 dessous = [h - y - 1
for y
in dessus]
109 agauche = min(agauche)
110 adroite = min(adroite)
112 dessous = min(dessous)
114 self.
sz =
vecteur(adroite + agauche, dessous + dessus)
116 self.
decal =
vecteur((adroite - agauche) / 2, (dessous - dessus) / 2)
117 self.
rayons =
vecteur((agauche + adroite) / 2, (dessus + dessous) / 2)
121 récupère l'image suivante du film et traite le cas où OpenCV
125 if cv2.GrabFrame(self.
capture):
126 return cv2.RetrieveFrame(self.
capture)
129 "erreur, OpenCV 2.1 ne sait pas extraire des images du fichier", videofile)
134 Calcule et montre le film recadré à l'aide d'OpenCV
139 def rotateImage(self, img, angle):
141 return cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)
143 return cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)
145 return cv2.rotate(img, cv2.ROTATE_180)
149from interfaces.Ui_ralenti_dialog
import Ui_Dialog
as Ralenti_Dialog
153 """Affiche le film recadré"""
155 def __init__(self, parentObject):
156 QDialog.__init__(self)
157 Ralenti_Dialog.__init__(self)
163 self.ech, self.w, self.
h = self.
cadreur.echelleTaille()
164 self.
timer = QTimer()
169 self.pushButton.clicked.connect(self.reject)
171 self.label.resize(self.w, self.
h)
177 def change_ralenti(self, ralenti):
179 self.label_2.setText(self.tr(
180 "Ralenti : 1/{}".format(ralenti)))
184 """Conversion image opencv en QPixmap"""
185 rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
187 bytes_per_line = ch * w
188 convert_to_Qt_format = QImage(
189 rgb.data, w, h, bytes_per_line, QImage.Format.Format_RGB888)
190 p = convert_to_Qt_format.scaled(self.w, self.
h, Qt.AspectRatioMode.KeepAspectRatio)
191 return QPixmap.fromImage(p)
193 def affiche_image(self):
194 image_suivante = next(self.
images)
196 hautgauche = (p + self.
cadreur.decal -
197 self.
cadreur.rayons) * self.ech
198 taille = self.
cadreur.sz * self.ech
200 cv2.CAP_PROP_POS_FRAMES, image_suivante)
201 status, img = self.
cadreur.capture.read()
203 w, h = int(taille.x), int(taille.y)
204 x, y = int(hautgauche.x), int(hautgauche.y)
206 crop_img = img[y:y+h, x:x+w]
208 self.label.setPixmap(self.
toQimage(crop_img))
213 Un lecteur de vidéos qui permet d'extraire les images une par une
218 Le constructeur tente d'ouvrir le fichier video. En cas d'échec
219 la valeur booléenne de l
'instance sera False. Le test de validité est
220 isolé dans un sous-shell
221 @param filename le nom d
'un fichier vidéo
239 def __nonzero__(self):
242 def getImage(self, index, angle=0, rgb=True):
244 récupère un array numpy
245 @param index le numéro de l
'image, commence à 1.
246 @param angle 0, 90, 180 ou 270 : rotation de l
'image (0 par défaut)
247 @apame rgb (vrai par defaut) s
'il est faux l'image est au format BGR
248 @return le statut, l
'image trouvée au format d'openCV
257 self.
capture.set(cv2.CAP_PROP_POS_FRAMES, index-1)
262 if rgb: img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
268 def rotateImage(self, img, angle):
270 return cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)
272 return cv2.rotate(img, cv2.ROTATE_90_COUNTERCLOCKWISE)
274 return cv2.rotate(img, cv2.ROTATE_180)
280 Détermine les fps, le nombre de frames, la largeur, la hauteur d'un fichier vidéo
281 @return un quadruplet (framerate,nombre d
'images,la largeur, la hauteur)
284 fps = self.
capture.get(cv2.CAP_PROP_FPS)
285 fcount = self.
capture.get(cv2.CAP_PROP_FRAME_COUNT)
287 largeur = self.
capture.get(cv2.CAP_PROP_FRAME_WIDTH)
288 hauteur = self.
capture.get(cv2.CAP_PROP_FRAME_HEIGHT)
289 if angle % 180 == 90:
290 largeur, hauteur = hauteur, largeur
292 print(
"could not retrieve informations from the video file.")
293 print(
"assuming fps = 25, frame count = 10.")
294 return 25, 10, 320, 200
295 return int(fps), int(fcount), int(largeur), int(hauteur)
298 return f
"<openCvReader instance: filename={self.filename}>"
301if __name__ ==
'__main__':
302 if len(sys.argv) > 1:
303 vidfile = sys.argv[1]
305 vidfile =
'/usr/share/python-mecavideo/video/g1.avi'
308 print(
"Ouverture du fichier %s réussie" % vidfile)
310 print(
"Ouverture manquée pour le fichier %s" % vidfile)
Un objet capable de recadrer une vidéo en suivant le déplacement d'un point donné.
def montrefilm(self, fini=False)
Calcule et montre le film recadré à l'aide d'OpenCV.
def echelleTaille(self)
Renvoie l'échelle qui permet de passer de l'image dans pymecavideo à l'image effectivement trouvée da...
def controleRalenti(self, position)
fonction de rappel commandée par le bouton "Quitte"
def queryFrame(self)
récupère l'image suivante du film et traite le cas où OpenCV ne sait pas le faire
def maxcadre(self)
calcule le plus grand cadre qui peut suivre le point n° obj sans déborder du cadre de la vidéo.
Un lecteur de vidéos qui permet d'extraire les images une par une.
def __init__(self, filename)
Le constructeur tente d'ouvrir le fichier video.
def rotateImage(self, img, angle)
def recupere_avi_infos(self, angle=0)
Détermine les fps, le nombre de frames, la largeur, la hauteur d'un fichier vidéo.
def getImage(self, index, angle=0, rgb=True)
récupère un array numpy
Une classe pour accéder aux images d'un film.
une classe pour des vecteurs 2D ; les coordonnées sont flottantes, et on peut accéder à celles-ci par...