Gebruik deze techniek om wat slimme wiskunde toe te passen op je video's en trillingen te verminderen.

Videostabilisatie is een techniek die ongewenste bewegingen en trillingen in videobeelden vermindert. Opnemen vanuit de hand, trillingen en beweging kunnen allemaal onstabiele camerabewegingen veroorzaken. Videostabilisatie produceert een vloeiender ogende video.

Het primaire doel van videostabilisatie is het schatten van de beweging van de camera tussen opeenvolgende frames. Het proces kan vervolgens de juiste transformaties toepassen om de frames uit te lijnen. Dit minimaliseert de waargenomen beweging.

Uw omgeving instellen

Start op het creëren van een virtuele omgeving om ervoor te zorgen dat de pakketten die u installeert om het programma uit te voeren niet conflicteren met bestaande pakketten. Voer vervolgens deze terminalopdracht uit om de vereiste bibliotheken te installeren:

pip installeer opencv-python numpy

Met deze opdracht worden NumPy- en OpenCV-bibliotheken geïnstalleerd. NumPy biedt tools voor numerieke taken terwijl OpenCV zich bezighoudt met computer vision-taken.

instagram viewer

De volledige broncode is beschikbaar in een GitHub-opslagplaats.

De vereiste bibliotheken importeren en drie cruciale functies definiëren

Maak een nieuw Python-bestand en geef het een naam naar keuze. Importeer NumPy- en OpenCV-bibliotheken aan het begin van het script.

importeren onnozel als np
importeren cv2

Door deze bibliotheken te importeren, kunt u hun functies in uw code gebruiken.

Definieer vervolgens drie functies die cruciaal zullen zijn voor het stabilisatieproces.

De functiecalcul_moving_average

Maak een functie aan en geef deze een naam bereken_bewegend_gemiddelde. Deze functie berekent het voortschrijdend gemiddelde van een bepaalde curve met behulp van de straal die u opgeeft. Het maakt gebruik van een convolutiebewerking met een gespecificeerde venstergrootte en een uniforme kernel. Dit voortschrijdend gemiddelde helpt fluctuaties in het traject glad te strijken.

defbereken_bewegend_gemiddelde(bocht, straal):
# Bereken het voortschrijdend gemiddelde van een curve met een gegeven straal
venstergrootte = 2 * straal + 1
kernel = np.ones (venstergrootte) / venstergrootte
curve_padded = np.lib.pad (curve, (straal, straal), 'rand')
smoothed_curve = np.convolve (curve_padded, kernel, mode='dezelfde')
smoothed_curve = smoothed_curve[radius:-radius]
opbrengst afgevlakte_kromme

De functie retourneert een vloeiende curve. Het helpt om ruis en schommelingen in de curve te verminderen. Het doet dit door het gemiddelde te nemen van de waarden binnen het schuifvenster.

De smooth_trajectory-functie

Maak een andere functie en noem deze glad_traject. Deze functie past het voortschrijdend gemiddelde toe op elke dimensie van het traject. Het zal dit bereiken door een afgevlakte kopie van het oorspronkelijke traject te maken. Dit zal de stabiliteit van de video verder verbeteren.

defglad_traject(traject):
# Maak het traject glad met voortschrijdend gemiddelde op elke dimensie
smoothed_trajectory = np.copy (traject)

voor i in bereik(3):
smoothed_trajectory[:, i] = bereken_bewegend_gemiddelde(
traject[:, ik],
radius=SMOOTHING_RADIUS
)

opbrengst smoothed_trajectory

De glad_traject functie retourneert een afgevlakte baan.

De fix_border-functie

Maak een laatste functie en noem deze fix_border. Deze functie fixeert de rand van het frame door een rotatie- en schaaltransformatie toe te passen. Het neemt het invoerframe, berekent de vorm, construeert een transformatiematrix en past de transformatie toe op het frame. Ten slotte geeft het het vaste frame terug.

deffix_border(kader):
# Corrigeer de framerand door rotatie en schaaltransformatie toe te passen
frame_shape = frame.vorm

matrix = cv2.getRotatieMatrix2D(
(kadervorm[1] / 2, kadervorm[0] / 2),
0,
1.04
)

frame = cv2.warpAffine (frame, matrix, (frame_shape[1], framevorm[0]))
opbrengst kader

De fix_border functie zorgt ervoor dat de gestabiliseerde frames geen randartefacten hebben die worden veroorzaakt door het stabilisatieproces.

Videostabilisatie initialiseren en de invoer opnemen

Begin met het instellen van de straal die de baanafvlakkingsfunctie zal gebruiken.

SMOOTHING_RADIUS = 50

Geef vervolgens het videopad door van de wankele video die u wilt stabiliseren.

# Open het invoervideobestand
# Vervang het pad door 0 om je webcam te gebruiken
cap = cv2.VideoCapture('inputvid.mp4')

Haal de eigenschappen van de wankele video op:

aantal_frames = int (cap.get (cv2.CAP_PROP_FRAME_COUNT))
breedte = int (cap.get (cv2.CAP_PROP_FRAME_WIDTH))
hoogte = int (cap.get (cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get (cv2.CAP_PROP_FPS)

Stel het uitvoerformaat in. Dit is het formaat waarin het programma de gestabiliseerde video opslaat. Je kunt elke gebruiken algemeen videoformaat je houdt van.

fourcc = cv2.VideoWriter_fourcc(*'mp4v')

Initialiseer ten slotte de videoschrijver:

uit = cv2.VideoWriter('video_out.mp4', fourcc, fps, (2 * breedte hoogte))

De extensie van de bestandsnaam die u doorgeeft aan de videoschrijver moet dezelfde zijn als degene die u instelt in het uitvoerformaat.

Frames lezen en verwerken

De eerste stap van het verwerken van de wankele video begint hier. Het omvat het lezen van frames van de invoervideo, het berekenen van transformaties en het vullen van de transformatie-array.

Begin met het lezen van het eerste frame.

_, prev_frame = cap.read()
prev_gray = cv2.cvtColor (prev_frame, cv2.COLOR_BGR2GRAY)

Initialiseer vervolgens de transformatiearray. Het slaat informatie op voor elk frame.

transformeert = np.zeros((aantal_frames - 1, 3), np.float32)

Ten slotte moet u de optische stroom tussen opeenvolgende frames berekenen. Schat vervolgens de affiene transformatie tussen de punten.

voor i in bereik (aantal_frames - 2):
# Bereken de optische stroom tussen opeenvolgende frames
prev_points = cv2.goodFeaturesToTrack(
vorige_grijs,
maxHoeken=200,
kwaliteitNiveau=0.01,
minAfstand=30,
blokgrootte=3
)

succes, curr_frame = cap.read()

alsniet succes:
pauze

curr_gray = cv2.cvtColor (curr_frame, cv2.COLOR_BGR2GRAY)

curr_points, status, err = cv2.calcOpticalFlowPyrLK(
vorige_grijs,
curr_grijs,
vorige_punten,
Geen
)

beweren prev_points.shape == curr_points.shape
idx = np.where (status == 1)[0]
vorige_punten = vorige_punten[idx]
huidige_punten = huidige_punten[idx]

# Schat affiene transformatie tussen de punten
matrix, _ = cv2.estimateAffine2D(vorige_punten, huidige_punten)
vertaling_x = matrix[0, 2]
vertaling_y = matrix[1, 2]
rotatiehoek = np.arctan2(matrix[1, 0], Matrix[0, 0])
transformeert[i] = [translation_x, translation_y, rotation_angle]
vorige_grijs = huidige_grijs

De lus herhaalt zich over elk frame (behalve het laatste frame) om transformaties te berekenen. Het berekent de optische stroom tussen opeenvolgende frames met behulp van de Lucas-Kanade-methode. cv2.goodFeaturesToTrack detecteert kenmerkpunten in het vorige frame vorige_grijs. Dan, cv2.calcOpticalFlowPyrLK volgt deze punten in het huidige frame curr_grijs.

Alleen de punten met een status van 1 (wat wijst op succesvol volgen) helpen bij het schatten van een affiene transformatiematrix. De code werkt de vorige_grijs variabele met het huidige grijswaardenframe voor de volgende iteratie.

Het traject gladstrijken

U moet het traject van de transformaties afvlakken om een ​​stabiel resultaat te bereiken.

# Bereken het traject door de transformaties cumulatief op te tellen
traject = np.cumsum (transformeert, as=0)

# Maak het traject glad met voortschrijdend gemiddelde
smoothed_trajectory = smooth_trajectory (traject)

# Bereken het verschil tussen het afgevlakte en originele traject
verschil = smoothed_trajectory - traject

# Voeg het verschil terug toe aan de originele transformaties om vloeiend te worden
# transformaties
transforms_smooth = transformeert + verschil

De bovenstaande code berekent het traject van de camerabeweging en verzacht het.

Frames stabiliseren en schrijven

De laatste stap is het stabiliseren van de frames en het schrijven van de gestabiliseerde video naar een uitvoerbestand.

Begin met het resetten van de video-opname. Dit zorgt ervoor dat toekomstige bewerkingen vanaf het begin van de video worden gelezen.

cap.set (cv2.CAP_PROP_POS_FRAMES, 0)

Stabiliseer vervolgens de video door elk frame te verwerken.

# Verwerk elk frame en stabiliseer de video
voor i in bereik (aantal_frames - 2):
succes, frame = cap.read()

alsniet succes:
pauze

translation_x = transforms_smooth[i, 0]
translation_y = transforms_smooth[i, 1]
rotatiehoek = transformeert_soepel[i, 2]

# Maak de transformatiematrix voor stabilisatie
transformatiematrix = np.nullen((2, 3), np.float32)
transformatie_matrix[0, 0] = np.cos (rotatiehoek)
transformatie_matrix[0, 1] = -np.sin (rotatiehoek)
transformatie_matrix[1, 0] = np.sin (rotatiehoek)
transformatie_matrix[1, 1] = np.cos (rotatiehoek)
transformatie_matrix[0, 2] = vertaling_x
transformatie_matrix[1, 2] = vertaling_y

# Pas de transformatie toe om het frame te stabiliseren
frame_stabilized = cv2.warpAffine(
kader,
transformatie_matrix,
(breedte hoogte)
)

# Bevestig de rand van het gestabiliseerde frame
frame_stabilized = fix_border (frame_stabilized)

# Verbind de originele en gestabiliseerde frames naast elkaar
frame_out = cv2.hconcat([frame, frame_gestabiliseerd])

# Wijzig het formaat van het frame als de breedte groter is dan 1920 pixels
als frame_out.shape[1] > 1920:
frame_out = cv2.formaat wijzigen(
frame_out,
(frame_out.shape[1] // 2, frame_out.shape[0] // 2)
)

# Geef de frames voor en na weer
cv2.imshow("Voor en na", frame_uit)
cv2.waitKey(10)

# Schrijf het frame naar het uitvoervideobestand
uit.schrijven (frame_out)

De bovenstaande code stabiliseert elk frame met behulp van de berekende transformaties, inclusief translatie- en rotatie-aanpassingen. Vervolgens combineert het de gestabiliseerde frames met de originele frames om een ​​vergelijking te maken.

De Video Capture en Writer vrijgeven

Voltooi het programma door de video-opname- en schrijfobjecten vrij te geven.

# Laat de video-opname en -schrijver los en sluit alle geopende vensters
cap.release()
uit.release()
cv2.destroyAllWindows()

Deze code sluit ook alle geopende vensters.

Definitieve programma-uitvoer

De uitvoer van het programma ziet er ongeveer zo uit:

En hier is een voorbeeld van de gestabiliseerde video:

De uitvoer toont de vergelijking tussen de wankele video en de gestabiliseerde video.

Ontdek OpenCV-mogelijkheden

U kunt OpenCV toepassen op veel gebieden die betrekking hebben op computervisie. Dit komt omdat het een breed scala aan functionaliteiten biedt. U moet de mogelijkheden ervan verkennen door aan meer projecten te werken waarbij computervisie betrokken is. Hierdoor maak je kennis met nieuwe concepten en krijg je nieuwe onderzoeksgebieden.