Bruk denne teknikken til å bruke litt smart matematikk på videoene dine og redusere risting.

Videostabilisering er en teknikk som reduserer uønsket bevegelse og risting i videoopptak. Håndholdt fotografering, vibrasjon og bevegelse kan alle forårsake ustødige kamerabevegelser. Videostabilisering gir en video som ser jevnere ut.

Det primære målet med videostabilisering er å estimere kameraets bevegelse mellom påfølgende bilder. Prosessen kan deretter bruke passende transformasjoner for å justere rammene. Dette minimerer den opplevde bevegelsen.

Sette opp miljøet ditt

Start med skape et virtuelt miljø for å sikre at pakkene du installerer for å kjøre programmet ikke kommer i konflikt med eksisterende. Kjør deretter denne terminalkommandoen for å installere de nødvendige bibliotekene:

pip installer opencv-python numpy

Denne kommandoen installerer NumPy- og OpenCV-biblioteker. NumPy gir verktøy for numeriske oppgaver mens OpenCV tar for seg datasynsoppgaver.

Den fullstendige kildekoden er tilgjengelig i en GitHub-depot.

Importere de nødvendige bibliotekene og definere tre viktige funksjoner

Lag en ny Python-fil og gi den et navn du liker. Importer NumPy- og OpenCV-biblioteker i begynnelsen av skriptet.

import nusset som np
import cv2

Ved å importere disse bibliotekene kan du bruke funksjonene deres i koden din.

Definer deretter tre funksjoner som vil være avgjørende for stabiliseringsprosessen.

Funksjonen calculate_moving_average

Lag en funksjon og navngi den beregne_bevegende_gjennomsnitt. Denne funksjonen vil beregne det glidende gjennomsnittet av en gitt kurve ved å bruke radiusen du spesifiserer. Den bruker en konvolusjonsoperasjon med en spesifisert vindusstørrelse og en enhetlig kjerne. Dette glidende gjennomsnittet hjelper til med å jevne ut svingninger i banen.

defberegne_bevegende_gjennomsnitt(kurve, radius):
# Beregn det glidende gjennomsnittet av en kurve ved å bruke en gitt radius
vindu_størrelse = 2 * radius + 1
kjerne = np.ones (vindusstørrelse) / vindustørrelse
curve_padded = np.lib.pad (kurve, (radius, radius), 'kant')
smoothed_curve = np.convolve (curve_padded, kernel, mode='samme')
glattet_kurve = glattet_kurve[radius:-radius]
komme tilbake glattet_kurve

Funksjonen returnerer en jevn kurve. Det bidrar til å redusere støy og svingninger i kurven. Den gjør dette ved å beregne gjennomsnittet av verdiene i skyvevinduet.

Funksjonen smooth_trajectory

Opprett en annen funksjon og navngi den glatt_bane. Denne funksjonen vil bruke det glidende gjennomsnittet på hver dimensjon av banen. Det vil oppnå dette ved å lage en glattet kopi av den originale banen. Dette vil forbedre stabiliteten til videoen ytterligere.

defglatt_bane(bane):
# Jevn ut banen ved å bruke glidende gjennomsnitt på hver dimensjon
smoothed_trajectory = np.copy (bane)

til Jeg i område(3):
smoothed_trajectory[:, i] = beregne_bevegelig_gjennomsnitt(
bane[:, i],
radius=SMOOTHING_RADIUS
)

komme tilbake smoothed_trajectory

De glatt_bane funksjonen returnerer en jevnet bane.

Funksjonen fix_border

Lag en siste funksjon og navngi den fix_border. Denne funksjonen vil fikse rammens kant ved å bruke en rotasjons- og skaleringstransformasjon. Den tar inngangsrammen, beregner formen, konstruerer en transformasjonsmatrise og bruker transformasjonen på rammen. Til slutt returnerer den den faste rammen.

deffix_border(ramme):
# Fiks rammekanten ved å bruke rotasjon og skaleringstransformasjon
frame_shape = frame.shape

matrise = cv2.getRotationMatrix2D(
(ramme_form[1] / 2, rammeform[0] / 2),
0,
1.04
)

frame = cv2.warpAffine (ramme, matrise, (ramme_form[1], rammeform[0]))
komme tilbake ramme

De fix_border funksjon sikrer at de stabiliserte rammene ikke har noen kantartefakter forårsaket av stabiliseringsprosessen.

Initialisere videostabilisering og ta inndata

Start med å stille inn radiusen som baneutjevningsfunksjonen skal bruke.

SMOOTHING_RADIUS = 50

Deretter går du inn i videobanen til den rystende videoen du vil stabilisere.

# Åpne inndatavideofilen
# Erstatt banen med 0 for å bruke webkameraet ditt
cap = cv2.VideoCapture('inputvid.mp4')

Få egenskapene til den rystende videoen:

num_frames = int (cap.get (cv2.CAP_PROP_FRAME_COUNT))
width = int (cap.get (cv2.CAP_PROP_FRAME_WIDTH))
høyde = int (cap.get (cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get (cv2.CAP_PROP_FPS)

Angi utdataformatet. Dette er formatet som programmet vil lagre den stabiliserte videoen med. Du kan bruke hvilken som helst vanlig videoformat du liker.

fourcc = cv2.VideoWriter_fourcc(*'mp4v')

Til slutt initialiserer du videoskriveren:

ut = cv2.VideoWriter('video_out.mp4', fourcc, fps, (2 * bredde høyde))

Utvidelsen av filnavnet du sender til videoskriveren skal være den samme som du angir i utdataformatet.

Lese- og bearbeidingsrammer

Det første trinnet med å behandle den rystende videoen starter her. Det innebærer å lese rammer fra inngangsvideoen, beregne transformasjoner og fylle ut transformasjonsmatrisen.

Start med å lese den første rammen.

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

Initialiser deretter transformasjonsmatrisen. Den vil lagre informasjon for hver ramme.

transforms = np.zeros((antall_frames - 1, 3), np.float32)

Til slutt må du beregne den optiske flyten mellom påfølgende rammer. Estimer deretter affin transformasjon mellom punktene.

til Jeg i område (antall_rammer - 2):
# Beregn optisk flyt mellom påfølgende bilder
prev_points = cv2.goodFeaturesToTrack(
forrige_grå,
maxCorners=200,
kvalitetsnivå=0.01,
minAvstand=30,
blokkstørrelse=3
)

suksess, curr_frame = cap.read()

hvisikke suksess:
gå i stykker

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

curr_points, status, err = cv2.calcOpticalFlowPyrLK(
forrige_grå,
curr_grey,
prev_points,
Ingen
)

hevde prev_points.shape == curr_points.shape
idx = np.where (status == 1)[0]
prev_points = prev_points[idx]
curr_points = curr_points[idx]

# Estimer affin transformasjon mellom punktene
matrise, _ = cv2.estimateAffine2D(prev_points, curr_points)
translation_x = matrise[0, 2]
translation_y = matrise[1, 2]
rotasjonsvinkel = np.arctan2(matrise[1, 0], matrise[0, 0])
transforms[i] = [translation_x, translation_y, rotation_angle]
forrige_grå = curr_grå

Sløyfen itererer over hver ramme (unntatt den siste rammen) for å beregne transformasjoner. Den beregner optisk flyt mellom påfølgende bilder ved hjelp av Lucas-Kanade-metoden. cv2.goodFeaturesToTrack oppdager funksjonspunkter i forrige bilde forrige_grå. Deretter, cv2.calcOpticalFlowPyrLK sporer disse punktene i gjeldende ramme curr_grå.

Bare punktene med status 1 (som indikerer vellykket sporing) hjelper til med å estimere en affin transformasjonsmatrise. Koden oppdaterer forrige_grå variabel med gjeldende gråtoneramme for neste iterasjon.

Utjevning av banen

Du må jevne ut banen oppnådd fra transformasjonene for å oppnå et stabilt resultat.

# Beregn banen ved å summere transformasjonene kumulativt
bane = np.cumsum (transformeres, akse=0)

# Jevn ut banen ved å bruke glidende gjennomsnitt
smoothed_trajectory = smooth_trajectory (bane)

# Beregn forskjellen mellom den utjevnede og opprinnelige banen
forskjell = glattet_bane - bane

# Legg forskjellen tilbake til de opprinnelige transformasjonene for å oppnå jevn
# transformasjoner
transforms_smooth = transformerer + forskjell

Koden ovenfor beregner banen til kamerabevegelsen og jevner den ut.

Stabiliserende og skriverammer

Det siste trinnet er å stabilisere rammene og skrive den stabiliserte videoen inn i en utdatafil.

Start med å tilbakestille videoopptaket. Dette sikrer at fremtidige operasjoner vil leses fra starten av videoen.

cap.set (cv2.CAP_PROP_POS_FRAMES, 0)

Deretter stabiliseres videoen ved å behandle hvert bilde.

# Behandle hvert bilde og stabiliser videoen
til Jeg i område (antall_rammer - 2):
suksess, ramme = cap.read()

hvisikke suksess:
gå i stykker

translation_x = transforms_smooth[i, 0]
translation_y = transforms_smooth[i, 1]
rotasjonsvinkel = transformerer_glatt[i, 2]

# Lag transformasjonsmatrisen for stabilisering
transformasjonsmatrise = np.null((2, 3), np.float32)
transformasjonsmatrise[0, 0] = np.cos (rotasjonsvinkel)
transformasjonsmatrise[0, 1] = -np.sin (rotasjonsvinkel)
transformasjonsmatrise[1, 0] = np.sin (rotasjonsvinkel)
transformasjonsmatrise[1, 1] = np.cos (rotasjonsvinkel)
transformasjonsmatrise[0, 2] = translation_x
transformasjonsmatrise[1, 2] = translation_y

# Bruk transformasjonen for å stabilisere rammen
frame_stabilized = cv2.warpAffine(
ramme,
transformasjonsmatrise,
(bredde høyde)
)

# Fest kanten på den stabiliserte rammen
frame_stabilized = fix_border (ramme_stabilisert)

# Slå sammen de originale og stabiliserte rammene side om side
frame_out = cv2.hconcat([ramme, rammestabilisert])

# Endre størrelsen på rammen hvis bredden overstiger 1920 piksler
hvis frame_out.shape[1] > 1920:
frame_out = cv2.resize(
frame_out,
(ramme_ut.form[1] // 2, frame_out.shape[0] // 2)
)

# Vis før- og etterrammene
cv2.imshow("Før og etter", frame_out)
cv2.waitKey(10)

# Skriv rammen til utgangsvideofilen
out.write (frame_out)

Koden ovenfor stabiliserer hver ramme ved å bruke de beregnede transformasjonene, inkludert translasjons- og rotasjonsjusteringer. Den kombinerer deretter de stabiliserte rammene med de originale for å gi en sammenligning.

Slipper Video Capture and Writer

Fullfør programmet ved å frigjøre videoopptak og skriveobjekter.

# Slipp videoopptaket og skriveren, og lukk alle åpne vinduer
cap.release()
out.release()
cv2.destroyAllWindows()

Denne koden lukker også alle åpne vinduer.

Endelig programutgang

Utgangen av programmet vil se omtrent slik ut:

Og her er et eksempel på den stabiliserte videoen:

Utgangen viser sammenligningen mellom den ustø videoen og den stabiliserte.

Utforsk OpenCV-funksjonene

Du kan bruke OpenCV på mange felt som involverer datasyn. Dette er fordi det tilbyr et bredt spekter av funksjoner. Du bør utforske dens evner ved å jobbe med flere prosjekter som involverer datasyn. Dette vil introdusere deg for nye konsepter og gi deg nye områder å forske på.