השתמש בטכניקה זו כדי ליישם קצת מתמטיקה חכמה על הסרטונים שלך ולהפחית רעידות.

ייצוב וידאו הוא טכניקה המפחיתה תנועה ורעידות לא רצויות בצילומי וידאו. צילום כף יד, רטט ותנועה עלולים לגרום לתנועות מצלמה לא יציבות. ייצוב וידאו מייצר סרטון חלק יותר למראה.

המטרה העיקרית של ייצוב וידאו היא להעריך את תנועת המצלמה בין פריימים עוקבים. לאחר מכן, התהליך יכול להחיל טרנספורמציות מתאימות כדי ליישר את המסגרות. זה ממזער את התנועה הנתפסת.

הגדרת הסביבה שלך

התחל ב יצירת סביבה וירטואלית כדי להבטיח שהחבילות שאתה מתקין להפעלת התוכנית אינן מתנגשות עם החבילות הקיימות. לאחר מכן הפעל את פקודת הטרמינל הזו כדי להתקין את הספריות הנדרשות:

pip להתקין opencv-python numpy

פקודה זו מתקינה ספריות NumPy ו-OpenCV. NumPy מספקת כלים למשימות מספריות ואילו OpenCV עוסק במשימות ראייה ממוחשבת.

קוד המקור המלא זמין ב-a מאגר GitHub.

ייבוא ​​הספריות הנדרשות והגדרת שלוש פונקציות חיוניות

צור קובץ Python חדש ותן לו שם לטעמך. ייבא ספריות NumPy ו-OpenCV בתחילת הסקריפט.

יְבוּא רדום כפי ש np
יְבוּא cv2

ייבוא ​​ספריות אלה יאפשר לך להשתמש בפונקציות שלהן בקוד שלך.

instagram viewer

לאחר מכן, הגדר שלוש פונקציות שיהיו קריטיות לתהליך הייצוב.

הפונקציה calculate_moving_average

צור פונקציה ושמה לה חשב_ממוצע_נע. פונקציה זו תחשב את הממוצע הנע של עקומה נתונה באמצעות הרדיוס שתציין. הוא משתמש בפעולת קונבולציה עם גודל חלון מוגדר וקרנל אחיד. ממוצע נע זה עוזר להחליק את התנודות במסלול.

defחשב_ממוצע_נע(עקומה, רדיוס):
# חשב את הממוצע הנע של עקומה באמצעות רדיוס נתון
window_size = 2 *רדיוס + 1
kernel = np.ones (window_size) / window_size
curve_padded = np.lib.pad (עקומה, (רדיוס, רדיוס), 'קָצֶה')
smoothed_curve = np.convolve (curve_padded, kernel, mode='אותו')
עקומת_חלקה = עקומת_חלקה[radius:-radius]
לַחֲזוֹר עקומה_מוחלקת

הפונקציה מחזירה עקומה חלקה. זה עוזר להפחית רעש ותנודות בעקומה. זה עושה זאת על ידי ממוצע של הערכים בחלון ההזזה.

פונקציית החלק_מסלול

צור פונקציה נוספת ושמה לה חלק_מסלול. פונקציה זו תחיל את הממוצע הנע על כל מימד של המסלול. זה ישיג זאת על ידי יצירת עותק מוחלק של המסלול המקורי. זה ישפר עוד יותר את היציבות של הסרטון.

defחלק_מסלול(מַסלוּל):
# החלק את המסלול באמצעות ממוצע נע בכל מימד
smoothed_trajectory = np.copy (מסלול)

ל אני ב טווח(3):
smoothed_trajectory[:, i] = calculate_moving_average(
מסלול[:,i],
radius=SMOOTHING_RADIUS
)

לַחֲזוֹר מסלול_מוחלק

ה חלק_מסלול הפונקציה מחזירה מסלול מוחלק.

הפונקציה fix_border

צור פונקציה אחרונה ושמה לה fix_border. פונקציה זו תתקן את הגבול של המסגרת על ידי החלת סיבוב ושינוי קנה מידה. הוא לוקח את מסגרת הקלט, מחשב את צורתו, בונה מטריצת טרנספורמציה ומחיל את הטרנספורמציה על המסגרת. לבסוף, הוא מחזיר את המסגרת הקבועה.

deffix_border(מִסגֶרֶת):
# תקן את גבול המסגרת על ידי החלת סיבוב ושינוי קנה מידה
frame_shape = frame.shape

matrix = cv2.getRotationMatrix2D(
(צורת_מסגרת[1] / 2, צורת_מסגרת[0] / 2),
0,
1.04
)

frame = cv2.warpAffine (מסגרת, מטריצה, (frame_shape[1], צורת_מסגרת[0]))
לַחֲזוֹר מִסגֶרֶת

ה fix_border הפונקציה מבטיחה שלמסגרות המיוצבות אין חפצי גבול הנגרמים מתהליך הייצוב.

אתחול ייצוב וידאו וקבלת הקלט

התחל על ידי הגדרת הרדיוס שבו תשתמש פונקציית החלקת המסלול.

SMOOTHING_RADIUS = 50

לאחר מכן, עברו בנתיב הווידאו של הסרטון המטלטל שברצונכם לייצב.

# פתח את קובץ וידאו הקלט
# החלף את הנתיב ב-0 כדי להשתמש במצלמת האינטרנט שלך
cap = cv2.VideoCapture('inputvid.mp4')

קבלו את המאפיינים של הסרטון המטלטל:

num_frames = int (cap.get (cv2.CAP_PROP_FRAME_COUNT))
רוחב = int (cap.get (cv2.CAP_PROP_FRAME_WIDTH))
גובה = int (cap.get (cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get (cv2.CAP_PROP_FPS)

הגדר את פורמט הפלט. זהו הפורמט שבו התוכנית תשמור את הסרטון המיוצב איתו. אתה יכול להשתמש בכל פורמט וידאו נפוץ אתה אוהב.

fourcc = cv2.VideoWriter_fourcc(*'mp4v')

לבסוף, אתחל את כותב הסרטון:

out = cv2.VideoWriter('video_out.mp4', fourcc, fps, (2 * רוחב גובה))

הסיומת של שם הקובץ שתעביר לכותב הווידאו צריכה להיות זהה לזה שהגדרת בפורמט הפלט.

מסגרות קריאה ועיבוד

השלב הראשון בעיבוד הסרטון המטלטל מתחיל כאן. זה כולל קריאת מסגרות מסרטון הקלט, חישוב טרנספורמציות ואכלוס מערך ההמרות.

התחל בקריאת המסגרת הראשונה.

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

לאחר מכן אתחול מערך הטרנספורמציה. זה יאחסן מידע עבור כל מסגרת.

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

לבסוף, אתה צריך לחשב את הזרימה האופטית בין מסגרות עוקבות. לאחר מכן, הערך טרנספורמציה אפינית בין הנקודות.

ל אני ב טווח (מספר_פריימים - 2):
# חשב זרימה אופטית בין פריימים עוקבים
prev_points = cv2.goodFeaturesToTrack(
prev_grey,
maxCorners=200,
qualityLevel=0.01,
minDistance=30,
blockSize=3
)

success, curr_frame = cap.read()

אםלֹא הַצלָחָה:
לשבור

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

curr_points, status, err = cv2.calcOpticalFlowPyrLK(
prev_grey,
curr_grey,
prev_points,
אף אחד
)

לִטעוֹן prev_points.shape == curr_points.shape
idx = np.where (סטטוס == 1)[0]
prev_points = prev_points[idx]
curr_points = curr_points[idx]

# אומדן טרנספורמציה אפינית בין הנקודות
מטריצה, _ = cv2.estimateAffine2D(prev_points, curr_points)
translation_x = מטריצה[0, 2]
translation_y = מטריצה[1, 2]
rotation_angle = np.arctan2(matrix[1, 0], מטריצה[0, 0])
transforms[i] = [translation_x, translation_y, rotation_angle]
prev_grey = curr_grey

הלולאה חוזרת על כל מסגרת (למעט המסגרת האחרונה) כדי לחשב טרנספורמציות. הוא מחשב זרימה אופטית בין פריימים עוקבים בשיטת Lucas-Kanade. cv2.goodFeaturesToTrack מזהה נקודות תכונה בפריים הקודם prev_grey. לאחר מכן, cv2.calcOpticalFlowPyrLK עוקב אחר נקודות אלו במסגרת הנוכחית curr_grey.

רק הנקודות עם הסטטוס 1 (המעידות על מעקב מוצלח) עוזרות באומדן מטריצת טרנספורמציה קשורה. הקוד מעדכן את prev_grey משתנה עם המסגרת הנוכחית בגווני אפור עבור האיטרציה הבאה.

החלקת המסלול

אתה צריך להחליק את המסלול המתקבל מהטרנספורמציות כדי להשיג תוצאה יציבה.

# חשב את המסלול על ידי סיכום מצטבר של התמורות
מסלול = np.cumsum (שינויים, ציר=0)

# החלק את המסלול באמצעות ממוצע נע
smoothed_trajectory = חלק_מסלול (מסלול)

# חשב את ההבדל בין המסלול המוחלק למסלול המקורי
difference = smoothed_trajectory - מסלול

# הוסף את ההבדל בחזרה לטרנספורמציות המקוריות כדי לקבל חלק
# טרנספורמציות
transforms_smooth = טרנספורמציה + הבדל

הקוד לעיל מחשב את מסלול תנועת המצלמה ומחליק אותו.

ייצוב וכתיבת מסגרות

השלב האחרון הוא לייצב את הפריימים ולכתוב את הסרטון המיוצב לקובץ פלט.

התחל באיפוס לכידת הווידאו. זה מבטיח שפעולות עתידיות יקראו מתחילת הסרטון.

cap.set (cv2.CAP_PROP_POS_FRAMES, 0)

לאחר מכן ייצב את הסרטון על ידי עיבוד כל פריים.

# עבדו כל פריים וייצבו את הסרטון
ל אני ב טווח (מספר_פריימים - 2):
success, frame = cap.read()

אםלֹא הַצלָחָה:
לשבור

translation_x = transforms_smooth[i, 0]
translation_y = transforms_smooth[i, 1]
rotation_angle = טרנספורמציה_חלקה[i, 2]

# צור את מטריצת הטרנספורמציה לייצוב
transformation_matrix = np.zeros((2, 3), np.float32)
טרנספורמציה_מטריקס[0, 0] = np.cos (זווית_סיבוב)
טרנספורמציה_מטריקס[0, 1] = -np.sin (זווית_סיבוב)
טרנספורמציה_מטריקס[1, 0] = np.sin (זווית_סיבוב)
טרנספורמציה_מטריקס[1, 1] = np.cos (זווית_סיבוב)
טרנספורמציה_מטריקס[0, 2] = translation_x
טרנספורמציה_מטריקס[1, 2] = translation_y

# החל את השינוי כדי לייצב את המסגרת
frame_stabilized = cv2.warpAffine(
מִסגֶרֶת,
טרנספורמציה_מטריקס,
(רוחב גובה)
)

# תקן את הגבול של המסגרת המיוצבת
frame_stabilized = fix_border (frame_stabilized)

# שרשור את המסגרות המקוריות והמיוצבות זו לצד זו
frame_out = cv2.hconcat([frame, frame_stabilized])

# שנה את גודל המסגרת אם הרוחב שלה עולה על 1920 פיקסלים
אם frame_out.shape[1] > 1920:
frame_out = cv2.resize(
frame_out,
(frame_out.shape[1] // 2, frame_out.shape[0] // 2)
)

# הצג את המסגרות של לפני ואחרי
cv2.imshow("לפני ואחרי", frame_out)
cv2.waitKey(10)

# כתוב את המסגרת לקובץ וידאו הפלט
out.write (frame_out)

הקוד לעיל מייצב כל מסגרת באמצעות הטרנספורמציות המחושבות, כולל התאמות תרגום וסיבוב. לאחר מכן הוא משלב את המסגרות המיוצבות עם אלה המקוריות כדי לספק השוואה.

שחרור הווידאו לכידת וסופר

סיים את התוכנית על ידי שחרור אובייקטי לכידת הווידאו והכתיבה.

# שחרר את לכידת הווידאו והכותב, וסגור את כל החלונות הפתוחים
cap.release()
out.release()
cv2.destroyAllWindows()

קוד זה גם סוגר כל חלונות פתוחים.

פלט תוכנית סופי

הפלט של התוכנית ייראה בערך כך:

והנה דוגמה לסרטון המיוצב:

הפלט מציג את ההשוואה בין הסרטון המטלטל לזה המיוצב.

חקור את יכולות OpenCV

אתה יכול ליישם OpenCV בתחומים רבים הכוללים ראייה ממוחשבת. הסיבה לכך היא שהוא מציע מגוון רחב של פונקציות. עליך לחקור את היכולות שלו על ידי עבודה על פרויקטים נוספים הכוללים ראייה ממוחשבת. זה יציג בפניכם מושגים חדשים ויעניק לכם תחומים חדשים לחקור עליהם.