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 stykkercurr_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 stykkertranslation_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å.