Använd den här tekniken för att tillämpa lite smart matematik på dina videor och minska skakningar.
Videostabilisering är en teknik som minskar oönskade rörelser och skakningar i videofilmer. Handhållen fotografering, vibrationer och rörelser kan alla orsaka ostadiga kamerarörelser. Videostabilisering ger en video som ser mjukare ut.
Det primära målet med videostabilisering är att uppskatta kamerans rörelse mellan på varandra följande bildrutor. Processen kan sedan tillämpa lämpliga transformationer för att rikta in ramarna. Detta minimerar den upplevda rörelsen.
Ställa in din miljö
Börja med skapa en virtuell miljö för att säkerställa att paketen du installerar för att köra programmet inte kommer i konflikt med befintliga. Kör sedan det här terminalkommandot för att installera de nödvändiga biblioteken:
pip installera opencv-python numpy
Detta kommando installerar NumPy- och OpenCV-bibliotek. NumPy tillhandahåller verktyg för numeriska uppgifter medan OpenCV hanterar datorseende uppgifter.
Den fullständiga källkoden finns tillgänglig i en GitHub-förråd.
Importera de obligatoriska biblioteken och definiera tre viktiga funktioner
Skapa en ny Python-fil och ge den ett namn som du gillar. Importera NumPy- och OpenCV-bibliotek i början av skriptet.
importera numpy som np
importera cv2
Genom att importera dessa bibliotek kan du använda deras funktioner i din kod.
Därefter definierar du tre funktioner som kommer att vara avgörande för stabiliseringsprocessen.
Funktionen calculate_moving_average
Skapa en funktion och namnge den beräkna_rörligt_medelvärde. Denna funktion kommer att beräkna det glidande medelvärdet för en given kurva med hjälp av den radie du anger. Den använder en faltningsoperation med en specificerad fönsterstorlek och en enhetlig kärna. Detta glidande medelvärde hjälper till att jämna ut fluktuationer i banan.
defberäkna_rörligt_medelvärde(kurva, radie):
# Beräkna det glidande medelvärdet för en kurva med hjälp av en given radie
fönsterstorlek = 2 * radie + 1
kärna = np.ones (fönsterstorlek) / fönsterstorlek
curve_padded = np.lib.pad (kurva, (radie, radie), 'kant')
smoothed_curve = np.convolve (curve_padded, kernel, mode='samma')
smoothed_curve = smoothed_curve[radius:-radius]
lämna tillbaka smoothed_curve
Funktionen returnerar en jämn kurva. Det hjälper till att minska buller och svängningar i kurvan. Den gör detta genom att beräkna ett medelvärde för värdena i det skjutbara fönstret.
Funktionen smooth_trajectory
Skapa en annan funktion och namnge den smooth_trajectory. Denna funktion kommer att tillämpa det glidande medelvärdet på varje dimension av banan. Det kommer att uppnå detta genom att skapa en utjämnad kopia av den ursprungliga banan. Detta kommer att förbättra stabiliteten i videon ytterligare.
defsmooth_trajectory(bana):
# Jämna ut banan med glidande medelvärde för varje dimension
smoothed_trajectory = np.copy (bana)för i i räckvidd(3):
smoothed_trajectory[:, i] = calculate_moving_average(
bana[:, i],
radie=SMOOTHING_RADIUS
)
lämna tillbaka smoothed_trajectory
De smooth_trajectory funktion returnerar en utjämnad bana.
Funktionen fix_border
Skapa en sista funktion och namnge den fix_border. Den här funktionen fixar ramens kant genom att tillämpa en rotations- och skalomvandling. Den tar ingångsramen, beräknar dess form, konstruerar en transformationsmatris och tillämpar transformationen på ramen. Slutligen returnerar den den fasta ramen.
deffix_border(ram):
# Fixa ramkanten genom att tillämpa rotation och skala transformation
ram_form = ram.form
matrix = cv2.getRotationMatrix2D(
(ramform[1] / 2, ramform[0] / 2),
0,
1.04
)
ram = cv2.warpAffine (ram, matris, (ramform[1], ramform[0]))
lämna tillbaka ram
De fix_border funktionen säkerställer att de stabiliserade ramarna inte har några kantartefakter orsakade av stabiliseringsprocessen.
Initiera videostabilisering och ta indata
Börja med att ställa in radien som banutjämningsfunktionen ska använda.
SMOOTHING_RADIUS = 50
Gå sedan in i videobanan för den skakiga video du vill stabilisera.
# Öppna ingångsvideofilen
# Ersätt sökvägen med 0 för att använda din webbkamera
cap = cv2.VideoCapture('inputvid.mp4')
Hämta den skakiga videons egenskaper:
num_frames = int (cap.get (cv2.CAP_PROP_FRAME_COUNT))
bredd = int (cap.get (cv2.CAP_PROP_FRAME_WIDTH))
höjd = int (cap.get (cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get (cv2.CAP_PROP_FPS)
Ställ in utdataformatet. Detta är formatet som programmet kommer att spara den stabiliserade videon med. Du kan använda vilken som helst vanligt videoformat du gillar.
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
Initiera slutligen videoskrivaren:
ut = cv2.VideoWriter('video_out.mp4', fourcc, fps, (2 * bredd höjd))
Förlängningen av filnamnet du skickar till videoskrivaren bör vara densamma som den du ställer in i utdataformatet.
Läs- och bearbetningsramar
Det första steget med att bearbeta den skakiga videon börjar här. Det involverar att läsa ramar från ingångsvideon, beräkna transformationer och fylla i transformationsmatrisen.
Börja med att läsa den första ramen.
_, prev_frame = cap.read()
prev_gray = cv2.cvtColor (prev_frame, cv2.COLOR_BGR2GRAY)
Initiera sedan transformationsmatrisen. Den lagrar information för varje bildruta.
transforms = np.zeros((antal_frames - 1, 3), np.float32)
Slutligen måste du beräkna det optiska flödet mellan på varandra följande ramar. Uppskatta sedan affin transformation mellan punkterna.
för i i intervall (antal_frames - 2):
# Beräkna optiskt flöde mellan på varandra följande ramar
prev_points = cv2.goodFeaturesToTrack(
prev_grey,
maxCorners=200,
kvalitetsnivå=0.01,
minAvstånd=30,
blockSize=3
)framgång, curr_frame = cap.read()
ominte Framgång:
ha söndercurr_gray = cv2.cvtColor (curr_frame, cv2.COLOR_BGR2GRAY)
curr_points, status, err = cv2.calcOpticalFlowPyrLK(
prev_grey,
curr_gray,
prev_points,
Ingen
)hävda prev_points.shape == curr_points.shape
idx = np.where (status == 1)[0]
prev_points = prev_points[idx]
curr_points = curr_points[idx]
# Uppskatta affin transformation mellan punkterna
matris, _ = cv2.estimateAffine2D(prev_points, curr_points)
translation_x = matris[0, 2]
translation_y = matris[1, 2]
rotationsvinkel = np.arctan2(matris[1, 0], matris[0, 0])
transforms[i] = [translation_x, translation_y, rotation_angle]
prev_gray = curr_gray
Slingan itererar över varje bildruta (förutom den sista bildrutan) för att beräkna transformationer. Den beräknar optiskt flöde mellan på varandra följande ramar med hjälp av Lucas-Kanade-metoden. cv2.goodFeaturesToTrack upptäcker funktionspunkter i föregående bildruta prev_grå. Sedan, cv2.calcOpticalFlowPyrLK spårar dessa punkter i den aktuella bildrutan curr_grå.
Endast punkterna med statusen 1 (indikerar framgångsrik spårning) hjälper till att uppskatta en affin transformationsmatris. Koden uppdaterar prev_grå variabel med den aktuella gråskaleramen för nästa iteration.
Jämna ut banan
Du måste jämna ut banan som erhålls från transformationerna för att uppnå ett stabilt resultat.
# Beräkna banan genom att kumulativt summera transformationerna
bana = np.cumsum (transformers, axel=0)# Jämna ut banan med glidande medelvärde
smoothed_trajectory = smooth_trajectory (bana)# Beräkna skillnaden mellan den utjämnade och den ursprungliga banan
skillnad = smoothed_trajectory - bana
# Lägg tillbaka skillnaden till de ursprungliga transformationerna för att få jämn
# transformationer
transforms_smooth = transformerar + skillnad
Ovanstående kod beräknar banan för kamerarörelsen och jämnar ut den.
Stabilisera och skriva ramar
Det sista steget är att stabilisera bildrutorna och skriva den stabiliserade videon till en utdatafil.
Börja med att återställa videoinspelningen. Detta säkerställer att framtida operationer kommer att läsas från början av videon.
cap.set (cv2.CAP_PROP_POS_FRAMES, 0)
Stabilisera sedan videon genom att bearbeta varje bildruta.
# Bearbeta varje bildruta och stabilisera videon
för i i intervall (antal_frames - 2):
framgång, ram = cap.read()ominte Framgång:
ha söndertranslation_x = transforms_smooth[i, 0]
translation_y = transforms_smooth[i, 1]
rotationsvinkel = transformerar_slät[i, 2]# Skapa transformationsmatrisen för stabilisering
transformation_matrix = np.zeros((2, 3), np.float32)
transformation_matrix[0, 0] = np.cos (rotationsvinkel)
transformation_matrix[0, 1] = -np.sin (rotationsvinkel)
transformation_matrix[1, 0] = np.sin (rotationsvinkel)
transformation_matrix[1, 1] = np.cos (rotationsvinkel)
transformation_matrix[0, 2] = translation_x
transformation_matrix[1, 2] = translation_y# Använd transformationen för att stabilisera ramen
frame_stabilized = cv2.warpAffine(
ram,
transformation_matrix,
(bredd höjd)
)# Fixa kanten på den stabiliserade ramen
frame_stabilized = fix_border (frame_stabilized)# Sammanfoga original och stabiliserade ramar sida vid sida
frame_out = cv2.hconcat([frame, frame_stabilized])# Ändra storlek på ramen om dess bredd överstiger 1920 pixlar
om frame_out.shape[1] > 1920:
frame_out = cv2.resize(
frame_out,
(frame_out.shape[1] // 2, frame_out.shape[0] // 2)
)# Visa före- och efterramarna
cv2.imshow("Före och efter", frame_out)
cv2.waitKey(10)
# Skriv ramen till utdatavideofilen
out.write (frame_out)
Ovanstående kod stabiliserar varje ram med hjälp av de beräknade transformationerna, inklusive translations- och rotationsjusteringar. Den kombinerar sedan de stabiliserade ramarna med de ursprungliga för att ge en jämförelse.
Släpp Video Capture and Writer
Slutför programmet genom att släppa videoinspelnings- och skrivobjekten.
# Släpp videoinspelningen och skrivaren och stäng alla öppna fönster
cap.release()
out.release()
cv2.destroyAllWindows()
Denna kod stänger också alla öppna fönster.
Slutlig programutgång
Utdata från programmet kommer att se ut ungefär så här:
Och här är ett exempel på den stabiliserade videon:
Utdata visar jämförelsen mellan den skakiga videon och den stabiliserade.
Utforska OpenCV-funktioner
Du kan tillämpa OpenCV inom många områden som involverar datorseende. Detta beror på att den erbjuder ett brett utbud av funktioner. Du bör utforska dess kapacitet genom att arbeta med fler projekt som involverar datorseende. Detta kommer att introducera dig till nya koncept och ge dig nya områden att forska om.