עיבוד תמונה OpenCV

Ybwd Tmwnh Opencv



אנו הולכים ללמוד את שיטות עיבוד התמונה במאמר זה. נבחן כמה נושאים בסיסיים אך קריטיים בראייה ממוחשבת ולמידת מכונה. טכניקות עיבוד תמונה בסיסיות אלו יכולות לפתור בעיות מורכבות, כגון מערכי נתונים. כתוצאה מכך, ישנם שישה שלבים בסיסיים בעיבוד תמונה, המפורטים להלן:
  1. תרגום תמונה
  2. סיבוב תמונה
  3. אריתמטיקה תמונה
  4. היפוך תמונה
  5. חיתוך תמונה
  6. שינוי גודל תמונה

כעת, נסביר בפירוט את כל נושאי עיבוד התמונה שהוזכרו לעיל.

1. תרגום תמונה

תרגום תמונה הוא שיטת עיבוד תמונה שעוזרת לנו להזיז את התמונה לאורך ציר ה-x וה-y. אנחנו יכולים להזיז את התמונה למעלה, למטה, ימינה, שמאלה או כל שילוב.







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





אנו יכולים להבין את הרעיון של תמונת התרגום באמצעות תוכנית זו.





קוד פייתון: נשמור את שם התוכנית הבאה בתור translate.py .

# ייבוא ​​חבילות נדרשות

יְבוּא רדום כפי ש לְמָשָׁל

יְבוּא argparse

יְבוּא אימוטיל

יְבוּא cv2

# אנו מיישמים את מנתח הארגומנטים

ap_obj = argparse. ArgumentParser ( )

ap_obj. הוספה_טיעון ( '-ק' , '--תמונה' , נדרש = נָכוֹן ,

עֶזרָה = 'מיקום קובץ התמונה' )

args = של מי ( ap_obj. parse_args ( ) )

# טען את התמונה והצג על המסך

תמונה = cv2. imread ( args [ 'תמונה' ] )

cv2. imshow ( 'תמונה מקורית' , תמונה )

# התרגום של התמונה הוא מטריצת NumPy המופיעה להלן:

# [[1, 0, shiftX], [0, 1, shiftY]]

# אנו הולכים להשתמש במטריצת NumPy לעיל כדי להעביר את התמונות לאורך

# כיווני ציר x וציר y. לשם כך, עלינו פשוט להעביר את ערכי הפיקסלים.

# בתוכנית זו נעביר את התמונה 30 פיקסלים ימינה

# ו-70 פיקסלים לכיוון התחתון.

translation_mat = לְמָשָׁל לצוף32 ( [ [ 1 , 0 , 30 ] , [ 0 , 1 , 70 ] ] )

תרגום_תמונה = cv2. warpAffine ( תמונה , translation_mat ,

( תמונה. צוּרָה [ 1 ] , תמונה. צוּרָה [ 0 ] ) )

cv2. imshow ( 'תרגום תמונה למטה וימינה' , תרגום_תמונה )

# כעת, אנו הולכים להשתמש במטריצת NumPy לעיל כדי להעביר את התמונות לאורך

# כיוונים של ציר x (שמאל) וציר y (למעלה).

# כאן, אנחנו הולכים להזיז את התמונות 50 פיקסלים שמאלה

# ו-90 פיקסלים כלפי מעלה.

translation_mat = לְמָשָׁל לצוף32 ( [ [ 1 , 0 , - חמישים ] , [ 0 , 1 , - 90 ] ] )

תרגום_תמונה = cv2. warpAffine ( תמונה , translation_mat ,

( תמונה. צוּרָה [ 1 ] , תמונה. צוּרָה [ 0 ] ) )

cv2. imshow ( 'תרגום תמונה למעלה ושמאלה' , תרגום_תמונה )

cv2. waitKey ( 0 )

שורות 1 עד 5: אנו מייבאים את כל החבילות הנדרשות לתוכנית זו, כמו OpenCV, argparser ו-NumPy. אנא שימו לב שיש עוד ספרייה שהיא imutils. זו לא חבילה של OpenCV. זוהי רק ספרייה שתציג בקלות את אותו עיבוד תמונה.



ה-imutils של הספרייה לא ייכללו אוטומטית כאשר נתקין את OpenCV. אז כדי להתקין את imutils, עלינו להשתמש בשיטה הבאה:

pip להתקין imutils

שורות 8 עד 15: יצרנו את האגרפרסר שלנו וטענו את התמונה שלנו.

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

השורה הראשונה של מטריצת התרגום נראית כך:

שורה זו של המטריצה ​​מיועדת לציר ה-x. הערך של t איקס יחליט אם התמונה תועבר לצד שמאל או ימין. אם נעביר ערך שלילי, אז זה אומר שהתמונה תוזז לצד שמאל, ואם הערך חיובי, אז זה אומר שהתמונה תוזז לצד ימין.

כעת נגדיר את השורה השנייה של המטריצה ​​באופן הבא:

שורה זו של המטריצה ​​מיועדת לציר ה-y. הערך של t י יחליט אם התמונה תועבר למעלה או למטה. אם נעביר ערך שלילי, אז זה אומר שהתמונה תוזז כלפי מעלה, ואם הערך חיובי, אז זה אומר שהתמונה תועבר כלפי מטה.

בתוכנית הקודמת בשורה 24, אנו מגדירים את ה-t איקס = 30 וה-t י = 70. אז אנחנו מזיזים את התמונה 30 פיקסלים לצד ימין ו-70 פיקסלים כלפי מטה.

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

שורה 27: שורה 27 תציג את התוצאה בפלט.

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

שורה 33 עד 34: בתוכנית הקודמת בשורה 33, אנו מגדירים את ה-t איקס = -50 וה-t י = -90. אז אנחנו מזיזים את התמונה 50 פיקסלים לכיוון הצד השמאלי ו-90 פיקסלים כלפי מעלה. אבל תהליך תרגום התמונה הראשי מתרחש בשורה 34, שם אנו מגדירים את מטריצת התרגום cv2.warpAffine .

קו 36 : שורה 36 תציג את התוצאה כפי שמוצגת בפלט.

כדי להפעיל את הקוד הקודם, עלינו לתת את הנתיב של התמונה כפי שניתן להלן.

תְפוּקָה: python translate.py –image squirrel.jpg

כעת, ניישם את אותה תוכנית תרגום תמונות באמצעות ה אימוטיל סִפְרִיָה. ספרייה זו קלה מאוד לשימוש עבור עיבוד תמונה. בספרייה זו, אנחנו לא צריכים לחשוב על ה cv2.warpAffine כי הספרייה הזו תדאג לזה. אז בואו ליישם את תוכנית תרגום התמונות הזו באמצעות ספריית imutils.

קוד פייתון: נשמור את שם התוכנית הבאה בתור translate_imutils.py .

# ייבא את החבילות הדרושות

יְבוּא רדום כפי ש לְמָשָׁל

יְבוּא argparse

יְבוּא אימוטיל

יְבוּא cv2

# פונקציה זו מיישמת את תרגום התמונה ו

# מחזיר את התמונה המתורגמת לפונקציה הקוראת.

def לתרגם ( תמונה , איקס , י ) :

מטריקס_תרגום = לְמָשָׁל לצוף32 ( [ [ 1 , 0 , איקס ] , [ 0 , 1 , י ] ] )

תרגום_תמונה = cv2. warpAffine ( תמונה , מטריקס_תרגום ,

( תמונה. צוּרָה [ 1 ] , תמונה. צוּרָה [ 0 ] ) )

לַחֲזוֹר תרגום_תמונה

# בנה את מנתח הארגומנטים ונתח את הארגומנטים

ap = argparse. ArgumentParser ( )

ap. הוספה_טיעון ( '-אני' , '--תמונה' , נדרש = נָכוֹן , עֶזרָה = 'הנתיב לתמונה' )

args = של מי ( ap. parse_args ( ) )

# טען את התמונה והצג על המסך

תמונה = cv2. imread ( args [ 'תמונה' ] )

cv2. imshow ( 'תמונה מקורית' , תמונה )

תרגום_תמונה = אימוטיל. לתרגם ( תמונה , 10 , 70 )

cv2. imshow ( 'תרגום תמונה לימין ולחסרון' ,

תרגום_תמונה )

cv2. waitKey ( 0 )

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

השורות האלה כבר הוסברו, אבל עכשיו אנחנו הולכים לבנות פונקציה שנקראת translate () ונשלח לתוכה שלושה פרמטרים ברורים. התמונה עצמה משמשת כפרמטר ראשון. ערכי ה-x וה-y של מטריצת התרגום תואמים לפרמטר השני והשלישי.

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

שורה 24: התוכנית הקודמת תראה שבשורה 24, אנו מגדירים את tx = 10 ואת ty = 70. אז אנו מזיזים את התמונה 10 פיקסלים לצד ימין ו-70 פיקסלים כלפי מטה.

בתוכנית זו, לא אכפת לנו מפונקציות cv2.warpAffine משום שהן כבר נמצאות בתוך חבילת ספריית imutils.

כדי להפעיל את הקוד הקודם, עלינו לתת את הנתיב של התמונה, כפי שניתן להלן:

תְפוּקָה:

פיתון אימוטילס. py --דימוי סנאי. jpg

2. סיבוב תמונה

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

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

בדומה לתרגום, ואולי לא מפתיע, סיבוב בזווית, תטא נקבע על ידי בניית מטריצה ​​M בפורמט הבא:

מטריצה ​​זו עשויה לסובב מעלות תטא וקטור (נגד כיוון השעון) סביב המוצא הנתון (x, y)-מישור קרטזי. בדרך כלל, בתרחיש זה, המקור יהיה מרכז התמונה, אך למעשה, אנו עשויים לייעד כל נקודת אקראית (x, y) כמרכז הסיבוב שלנו.

התמונה המסובבת R נוצרת לאחר מכן מהתמונה המקורית I באמצעות כפל מטריצה ​​פשוט: R = IM

OpenCV, לעומת זאת, מציעה בנוסף את היכולת (1) לשנות קנה מידה (כלומר, לשנות את גודלה) של תמונה ו-(2) להציע מרכז סיבוב שרירותי לביצוע הסיבוב.

מטריצת הסיבוב המותאמת שלנו M מוצגת להלן:

נתחיל בפתיחה ויצירה של קובץ חדש בשם rotate.py :

# ייבוא ​​החבילות הנדרשות

יְבוּא רדום כפי ש לְמָשָׁל

יְבוּא argparse

יְבוּא אימוטיל

יְבוּא cv2

# יצירת אובייקט argumentparser וארגומנט ניתוח

apobj = argparse. ArgumentParser ( )

apobj. הוספה_טיעון ( '-ק' , '--תמונה' , נדרש = נָכוֹן , עֶזרָה = 'נתיב תמונה' )

טיעונים = של מי ( apobj. parse_args ( ) )

תמונה = cv2. imread ( טיעונים [ 'תמונה' ] )

cv2. imshow ( 'תמונה מקורית' , תמונה )

# חשב את מרכז התמונה באמצעות מידות התמונה.

( גוֹבַה , רוֹחַב ) = תמונה. צוּרָה [ : 2 ]

( centerX , מרכז Y ) = ( רוחב / 2 , גובה / 2 )

# כעת, באמצעות cv2, נסובב את התמונה ב-55 מעלות ל

# קבע את מטריצת הסיבוב באמצעות getRotationMatrix2D()

rotationMatrix = cv2. getRotationMatrix2D ( ( centerX , מרכז Y ) , 55 , 1.0 )

rotatedImage = cv2. warpAffine ( תמונה , rotationMatrix , ( רוֹחַב , גוֹבַה ) )

cv2. imshow ( 'סובב את התמונה ב-55 מעלות' , rotatedImage )

cv2. waitKey ( 0 )

# התמונה תסובב כעת ב-85 מעלות.

rotationMatrix = cv2. getRotationMatrix2D ( ( centerX , מרכז Y ) , - 85 , 1.0 )

rotatedImage = cv2. warpAffine ( תמונה , rotationMatrix , ( רוֹחַב , גוֹבַה ) )

cv2. imshow ( 'סובב את התמונה ב-85 מעלות' , rotatedImage )

cv2. waitKey ( 0 )

שורות 1 עד 5: אנו מייבאים את כל החבילות הנדרשות לתוכנית זו, כמו OpenCV, argparser ו-NumPy. אנא שימו לב שיש עוד ספרייה שהיא imutils. זו לא חבילה של OpenCV. זוהי רק ספרייה שתשמש כדי להציג את אותו עיבוד תמונה בקלות.

ה-imutils של הספרייה לא ייכללו אוטומטית כאשר נתקין את OpenCV. OpenCV מתקין את imutils. עלינו להשתמש בשיטה הבאה:

pip להתקין imutils

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

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

קווים 17 עד 18 קח את הרוחב והגובה של התמונה, בהתאמה, ולאחר מכן חלקו כל מימד בשניים כדי לקבוע את מרכז התמונה.

אנו בונים מטריצה ​​כדי לסובב תמונה באותו אופן שהגדרנו מטריצה ​​לתרגום תמונה. אנחנו פשוט נתקשר ל cv2.getRotationMatrix2D פונקציה בשורה 22 במקום ליצור את המטריצה ​​באופן ידני באמצעות NumPy (שעשוי להיות מעט מסורבל).

ה cv2.getRotationMatrix2D הפונקציה דורשת שלושה פרמטרים. הקלט הראשון הוא זווית הסיבוב הרצויה (במקרה זה, מרכז התמונה). לאחר מכן משתמשים בתטא כדי לציין כמה מעלות (נגד כיוון השעון) נסובב את התמונה. כאן, נסובב את התמונה ב-45 מעלות. האפשרות הסופית קשורה לגודל התמונה.

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

שורה 22 עד 23: לאחר קבלת מטריצת הסיבוב שלנו M מה- cv2.getRotationMatrix2D פונקציה, אנו מסובבים את התמונה שלנו באמצעות cv2.warpAffine טכניקה בשורה 23. הקלט הראשון של הפונקציה הוא התמונה שאנו רוצים לסובב. הרוחב והגובה של תמונת הפלט שלנו מוגדרים לאחר מכן, יחד עם מטריצת הסיבוב שלנו M. בשורה 23, התמונה מסובבת אז ב-55 מעלות.

אתה יכול לשים לב שהתמונה שלנו סובבה.

קווים 28 עד 30 מהווים את הסיבוב השני. שורות 22–23 של הקוד זהות, אלא שהפעם אנחנו מסתובבים ב-85 מעלות לעומת 55.

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

נתחיל בפתיחה ויצירה של קובץ חדש בשם rotate.py:

# ייבוא ​​החבילות הנדרשות

יְבוּא רדום כפי ש לְמָשָׁל

יְבוּא argparse

יְבוּא אימוטיל

יְבוּא cv2

# יצירת אובייקט argumentparser וארגומנט ניתוח

ap_obj = argparse. ArgumentParser ( )

ap_obj. הוספה_טיעון ( '-ק' , '--תמונה' , נדרש = נָכוֹן , עֶזרָה = 'נתיב תמונה' )

טַעֲנָה = של מי ( ap_obj. parse_args ( ) )

# טען את התמונה והצג על המסך

תמונה = cv2. imread ( טַעֲנָה [ 'תמונה' ] )

cv2. imshow ( 'תמונה מקורית' , תמונה )

# חשב את מרכז התמונה באמצעות מידות התמונה.

( גוֹבַה , רוֹחַב ) = תמונה. צוּרָה [ : 2 ]

( centerX , מרכז Y ) = ( רוחב / 2 , גובה / 2 )

# כעת, באמצעות cv2, נסובב את התמונה ב-55 מעלות ל

# קבע את מטריצת הסיבוב באמצעות getRotationMatrix2D()

rotationMatrix = cv2. getRotationMatrix2D ( ( centerX , מרכז Y ) , 55 , 1.0 )

rotatedImage = cv2. warpAffine ( תמונה , rotationMatrix , ( רוֹחַב , גוֹבַה ) )

cv2. imshow ( 'סובב את התמונה ב-55 מעלות' , rotatedImage )

cv2. waitKey ( 0 )

# התמונה תסובב כעת ב-85 מעלות.

rotationMatrix = cv2. getRotationMatrix2D ( ( centerX , מרכז Y ) , - 85 , 1.0 )

rotatedImage = cv2. warpAffine ( תמונה , rotationMatrix , ( רוֹחַב , גוֹבַה ) )

cv2. imshow ( 'סובב את התמונה ב-85 מעלות' , rotatedImage )

cv2. waitKey ( 0 )

# סיבוב תמונה מנקודה שרירותית כלשהי, לא מהמרכז

rotationMatrix = cv2. getRotationMatrix2D ( ( centerX - 40 , centerY - 40 ) , 55 , 1.0 )

rotatedImage = cv2. warpAffine ( תמונה , rotationMatrix , ( רוֹחַב , גוֹבַה ) )

cv2. imshow ( 'סיבוב תמונה מנקודות שרירותיות' , rotatedImage )

cv2. waitKey ( 0 )

שורה 34 עד 35: עכשיו, הקוד הזה אמור להיראות די נפוץ לסיבוב אובייקט. כדי לסובב את התמונה סביב נקודה 40 פיקסלים שמאלה ו-40 פיקסלים מעל המרכז שלה, אנו מורים על cv2.getRotationMatrix2D פונקציה לשים לב לפרמטר הראשון שלו.

התמונה שנוצרה כאשר אנו מיישמים סיבוב זה מוצגת להלן:

אנו יכולים לראות בבירור שמרכז הסיבוב הוא כעת הקואורדינטה (x, y), שהיא 40 פיקסלים משמאל ו-40 פיקסלים מעל למרכז המחושב של התמונה.

3. חשבון תמונה

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

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

שקול לשלב את שתי המטריצות הבאות:

איזו תוצאה תניב תוספת המטריצה? התשובה הפשוטה היא סכום ערכי המטריצה, אלמנט אחר אלמנט:

מספיק פשוט, נכון?

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

פיקסלים בתמונות RGB, למשל, נופלים בין [0, 255]. מה קורה אם ננסה להוסיף 10 לפיקסל בעוצמה של 250 תוך כדי התבוננות בו?

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

אז מה אמור לקרות? האם עלינו לבצע בדיקה כדי לוודא שאף פיקסל אינו מעבר לטווח של [0, 255], ולחתוך כל פיקסל לערך בין 0 ל-255?

או שאנחנו 'מתעטפים' ומבצעים פעולת מודולוס? בהתאם לכללי המודולוס, הוספת 10 ל-255 רק תביא לערך של 9.

כיצד יש לטפל בהוספות וחיכויים לתמונות מעבר לטווח של [0, 255]?

האמת היא שאין טכניקה נכונה או לא נכונה; הכל תלוי איך אתה עובד עם הפיקסלים שלך ומה אתה מקווה להשיג.

אבל זכור שיש הבדלים בין הוספה ב-OpenCV לתוספת ב-NumPy. אריתמטיקה מודולוס ו'כריכה' יבוצעו על ידי NumPy. לעומת זאת, OpenCV יבצע גזירה ויוודא שערכי הפיקסלים לעולם לא יעזבו את הטווח [0, 255].

נתחיל ביצירת קובץ חדש בשם arithmetic.py ופותחים אותו:

# python arithmetic.py --image squirrel.jpg

# ייבוא ​​החבילות הנדרשות

יְבוּא רדום כפי ש לְמָשָׁל

יְבוּא argparse

יְבוּא אימוטיל

יְבוּא cv2

# יצירת אובייקט argumentparser וארגומנט ניתוח

apObj = argparse. ArgumentParser ( )

apObj. הוספה_טיעון ( '-ק' , '--תמונה' , נדרש = נָכוֹן , עֶזרָה = 'נתיב תמונה' )

טיעונים = של מי ( apObj. parse_args ( ) )

תמונה = cv2. imread ( טיעונים [ 'תמונה' ] )

cv2. imshow ( 'תמונה מקורית' , תמונה )

'''

הערכים של הפיקסלים שלנו יהיו בטווח [0, 255]

מכיוון שתמונות הן מערכי NumPy, המאוחסנים כמספרים שלמים של 8 סיביות ללא סימנים.

בעת שימוש בפונקציות כמו cv2.add ו-cv2.subtract, הערכים ייחתכו

לטווח זה גם אם הם מתווספים או מופחתים מחוץ ל-

טווח [0, 255]. הנה המחשה:

'''


הדפס ( 'מקסימום 255: {}' . פוּרמָט ( str ( cv2. לְהוֹסִיף ( לְמָשָׁל uint8 ( [ 201 ] ) ,

לְמָשָׁל uint8 ( [ 100 ] ) ) ) ) )

הדפס ( 'מינימום של 0: {}' . פוּרמָט ( str ( cv2. להחסיר ( לְמָשָׁל uint8 ( [ 60 ] ) ,

לְמָשָׁל uint8 ( [ 100 ] ) ) ) ) )

'''

כאשר עושים פעולות אריתמטיות עם מערכים אלה באמצעות NumPy,

הערך יתעטף במקום להיות מוצמד ל-

[0, 255]טווח. בעת שימוש בתמונות, חיוני לשמור זאת

בראש.

'''


הדפס ( 'לעטוף: {}' . פוּרמָט ( str ( לְמָשָׁל uint8 ( [ 201 ] ) + למשל uint8 ( [ 100 ] ) ) ) )

הדפס ( 'לעטוף: {}' . פוּרמָט ( str ( לְמָשָׁל uint8 ( [ 60 ] ) - למשל uint8 ( [ 100 ] ) ) ) )

'''

בואו נכפיל את הבהירות של כל פיקסל בתמונה שלנו ב-101.

לשם כך, אנו יוצרים מערך NumPy באותו גודל כמו המטריצה ​​שלנו,

מלאים באחדים, ומכפילים אותו ב-101 כדי לייצר מערך מלא

עם 101s. לבסוף, אנו ממזגים את שתי התמונות.

תשים לב שהתמונה כעת 'בהירה יותר'.

'''


מַטרִיצָה = לְמָשָׁל יחידות ( תמונה. צוּרָה , dtype = 'uint8' ) * 101

תמונה_נוספה = cv2. לְהוֹסִיף ( תמונה , מַטרִיצָה )

cv2. imshow ( 'תוסף תמונה' , תמונה_נוספה )

#באופן דומה, אנו עשויים להפוך את התמונה שלנו לכהה יותר על ידי צילום

# במרחק של 60 מכל הפיקסלים.

מַטרִיצָה = לְמָשָׁל יחידות ( תמונה. צוּרָה , dtype = 'uint8' ) * 60

image_subtracted = cv2. להחסיר ( תמונה , מַטרִיצָה )

cv2. imshow ( 'תוצאת תמונה מופחתת' , image_subtracted )

cv2. waitKey ( 0 )

קווים 1 עד 16 ישמש לביצוע התהליך הרגיל שלנו, שכולל ייבוא ​​החבילות שלנו, הגדרת מנתח הארגומנטים שלנו וטעינת התמונה שלנו.

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

שני מערכי NumPy ללא סימן של 8 סיביות מוגדרים ב שורה 26 . ערך של 201 הוא האלמנט היחיד במערך הראשון. למרות שרק איבר אחד נמצא במערך השני, יש לו ערך של 100. לאחר מכן הערכים מתווספים באמצעות הפונקציה cv2.add של OpenCV.

מה אתה צופה שתהיה התוצאה?

בהתאם לעקרונות החשבון הקונבנציונליים, התשובה צריכה להיות 301. אך זכור כי אנו עוסקים במספרים שלמים ללא סימנים של 8 סיביות, שיכולים להיות רק בטווח [0, 255]. מכיוון שאנו משתמשים בשיטת cv2.add, OpenCV מטפל בגזירה ומבטיח שההוספה תחזיר רק תוצאה מקסימלית של 255.

השורה הראשונה של הרשימה למטה מציגה את התוצאה של הפעלת קוד זה:

חֶשְׁבּוֹן. py

מקסימום של 255 : [ [ 255 ] ]

הסכום אכן הניב מספר של 255.

בעקבות זאת, שורה 26 משתמש ב-cv2.subtract כדי לבצע חיסור. פעם נוספת, אנו מגדירים שני מערכי NumPy שלמים ללא סימנים של 8 סיביות עם אלמנט בודד בכל אחד מהם. הערך של המערך הראשון הוא 60, ואילו הערך של המערך השני הוא 100.

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

חֶשְׁבּוֹן. py

מינימום של 0 : [ [ 0 ] ]

בעזרת cv2, הפחיתו 100 מ-60, הפקו את הערך 0.

אבל מה קורה אם נשתמש ב-NumPy במקום OpenCV כדי לבצע את החישובים?

קווים 38 ו-39 לטפל בנושא זה.

ראשית, מוגדרים שני מערכי NumPy ללא סימנים של 8 סיביות עם אלמנט בודד כל אחד. הערך של המערך הראשון הוא 201, ואילו הערך של המערך השני הוא 100. התוספת שלנו תיחתך, וערך של 255 יוחזר אם נשתמש בפונקציה cv2.add.

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

חֶשְׁבּוֹן. py
לעטוף: [ ארבע חמש ]

לאחר מכן, מוגדרים שני מערכי NumPy נוספים, האחד עם ערך של 50 והשני עם 100. חיסור זה ייחתך על ידי שיטת cv2.subtract כדי להחזיר תוצאה של 0. אך אנו מודעים לכך שבמקום לחתוך, NumPy מבצעת אריתמטיקה מודולו. במקום זאת, נהלי המודולו עוטפים ומתחילים לספור אחורה מ-255 ברגע שמגיעים ל-0 במהלך החיסור. אנו יכולים לראות זאת מהפלט הבא:

חֶשְׁבּוֹן. py

לעטוף: [ 207 ]

שוב, הפלט הטרמינל שלנו מדגים את ההבחנה בין גזירה לליפוף:

חשוב לזכור את התוצאה הרצויה בעת ביצוע אריתמטיקה של מספרים שלמים. האם אתה רוצה שערכים מחוץ לטווח [0, 255] ייחתכו? השתמש בטכניקות חשבון התמונות המובנות של OpenCV לאחר מכן.

האם אתה רוצה שערכים יסתובבו אם הם מחוץ לטווח של [0, 255] ופעולות אריתמטיות מודולוס? לאחר מכן פשוט מוסיפים ומגרעים את מערכי ה-NumPy כרגיל.

קו 48 מגדיר מערך NumPy חד מימדי עם אותם מידות כמו התמונה שלנו. שוב, אנו מבטיחים שסוג הנתונים שלנו הוא מספרים שלמים ללא סימנים של 8 סיביות. אנחנו פשוט מכפילים את המטריצה ​​שלנו של ערכים חד ספרתיים ב-101 כדי למלא אותה בערכים של 101 במקום 1. לבסוף, אנחנו משתמשים בפונקציה cv2.add כדי להוסיף את המטריצה ​​של 100s שלנו לתמונה המקורית. זה מגדיל את עוצמת כל פיקסל ב-101 ובמקביל מבטיח שכל ערכים שמנסים לחרוג מ-255 יקוצצו לטווח [0, 255].

שים לב כיצד התמונה בהירה יותר באופן ניכר ונראית 'שטופה' יותר מהמקור. הסיבה לכך היא שאנו מובילים פיקסלים לעבר צבעים בהירים יותר על ידי העלאת עוצמות הפיקסלים שלהם ב-101.

על מנת להחסיר 60 מכל עוצמת פיקסל של התמונה, אנו מקימים תחילה מערך NumPy שני בקו 54 שממולא בשנות ה-60.

התוצאות של חיסור זה מתוארות בתמונה הבאה:

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

4. היפוך תמונה

בדומה לסיבוב, היפוך תמונה על פני ציר ה-x או ה-y שלה היא אפשרות נוספת המוצעת על ידי OpenCV. גם אם פעולות היפוך אינן מנוצלות בתדירות גבוהה, הכרתן מועילה להפליא מסיבות שונות שאולי לא תראה מיד.

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

מה, אם כן, אנחנו עושים?

מכיוון שפנים נשארות פנים בין אם הן משוקפות ובין אם לא, אנו מסוגלים להפוך כל תמונה של פנים אופקית ולהשתמש בגרסאות השיקוף כנתוני אימון נוספים.

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

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

מטרות:

משתמש ב cv2.flip פונקציה, תלמד כיצד להפוך תמונה אופקית ואנכית בפגישה זו.

היפוך הוא מניפולציית התמונה הבאה שנלמד. ניתן להפוך את צירי x ו-y של תמונה או אפילו את שניהם. לפני שנצלול לתוך הקידוד, עדיף להסתכל תחילה על התוצאות של היפוך תמונה. ראה תמונה שהופכה אופקית בתמונה הבאה:


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

נתחיל ביצירת קובץ חדש בשם flipping.py .

ראית דוגמה להיפוך תמונה, אז הבה נבחן את הקוד:

# python flipping.py --image quirrel.jpg

# ייבוא ​​החבילות הנדרשות

יְבוּא argparse

יְבוּא cv2

# יצירת האובייקט של מנתח ארגומנטים וניתוח הארגומנט

apObj = argparse. ArgumentParser ( )

apObj. הוספה_טיעון ( '-אני' , '--תמונה' , נדרש = נָכוֹן , עֶזרָה = 'נתיב תמונה' )

טַעֲנָה = של מי ( apObj. parse_args ( ) )

תמונה = cv2. imread ( טַעֲנָה [ 'תמונה' ] )

cv2. imshow ( 'מְקוֹרִי' , תמונה )

# הפוך את התמונה אופקית

התהפך = cv2. לְהַעִיף ( תמונה , 1 )

cv2. imshow ( 'תמונה התהפכה אופקית' , התהפך )

# הפוך את התמונה אנכית

התהפך = cv2. לְהַעִיף ( תמונה , 0 )

cv2. imshow ( 'היפוך תמונה אנכית' , התמונה הופכת )

הפוך תמונה אחת לאורך שני הצירים

התמונה הופכת = cv2. לְהַעִיף ( תמונה , - 1 )

cv2. imshow ( 'היפוך אופקי ואנכי' , התמונה הופכת )

cv2. waitKey ( 0 )

הצעדים שאנו נוקטים כדי לייבא את החבילות שלנו, לנתח את התשומות שלנו ולטעון את התמונה מהדיסק מטופלים ב-l ines 1 עד 12 .

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

ערך קוד היפוך של 1 אומר שנסובב את התמונה סביב ציר ה-y כדי להפוך אותה אופקית ( שורה 15 ). אם נציין קוד היפוך של 0, נרצה לסובב את התמונה סביב ציר ה-x ( קו 19 ). קוד הפוך שלילי ( קו 23 ) מסובב את התמונה בשני הצירים.

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

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

5. חיתוך תמונה

חיתוך, כפי שהשם מרמז, הוא תהליך הבחירה וההסרה של אזור העניין (או פשוט ROI), שהוא אזור התמונה שמעניין אותנו.

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

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

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

צור קובץ חדש בשם crop.py , פתח אותו והוסף את הקוד הבא:

# python crop.py

# ייבוא ​​החבילות הנדרשות

יְבוּא cv2

# טעינת תמונה והצגה על המסך

תמונה = cv2. imread ( 'squirrel.jpg' )

הדפס ( תמונה. צוּרָה )

cv2. imshow ( 'מְקוֹרִי' , תמונה )

# פרוסות מערך NumPy משמשות לחיתוך מהיר של תמונה

# אנחנו הולכים לחתוך את פני הסנאי מהתמונה

סנאי = תמונה [ 35 : 90 , 35 : 100 ]

cv2. imshow ( 'פני סנאי' , סנאי )

cv2. waitKey ( 0 )

# ועכשיו, הנה אנחנו הולכים לחתוך את כל הגוף

# של הסנאי

גוף סנאי = תמונה [ 35 : 148 , 23 : 143 ]

cv2. imshow ( 'גוף סנאי' , גוף סנאי )

cv2. waitKey ( 0 )

אנו נציג חיתוך ב-Python וב-OpenCV באמצעות תמונה שנטען מהדיסק שורות 5 ו-6 .

תמונה מקורית שאנו הולכים לחתוך

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

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

אנו יכולים לזהות את הפנים בתמונה באמצעות שורת קוד אחת בלבד. קו 13 , כדי לחלץ חלק מלבן מהתמונה, החל מ- (35, 35), אנו מספקים פרוסות מערך NumPy (90, 100). זה אולי נראה מבלבל שאנו מאכילים את היבול עם האינדקסים בסדר גובה-ראשון ורוחב-שנייה שאנו עושים, אך זכור ש-OpenCV מאחסן תמונות כמערכי NumPy. כתוצאה מכך, עלינו לספק את הערכים של ציר ה-y לפני ציר ה-x.

NumPy דורש את ארבעת האינדקסים הבאים כדי לבצע את החיתוך שלנו:

התחל y: קואורדינטת ה-y בהתחלה. במקרה זה, אנו מתחילים ב-y=35.

סוף y: קואורדינטת ה-y בסוף. היבול שלנו ייפסק כאשר y = 90.

התחלה x: קואורדינטת x ההתחלה של הפרוסה. היבול מתחיל ב-x=35.

סוף x: קואורדינטת ציר ה-X של קצה הפרוסה. ב-x=100, הפרוסה שלנו מסתיימת.

באופן דומה, אנו חותכים את האזורים (23, 35) ו-(143, 148) מהתמונה המקורית כדי לחלץ את הגוף המלא מהתמונה על קו 19 .

אתה יכול לראות שהתמונה נחתכה רק כדי להציג את הגוף והפנים.

6. שינוי גודל תמונה

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

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

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

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

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

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

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

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

# python resize.py --image squirrel.jpg

# ייבוא ​​החבילות הנדרשות

יְבוּא argparse

יְבוּא cv2

# יצירת האובייקט של מנתח ארגומנטים וניתוח הארגומנט

apObj = argparse. ArgumentParser ( )

apObj. הוספה_טיעון ( '-ק' , '--תמונה' , נדרש = נָכוֹן , עֶזרָה = 'נתיב תמונה' )

טיעונים = של מי ( apObj. parse_args ( ) )

# טען את התמונה והצג על המסך

תמונה = cv2. imread ( טיעונים [ 'תמונה' ] )

cv2. imshow ( 'מְקוֹרִי' , תמונה )

# על מנת למנוע מהתמונה להיראות עקומה, יחס רוחב-גובה

# חייב להיחשב או לעוות; לכן, אנחנו מבינים מה

# היחס בין התמונה החדשה לתמונה הנוכחית.

# בואו נהפוך את רוחב התמונה החדשה שלנו ל-160 פיקסלים.

אספקט = 160.0 / תמונה. צוּרָה [ 1 ]

מֵמַד = ( 160 , int ( תמונה. צוּרָה [ 0 ] * אספקט ) )

# שורה זו תציג פעולות שינוי גודל בפועל

שינוי גודל התמונה = cv2. שנה גודל ( תמונה , מֵמַד , שִׁרבּוּב = cv2. INTER_AREA )

cv2. imshow ( 'שינוי גודל רוחב תמונה' , שינוי גודל התמונה )

# מה אם נרצה לשנות את גובה התמונה? - משתמש ב

# אותו עיקרון, אנו יכולים לחשב את יחס הרוחב-גובה על סמך

# בגובה ולא ברוחב. בואו נעשה את הקנה מידה

גובה תמונה אחת 70 פיקסלים.

אספקט = 70.0 / תמונה. צוּרָה [ 0 ]

מֵמַד = ( int ( תמונה. צוּרָה [ 1 ] * אספקט ) , 70 )

# בצע את שינוי הגודל

שינוי גודל התמונה = cv2. שנה גודל ( תמונה , מֵמַד , שִׁרבּוּב = cv2. INTER_AREA )

cv2. imshow ( 'שינוי גודל גובה התמונה' , שינוי גודל התמונה )

cv2. waitKey ( 0 )

שורות 1-14 , לאחר ייבוא ​​החבילות שלנו והגדרת מנתח הארגומנטים שלנו, נטען ונציג את התמונה שלנו.

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

גובה רוחב הוא יחס הגובה-רוחב.

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

עַל קו 20 , נעשה חישוב היחס ששינוי הגודל. אנו מספקים את רוחב התמונה החדשה שלנו כ-160 פיקסלים בשורת הקוד הזו. אנו פשוט מגדירים את היחס שלנו (אספקטרציה) כרוחב החדש (160 פיקסלים) חלקי הרוחב הישן, אליו אנו ניגשים באמצעות תמונה, כדי לחשב את היחס בין הגובה החדש לגובה הישן. צורה[1].

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

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

לבסוף, הלאה קו 25 , אנו מציגים את התמונה המוקטנת שלנו.

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

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

לאחר מכן, גודל התמונה משתנה למעשה קו 35 , והוא מוצג ב- קו 36.

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

סיכום

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

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

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

חשוב לזכור שלמרות ש-NumPy מבצעת פעולת מודול ו'עוטפת', OpenCV חיבור וחיסור חותכים ערכי מעבר לטווח [0, 255] כדי להתאים לטווח. כשאתה מפתח יישומי ראייה ממוחשבת משלך, לזכור את זה יעזור לך להימנע מציד באגים מסובכים.

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

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

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