Dans l'article précédent (https://qiita.com/kurodae/items/ba0d1c7115d1dc9ad7cf), j'ai beaucoup écrit sur la barre de progression. Dans cet article, je vais essayer de créer moi-même quelque chose comme un lecteur vidéo. (Pas de son ...) A l'origine, Video Player fourni par kivy pour visualiser les résultats de l'analyse vidéo (détection d'objets, etc.) /api-kivy.uix.videoplayer.html), mais j'ai essayé de créer un lecteur personnalisable. Comme le titre l'indique, j'ai eu du mal à implémenter la barre de recherche pour le lecteur vidéo, donc j'écris cet article pour le partage d'informations.
Comme mentionné au début, le but est de visualiser les résultats de l'analyse vidéo, donc installez la bibliothèque opencv pour l'analyse vidéo (image).
Mon environnement d'exploitation est le suivant.
OSX 10.14.6 Python 3.7.2
Si vous utilisez pip, vous pouvez l'installer avec uniquement la commande suivante.
pip install python-opencv
Extrait de wiki Je vais.
La barre de recherche est l'une des fonctions fournies dans le logiciel de lecture de musique / vidéo, etc., et est une fonction qui affiche l'emplacement de lecture des données. Vous pouvez saisir visuellement à quelle distance vous lisez de la musique ou un film du début à la fin par la position du "curseur", vous pouvez déplacer le curseur directement avec la souris et vous pouvez commencer à jouer à partir de n'importe quel endroit Il existe des avantages tels que.
La barre de recherche est une sorte de curseur. Alors, qu'est-ce qu'un curseur? [wiki](https://ja.wikipedia.org/wiki/%E3%82%A6%E3%82%A3%E3%82%B8%E3%82%A7%E3%83%83%E3%83 Il est cité à partir de% 88_ (GUI) #% E9% 81% B8% E6% 8A% 9E).
Slider - Similaire à une barre de défilement, mais un widget utilisé pour définir une valeur, pas pour le défilement.
kivy a un widget Slider, vous pouvez donc en faire une barre de recherche.
Je me sens comme cela.
La source est la suivante.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.clock import Clock
Builder.load_string('''
<MySlider>
orientation: 'vertical'
Label :
text: "{}".format(slider.value)
font_size: slider.value
Slider:
id: slider
step: 1
min: 200
max: 500
Button:
text: "press"
on_press: root.move_slider_start()
''')
class MySlider(BoxLayout):
def __init__(self, **kwargs):
super(MySlider, self).__init__(**kwargs)
def move_slider_start(self):
Clock.schedule_interval(self.move_slider, 1 / 60)
def move_slider(self, dt):
slider = self.ids['slider']
if slider.max > slider.value:
slider.value += 1
else:
return False
class sliderTest(App):
def build(self):
return MySlider()
sliderTest().run()
La source est que la valeur du curseur est liée au texte et à la police de l'étiquette en haut de l'écran, et l'étiquette change lorsque le curseur est déplacé. J'ai également ajouté un processus pour mettre à jour en continu la valeur du curseur avec l'horloge lorsque vous appuyez sur le bouton ci-dessous (je ferai quelque chose de similaire avec le lecteur vidéo plus tard).
Dans le langage kv, le texte de l'étiquette est mis à jour à l'aide de l'ID du curseur.
Label :
text: "{}".format(slider.value)
font_size: slider.value
Slider:
id: slider #id. Il peut être appelé en langage kv ou en Python.
step: 1 #La valeur minimale lors du déplacement du curseur. Si vous ne le définissez pas, vous obtiendrez une valeur flottante foirée
min: 200 #Valeur minimale du curseur
max: 500 #Valeur maximale du curseur
De plus, dans le processus de déplacement automatique du curseur, sélectionnez le widget dans "ids" où l'id attribué au widget est stocké sous forme de tableau associatif et modifiez les paramètres comme indiqué ci-dessous. Comme dans l'article précédent, il ne peut pas être utilisé avec l'instruction for, j'ai donc modifié la valeur du curseur avec Clock et mis à jour le dessin d'écran.
def move_slider(self, dt):
slider = self.ids['slider'] #ici!
if slider.max > slider.value:
slider.value += 1
else:
return False
Ce que j'essaye de faire cette fois, c'est une image comme celle ci-dessous.
C'est comme un lecteur vidéo avec seulement les fonctionnalités minimales. Tout ce que vous avez à faire est de charger la vidéo, de la lire, de spécifier un emplacement de lecture arbitraire et de vérifier le nombre actuel d'images.
La vidéo est comme la manipulation avec opencv.
VideoApp.py
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.graphics.texture import Texture
from kivy.properties import ObjectProperty
from kivy.clock import Clock
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.popup import Popup
import cv2
Builder.load_file('VideoApp.kv')
#Pop-up de sélection de vidéo
class LoadDialog(FloatLayout):
load = ObjectProperty(None)
cancel = ObjectProperty(None)
class MyVideoPlayer(BoxLayout):
image_texture = ObjectProperty(None)
image_capture = ObjectProperty(None)
def __init__(self, **kwargs):
super(MyVideoPlayer, self).__init__(**kwargs)
self.flagPlay = False #La vidéo est-elle en cours de lecture?
self.now_frame = 0 #Variable pour vérifier l'image de lecture de la vidéo pour la barre de recherche
self.image_index = [] #Tableau pour stocker les images ouvertes pour la barre de recherche
#Pop-up pour charger la vidéo
def fileSelect(self):
content = LoadDialog(load = self.load, cancel = self.dismiss_popup)
self._popup = Popup( title="File Select", content=content, size_hint=(0.9,0.9))
self._popup.open()
#Chargement de fichiers vidéo
def load (self, path, filename):
txtFName = self.ids['txtFName']
txtFName.text = filename[0]
self.image_capture = cv2.VideoCapture(txtFName.text)
self.sliderSetting()
self.dismiss_popup()
#Fermer la fenêtre contextuelle
def dismiss_popup(self):
self._popup.dismiss()
#Paramètres de la barre de recherche
def sliderSetting(self):
count = self.image_capture.get(cv2.CAP_PROP_FRAME_COUNT)
self.ids["timeSlider"].max = count
#Chargez la vidéo une fois et enregistrez toutes les images dans un tableau
while True:
ret, frame = self.image_capture.read()
if ret:
self.image_index.append(frame)
else:
self.image_capture.set(cv2.CAP_PROP_POS_FRAMES, 0)
break
#Lecture vidéo
def play(self):
self.flagPlay = not self.flagPlay
if self.flagPlay == True:
self.image_capture.set(cv2.CAP_PROP_POS_FRAMES, self.now_frame)
Clock.schedule_interval(self.update, 1.0 / self.image_capture.get(cv2.CAP_PROP_FPS))
else:
Clock.unschedule(self.update)
#Traitement de l'horloge de lecture vidéo
def update(self, dt):
ret, frame = self.image_capture.read()
#Quand l'image suivante peut être lue
if ret:
self.update_image(frame)
time = self.image_capture.get(cv2.CAP_PROP_POS_FRAMES)
self.ids["timeSlider"].value = time
self.now_frame = int(time)
#Barre de recherche
def siderTouchMove(self):
Clock.schedule_interval(self.sliderUpdate, 0)
#Processus de dessin d'écran lorsque la barre de recherche est déplacée
def sliderUpdate(self, dt):
#Lorsque la valeur de la barre de recherche et la valeur de l'image de lecture sont différentes
if self.now_frame != int(self.ids["timeSlider"].value):
frame = self.image_index[self.now_frame-1]
self.update_image(frame)
self.now_frame = int(self.ids["timeSlider"].value)
def update_image(self, frame):
##############################
#Écrivez la source de traitement d'image ici! !!
##############################
#retourner à l'envers
buf = cv2.flip(frame, 0)
image_texture = Texture.create(size=(frame.shape[1], frame.shape[0]), colorfmt='bgr')
image_texture.blit_buffer(buf.tostring(), colorfmt='bgr', bufferfmt='ubyte')
video = self.ids['video']
video.texture = image_texture
class TestVideo(App):
def build(self):
return MyVideoPlayer()
TestVideo().run()
fichier kv
VideoApp.kv
<MyVideoPlayer>:
orientation: 'vertical'
padding: 0
spacing: 1
BoxLayout:
orientation: 'horizontal'
padding: 0
spacing: 1
size_hint: (1.0, 0.1)
TextInput:
id: txtFName
text: ''
multiline: False
Button:
text: 'file load'
on_press: root.fileSelect()
BoxLayout:
orientation: 'horizontal'
padding: 0
spacing: 1
Image:
id: video
BoxLayout:
orientation: 'horizontal'
padding: 0
spacing: 1
size_hint: (1.0, 0.1)
Slider:
id: timeSlider
value: 0.0
max: 0.0
min: 0.0
step: 1
on_touch_move: root.siderTouchMove()
BoxLayout:
orientation: 'horizontal'
padding: 0
spacing: 1
size_hint: (1.0, 0.1)
ToggleButton:
size_hint: (0.2, 1)
text: 'Play'
on_press: root.play()
Label:
size_hint: (0.2, 1)
text: str(timeSlider.value) + "/" + str(timeSlider.max)
<LoadDialog>:
BoxLayout:
size: root.size
pos: root.pos
orientation: 'vertical'
FileChooserListView:
id: filechooser
path: "./"
BoxLayout:
size_hint_y : None
height : 30
Button:
text: 'Cancel'
on_release: root.cancel()
Button:
text: 'Load'
on_release: root.load(filechooser.path, filechooser.selection)
Lorsque vous l'exécutez, vous pouvez le lire comme ceci, ou vous pouvez déplacer la barre de recherche. La vidéo a été empruntée au site ici.
La vidéo elle-même est lue à la même dose que [Video Cupture] d'opencv (http://opencv.jp/opencv-2svn/cpp/reading_and_writing_images_and_video.html). Je suis sûr que personne ne l'a utilisé, mais c'est comme lire et afficher une vidéo image par image avec une déclaration while (comme ça / python-opencv-vidéocapture-file-camera /)). Encore une fois, si vous utilisez pendant ou pendant, il gèlera, utilisez donc Clock.
#Traitement de l'horloge de lecture vidéo
def update(self, dt):
ret, frame = self.image_capture.read()
#Quand l'image suivante peut être lue
if ret:
self.update_image(frame) #Traitement pour copier à l'écran
time = self.image_capture.get(cv2.CAP_PROP_POS_FRAMES) #Obtenez le nombre d'images pour la barre de recherche
self.ids["timeSlider"].value = time #Remplacez le nombre d'images de lecture par la valeur de la barre de recherche
self.now_frame = int(time) #Pour lors du déplacement de la barre de recherche
Aussi, lors de l'affichage d'une image sur kivy, utilisez une classe appelée Texture avec
blit_buffer```. Gérez l'image comme un tampon. À ce stade, les données d'image d'opencv seront à l'envers, alors ajoutez un processus pour les inverser.
En faisant cela, vous pouvez implémenter la fonction de lecture vidéo de la même manière que la lecture vidéo openCV normale. Le traitement d'image n'est pas effectué cette fois, mais si vous ajoutez ici un traitement tel que opencv, vous pouvez facilement visualiser les résultats du traitement.
def update_image(self, frame):
##############################
#Écrivez la source de traitement d'image ici! !!
##############################
#retourner à l'envers
buf = cv2.flip(frame, 0)
image_texture = Texture.create(size=(frame.shape[1], frame.shape[0]), colorfmt='bgr')
image_texture.blit_buffer(buf.tostring(), colorfmt='bgr', bufferfmt='ubyte')
video = self.ids['video']
video.texture = image_texture
Dans la barre de recherche vidéo, initialement à partir de la fonction set (fonction qui spécifie l'image de lecture) de la classe VideoCupter d'opencv , J'essayais d'implémenter une barre de recherche en appliquant la valeur Slider au numéro d'image de la vidéo. Cependant, lorsque je l'ai mis en œuvre, l'opération est devenue extrêmement lourde. Parce que la fonction set semble être un processus très lourd, j'ai donc cherché une autre méthode d'implémentation.
En conséquence, il était possible de l'implémenter facilement en stockant les données d'image d'opencv telles qu'elles sont dans le tableau et en associant la valeur de Slider à l'indice du tableau d'images. Par conséquent, lors de la lecture d'une vidéo, un processus est fourni pour lire la vidéo une fois et l'attribuer au tableau.
Dans le programme, puisque la VideoCupture qui a été lue une fois est réutilisée, vous devez spécifier
self.image_capture.set (cv2.CAP_PROP_POS_FRAMES, 0) '' pour ramener la position de lecture de la vidéo à l'état initial. , Vous ne pourrez pas lire la vidéo.
#Paramètres de la barre de recherche
def sliderSetting(self):
count = self.image_capture.get(cv2.CAP_PROP_FRAME_COUNT) #Obtenez le nombre d'images dans une vidéo
self.ids["timeSlider"].max = count #Remplacez le nombre d'images vidéo par la valeur maximale du curseur
#Chargez la vidéo une fois et enregistrez toutes les images dans un tableau
while True:
ret, frame = self.image_capture.read()
if ret:
self.image_index.append(frame)
else:
#Après avoir lu la dernière image, revenez à la première image
self.image_capture.set(cv2.CAP_PROP_POS_FRAMES, 0)
break
Merci pour toute l'aide que vous m'avez apportée.
Comment afficher des images avec Opencv ou Pillow avec Python Kivy Manipulation de la texture, etc.
Premiers pas avec Python 7ème: Sélectionnez un fichier et lisez une vidéo - Mémo technique d'Akirachin Merci beaucoup pour la vidéo.
Recommended Posts