contribution
Sortie (lorsque vous l'utilisez réellement, combinez les deux fichiers suivants avec ffmpeg ou un logiciel de montage vidéo)
 cut_movie.py
import datetime
import os
import cv2
import librosa
import numpy as np
import scipy
#Une fonction à sortir sur la console d'une manière agréable. Il ne faut pas que cela passe comme ca.
def pretty_print_sec(sec):
    int_sec = int(sec)
    hour = int_sec // 3600
    left_sec = int_sec - hour * 3600
    minute = left_sec // 60
    left_sec = left_sec - minute * 60
    hour_str = ("00" + str(hour))[-2:]
    min_str = ("00" + str(minute))[-2:]
    sec_str = ("00" + str(left_sec))[-2:]
    return ":".join([hour_str, min_str, sec_str])
#Fonction utilisée pour vérifier si le nombre cible de secondes est la cible de l'écrêtage
def is_in(tuple_list, val):
    for tup in tuple_list:
        if tup[0] <= val <= tup[1]:
            return True
    return False
#Utilisez ceci lors du recadrage basé sur la valeur maximale
def cut_by_max_rms(rms, percentile):
    is_on = False
    start = 0
    end = 0
    threshold = np.percentile(rms[0], percentile)
    cut_list = []
    #Si l'image précédente a également été sélectionnée pour le recadrage, combinez les plages de recadrage
    for i, val in enumerate(rms[0]):
        if val >= threshold and is_on:
            pass
        elif val >= threshold and not is_on:
            is_on = True
            start = float(i) * 30
        elif val < threshold and is_on:
            end = float(i) * 30
            is_on = False
            cut_list.append((start, end))
        else:
            pass
    if is_on:
        cut_list.append((start, float(i + 1) * 30))
    return cut_list
#Utilisez ceci pour la base de points maximale
def cut_by_local_max_rms(rms, max_frame_num):
    cut_list = []
    order = 1
    while True:
        pts = list(scipy.signal.argrelmax(rms[0], order=order)[0])
        if len(pts) < max_frame_num:
            break
        order += 1
    for point in pts:
        cut_list.append((point * 30, (point + 1) * 30))
    return cut_list
#Identification de l'emplacement de la découpe
#Découpez en fonction du volume
def decide_cut_frames(cut_type, voice_file):
    #Charger l'audio pour identifier les cultures
    #Je veux le rendre aussi léger que possible, donc je le lis à une fréquence d'échantillonnage de 8000
    y_voice, sr_voice = librosa.load(voice_file, sr=8000, mono=True)
    #Vérifiez le volume toutes les 30 secondes
    rms = librosa.feature.rms(
        y=y_voice,
        frame_length=sr_voice * 30,
        hop_length=sr_voice * 30,
        center=True,
        pad_mode="reflect",
    )
    if cut_type == "local_max":
        #Le volume est maximum(Où se trouve le sommet)Sélectionnez jusqu'à 20 images et découpez
        cut_list = cut_by_local_max_rms(rms, 20)
    elif cut_type == "max":
        #Top 5 des plus bruyants%Découpez le cadre de
        cut_list = cut_by_local_max_rms(rms, 100 - 95)
    return cut_list
#Recadrage vidéo
def cut_movie(cut_list, movie_file, output_movie_file):
    movie = cv2.VideoCapture(movie_file)
    fps = movie.get(cv2.CAP_PROP_FPS)
    height = movie.get(cv2.CAP_PROP_FRAME_HEIGHT)
    width = movie.get(cv2.CAP_PROP_FRAME_WIDTH)
    print(fps, int(width), int(height))
    #Format à la sortie
    #Notez que cela peut changer en fonction du système d'exploitation
    fourcc = cv2.VideoWriter_fourcc(*"mp4v")
    #S'il existe déjà, une erreur se produira, supprimez-la donc une fois.
    if os.path.exists(output_movie_file):
        os.remove(output_movie_file)
    out = cv2.VideoWriter(
        output_movie_file, fourcc, int(fps), (int(width), int(height))
    )
    for start, end in cut_list:
        i = start * fps
        movie.set(0, start * 1000)
        #Lecture image par image depuis le début et pause lorsque la fin est dépassée
        while movie.isOpened():
            sec = float(i / fps)
            if sec % 60 == 0:
                print(pretty_print_sec(sec), datetime.datetime.now(), flush=True)
            ret, frame = movie.read()
            if not ret:
                break
            #Ajouter du texte pour l'heure actuelle
            font = cv2.FONT_HERSHEY_SIMPLEX
            cv2.putText(
                frame,
                pretty_print_sec(sec),
                (10, int(height * 0.9)),
                font,
                1,
                (0, 255, 0),
                2,
                cv2.LINE_AA,
            )
            if is_in(cut_list, sec):
                out.write(frame)
            i += 1
            if sec > end:
                break
    movie.release()
    out.release()
#Recadrage audio
def cut_audio(cut_list, voice_file, output_audio_file):
    #Notez que sr sera de 22050 si None est spécifié.
    y_full, sr_full = librosa.load(voice_file, sr=None, mono=False)
    output_array = [[], []]
    for start, end in cut_list:
        for i in range(int(start * sr_full), int(end * sr_full) + 1):
            val_0 = y_full[0, i]
            val_1 = y_full[1, i]
            sec = float(i / sr_full)
            if sec % 60 == 0:
                print(pretty_print_sec(sec), datetime.datetime.now(), flush=True)
            if is_in(cut_list, sec):
                output_array[0].append(val_0)
                output_array[1].append(val_1)
            if sec > end:
                break
    #Tomber si vous n'utilisez pas asfortranarray
    librosa.output.write_wav(
        output_audio_file, np.asfortranarray(output_array), sr_full
    )
def main():
    audio_file = "full.mp3"  #Audio vidéo extrait
    voice_file = "voice.wav"  #Extrait uniquement la voix de la vidéo
    movie_file = "full.mp4"
    output_audio_file = "cut.wav"
    output_movie_file = "cut.mp4"
    cut_type = "local_max"  #Base de valeur maximale
    # cut_type = "max" #Base de valeur maximale
    cut_list = decide_cut_frames(cut_type, voice_file)
    cut_movie(cut_list, movie_file, output_movie_file)
    cut_audio(cut_list, audio_file, output_audio_file)
if __name__ == "__main__":
    main()
Recommended Posts