- איתור אובייקטים באמצעות SIFT
- איתור אובייקטים באמצעות ORB
- היסטוגרמה של שיפועי אוריינטציה (HOG)
- היסטוגרמה של שיפועים מכוונים (HOG), שלב אחר שלב:
- מסווגי מפל של HAAR
- זיהוי פנים ועיניים
- זיהוי פנים ועיניים חי
- כוונון מסווגים של אשדות
- איתור מכוניות והולכי רגל בסרטונים
התחלנו בהתקנת פיתון OpenCV בחלונות ועד כה עשינו עיבוד תמונה בסיסי, פילוח תמונות וזיהוי אובייקטים באמצעות פיתון, המכוסים במדריכות הבאות:
- תחילת העבודה עם Python OpenCV: התקנה ועיבוד תמונה בסיסי
- מניפולציות תמונה ב- Python OpenCV (חלק 1)
- מניפולציות תמונה ב- OpenCV (חלק 2)
- פילוח תמונה באמצעות OpenCV - חילוץ אזורים ספציפיים של תמונה
למדנו גם על שיטות ואלגוריתמים שונים לזיהוי אובייקטים, שם אותרו כמה נקודות מפתח עבור כל אובייקט באמצעות אלגוריתמים שונים. במדריך זה אנו נשתמש באלגוריתמים אלה כדי לזהות עצמים בחיים האמיתיים, כאן נשתמש ב- SIFT ו- ORB לזיהוי.
איתור אובייקטים באמצעות SIFT
כאן זיהוי אובייקטים ייעשה באמצעות זרם מצלמות אינטרנט חי, כך שאם הוא מזהה את האובייקט הוא יזכיר את האובייקט שנמצא. בקוד החלק העיקרי מנוגן על ידי הפונקציה הנקראת גלאי SIFT, רוב העיבוד נעשה על ידי פונקציה זו.
ובמחצית השנייה של הקוד, אנו מתחילים בפתיחת זרם מצלמת הרשת, ואז נטען את תבנית התמונה, כלומר תמונת ההתייחסות, כלומר התוכנית למעשה מסתכלת דרך זרם מצלמת הרשת.
לאחר מכן, אנו מצלמים ברציפות את התמונות מזרם מצלמת הרשת בעזרת אינסוף תוך כדי לולאה, ואז מצלמים את הגובה והרוחב המתאימים של מסגרת מצלמת הרשת, ולאחר מכן מגדירים את הפרמטרים של אזור התעניינות (ROI) שבו האובייקט שלנו יכול להשתלב על ידי לקיחת הגובה והרוחב המתאימים של מסגרת מצלמת הרשת. ואז אנו שואבים את המלבן מפרמטרי ההחזר על ההשקעה שהגדרנו לעיל. ואז סוף סוף חתוך את המלבן והזין אותו לחלק גלאי SWIFT של הקוד.
עכשיו לגלאי SIFT יש בעצם שתי כניסות, האחת היא התמונה החתוכה והשנייה היא תבנית התמונה שהגדרנו בעבר ואז זה נותן לנו כמה התאמות, כך שההתאמות הן בעצם מספר האובייקטים או המקשים הדומים בתמונה החתוכה ותמונת היעד. ואז אנו מגדירים ערך סף עבור ההתאמות, אם ערך ההתאמות גדול מהסף, שמנו תמונה שנמצאה על המסך שלנו עם צבע ירוק של מלבן ROI.
עכשיו בואו נחזור לחלק העיקרי של הקוד, הפונקציה שנקראת גלאי SIFT, זה לוקח את הקלט כשתי תמונות אחת היא התמונה בה היא מחפשת את האובייקט והשנייה היא האובייקט שאנו מנסים להתאים. אל (תבנית תמונה). ואז קנה המידה האפור את התמונה הראשונה והגדר את תבנית התמונה כתמונה שנייה. ואז אנו יוצרים אובייקט גלאי SIFT ומריצים את פונקציית איתור ומחשוב OpenCV SIFT, כדי לזהות את מקשי המקשים ולחשב את המתארים, המתארים הם בעצם הווקטורים המאחסנים את המידע על מקשי המקלדת, וזה ממש חשוב כאשר אנו מבצעים את ההתאמה בין מתארי התמונות.
ואז הגדר את התואם המבוסס על FLANN, אנחנו לא נכנסים לתיאוריה המתמטית של התאמה מאחוריו, אבל אתה יכול בקלות לבצע גוגל בנושא. ראשית, הגדירו את האינדקס kdtree לאפס ואז הגדרנו את האינדקס ואת פרמטרי החיפוש בתבנית המילון, אנחנו פשוט מגדירים את האלגוריתם בו אנו משתמשים שהוא KDTREE, ומספר העצים שנשתמש בהם, כך יהיה יותר עץ אנו משתמשים ככל שזה נעשה מסובך יותר ויותר. ובפרמטר החיפוש הגדירו את מספר הבדיקות, שהוא בעצם מספר ההתאמות שהוא עומד להשלים.
ואז צור את אובייקט ההתאמה המבוסס על FLANN על ידי טעינת הפרמטר שהגדרנו בעבר שהם פרמטרים של אינדקס ופרמטרים של חיפוש ועל סמך זה צור התאמה מבוססת FLANN שלנו, שהיא התאמה של KNN שבה KNN הוא השכן הקרוב ביותר, בעצם זו הדרך שבה אנו מחפשים התאמות ותיאורים קרובים ביותר ואנחנו מבצעים את ההתאמה עם קבוע האתחול k. כעת התואם מבוסס FLANN זה מחזיר את מספר ההתאמות שאנו מקבלים.
התאמה מבוססת FLANN היא רק קירוב, כדי להגביר את הדיוק של התאמה מבוססת FLANN אנו מבצעים בדיקת יחס של Lowe ומה שהיא עושה זה לחפש את ההתאמות מהשדכן מבוסס knn flann ולהגדיר כמה פרמטרים מטריים שזה המרחק כאן, אשר המרחק הוא פונקציה קהה, וברגע שהוא עומד בקריטריונים הוסף את ההתאמות להתאמות הטובות ומחזיר את ההתאמות הטובות שנמצאו, וכך זרם הווידאו בשידור חי מספר את מספר ההתאמות שנמצאו בפינת המסך.
עכשיו בואו נסתכל על הקוד לתיאור לעיל:
ייבא cv2 ייבוא מטומטם כ np def sift_detector (new_image, image_template): # פונקציה שמשווה תמונת קלט לתבנית # ואז מחזירה את מספר התאמות SIFT ביניהן image1 = cv2.cvtColor (new_image, cv2.COLOR_BGR2GRAY) image2 = image_template # Create אובייקט גלאי SIFT #sift = cv2.SIFT () sift = cv2.xfeatures2d.SIFT_create () # השג את המקשים והמתארים באמצעות SIFT keypoints_1, descriptors_1 = sift.detectAndCompute (image1, None) keypoints_2, descriptors_2 = sift.det ללא) # הגדר פרמטרים עבור Flann Matcher FLANN_INDEX_KDTREE = 0 index_params = dict (אלגוריתם = FLANN_INDEX_KDTREE, עצים = 3) search_params = dict (checks = 100) # Create the Flann Matcher object flann = cv2.FlannBasedMatcher (index_params, search_params) # השג התאמות בשיטת השכן הקרוב ביותר K # התוצאה 'התאמות' היא מספר ההתאמות הדומות שנמצאו בשתי התאמות התמונות = flann.knnMatch (descriptors_1, descriptors_2, k = 2) # אחסן התאמות טובות באמצעות מבחן היחס של Lowe good_matches = עבור m, n בהתאמות: אם m.distance <0.7 * n מרחק : good_matches.append (m) להחזיר len (good_matches) cap = cv2.VideoCapture (0) # טען את תבנית התמונה שלנו, זו תמונת התייחסות שלנו image_template = cv2.imread ('phone.jpg', 0) בעוד נכון: # קבל תמונות מצלמת רשת ret, frame = cap.read () # קבל גובה ורוחב גובה מסגרת מצלמת רשת , רוחב = frame.shape # הגדר ROI Box מידות top_left_x = int (רוחב / 3) top_left_y = int ((גובה / 2) + (גובה / 4)) bottom_right_x = int ((רוחב / 3) * 2) bottom_right_y = int ((גובה / 2) - (גובה / 4)) # צייר חלון מלבני לאזור העניין שלנו cv2. מלבן (מסגרת, (top_left_x, top_left_y,) (bottom_right_x, bottom_right_y), 255, 3) לחתוך חלון # ההתבוננות שהגדרנו לעיל קצוץ = מסגרת אוריינטציה מסגרת # הפוךאופקי מסגרת = cv2.flip (מסגרת, 1) # get מספר לנפות תואם גפרורים = sift_detector (קצוץ, תמונה_תבנית) # הצגת מחרוזת סטטוס המציגה את המספר הנוכחי. של התאמות cv2.putText (פריים, str (התאמות), (450,450), cv2.FONT_HERSHEY_COMPLEX, 2, (0,255,0), 1) # הסף שלנו לציין דטרקציה של אובייקט # אנו משתמשים ב- 10 שכן גלאי SIFT מחזיר מעט חיובי שווא סף = 10 # אם התאמות עולות על הסף שלנו אז אובייקט התגלה אם התאמות> סף: cv2.rectangle (frame, (top_left_x, top_left_y), (bottom_right_x, bottom_right_y), (0,255,0), 3) cv2.putText (frame, 'אובייקט נמצא', (50,50), cv2.FONT_HERSHEY_COMPLEX, 2, (0,255,0), 2) cv2.imshow ('גלאי אובייקטים באמצעות SIFT', מסגרת) אם cv2.waitKey (1) == 13: מספר 13 הוא שווי ההפסקה של Enter Key. Release () cv2.destroyAllWindows ()
איתור אובייקטים באמצעות ORB
זיהוי אובייקטים באמצעות SIFT הוא די מגניב ומדויק, מכיוון שהוא מייצר מספר התאמות מדויק בהרבה על סמך מקשי מקשים, אולם הוא מוגן בפטנט וזה מקשה על השימוש בו עבור היישומים המסחריים, והדרך האחרת היא אלגוריתם ORB לזיהוי אובייקטים.
בדומה לשיטת זיהוי האובייקטים על ידי SIFT בה חילקנו את התוכנית לשני חלקים, גם אחריה יבוצע כאן.
ראשית, אנו מגדירים את הפונקציה ORB_detector שלוקחת שתי קלטות האחת היא תמונת הזרם החי שמגיעה ממצלמת הרשת והשנייה היא תבנית התמונה שעל בסיסה אנו הולכים להתאים את התמונה שלנו. לאחר מכן אנו מגוונים את תמונת מצלמת הרשת שלנו ואז מבצעים אתחול לגלאי ה- ORB שלנו, ואנחנו קובעים אותה כאן על 1000 נקודות מפתח ופרמטרים של קנה מידה של 1.2. אתה יכול לשחק בקלות עם פרמטרים אלה, ואז לזהות את מקשי המקשים (kp) והמתארים (des) עבור שני התמונות והפרמטר השני שאנו מגדירים בפונקציה לזהות ומחשב הוא ללא, הוא מבקש להשתמש במסכת תמונה או לא, אנחנו מכחישים את זה כאן.
לאחר מכן עבר לגלאי בעבר השתמשנו בהתאמה מבוססת FLANN, אך כאן נשתמש ב- BFMatcher ובתוך BFMatcher אנו מגדירים שני פרמטרים האחד הוא NORM_HAMMING והשני הוא crossCheck שערכו הוא TRUE.
לאחר מכן חישבו את ההתאמות בין שתי התמונות באמצעות המתארים שהוגדרו לעיל, אשר בסך הכל מחזיר את מספר ההתאמות מכיוון שההתאמות הללו אינן קירוב ולכן אין צורך לבצע בדיקת יחס של Lowe, במקום זאת אנו ממיינים את ההתאמות על פי מרחק, לפחות המרחק יותר ההתאמה טובה יותר (כאן המרחק פירושו מרחק בין הנקודות), ובסוף אנו מחזירים את מספר ההתאמות באמצעות פונקציית האורך.
ובפונקציה העיקרית קבענו את הסף לערך גבוה בהרבה, מכיוון שגלאי כדור הארץ מייצר הרבה רעש.
עכשיו בואו נסתכל על קוד לזיהוי מבוסס ORB
ייבא cv2 ייבוא מטומטם כ np def ORB_detector (new_image, image_template): # פונקציה המשווה תמונת קלט לתבנית # ואז מחזירה את מספר התאמות ORB ביניהן image1 = cv2.cvtColor (new_image, cv2.COLOR_BGR2GRAY) # צור גלאי ORB עם 1000 מקשי קצב עם גורם פירמידה מתרחש של 1.2 orb = cv2. ORB_create (1000, 1.2) # זיהוי מקשי מקשים של תמונה מקורית (kp1, des1) = orb.detectAndCompute (image1, None) # זיהוי מקשי תמונה של תמונה מסובבת (kp2, des2) = orb.detectAndCompute (image_template, None) # צור התאמה # שים לב שאיננו משתמשים יותר בהתאמה מבוססת Flann bf = cv2.BFMatcher (cv2.NORM_HAMMING, crossCheck = True) # בצע התאמות = bf.match (des1, des2) # מיין את ההתאמות על פי מרחק. המרחק הקטן ביותר הוא התאמות טובות יותר = ממוינות (התאמות, מפתח = למבדה שווה: מרחק מרחק) להחזיר len (התאמות) כובע = cv2.VideoCapture (0) # טען את תבנית התמונה שלנו, זו תמונת התייחסות שלנו image_template = cv2.imread ('phone.jpg', 0) # image_template = cv2.imread ('images / kitkat.jpg', 0) בעוד נכון: # קבל תמונות מצלמת רשת ret, frame = cap.read () # קבל גובה ורוחב של גובה מסגרת מצלמת הרשת , width = frame.shape # הגדר ממדי תיבת ROI (שימו לב שחלק מהדברים האלה צריכים להיות מחוץ לולאה) top_left_x = int (רוחב / 3) top_left_y = int ((גובה / 2) + (גובה / 4)) bottom_right_x = int ((רוחב / 3) * 2) bottom_right_y = int ((גובה / 2) - (גובה / 4)) # צייר חלון מלבני עבורנו אזור עניין cv2.rectangle (frame, (top_left_x, top_left_y), (bottom_right_x, bottom_right_y), 255, 3) # יבול חלון תצפית שהגדרנו לעיל חתוך = מסגרת # הפוך את כיוון המסגרת אופקית מסגרת = cv2.flip (מסגרת, 1) # קבל מספר התאמות התאמה של ORB = ORB_detector (חתוך, תבנית תמונה) # הצגת מחרוזת סטטוס המציגה את המספר הנוכחי. of matches output_string = "Matches =" + str (matches) cv2.putText (frame, output_string, (50,450), cv2.FONT_HERSHEY_COMPLEX, 2, (250,0,150), 2) # הסף שלנו לציון דטרקציה של אובייקט # לתמונות חדשות או לתנאי הבהרה יתכן שתצטרך להתנסות קצת הערה: גלאי ה- ORB כדי להשיג את 1000 ההתאמות הראשונות, 350 הוא למעשה סף התאמה מינימלי של 35% = 250 # אם ההתאמות עולות על סף ואז אובייקט זוהה אם תואם> סף: cv2.rectangle (frame, (top_left_x, top_left_y), (bottom_right_x, bottom_right_y), (0,255,0), 3) cv2.putText (frame, 'אובייקט נמצא', (50, 50), cv2.FONT_HERSHEY_COMPLEX, 2, (0,255,0), 2) cv2.imshow ('גלאי אובייקטים באמצעות ORB', מסגרת) אם cv2.waitKey (1) == 13: # 13 הוא כובע ההפסקה של Enter Key .release () cv2.destroyAllWindows ()
היסטוגרמה של שיפועי אוריינטציה (HOG)
עכשיו בואו נדבר על מתאר אחר שהוא היסטוגרמה של שיפועים מכוונים (HOG).
HOG's הם מתארים די מגניבים ושימושיים והם משמשים באופן נרחב ומוצלח לזיהוי אובייקטים, כפי שראינו בעבר מתארי התמונות כמו SIFT ו- ORB, שם עלינו לחשב מקשי מקשים ואז עלינו לחשב מתארים מתוך נקודות המפתח האלה, אנשי HOG עושים את התהליך הזה. באופן שונה. הוא מייצג עצמים כווקטור תכונות יחיד לעומת קבוצה של וקטורי תכונות כאשר כל אחד מהם מייצג קטע מהתמונה. זה אומר שיש לנו תכונה וקטורית יחידה לכל התמונה.
זה מחושב על ידי גלאי חלונות הזזה מעל תמונה, כאשר מתאר HOG מחושב עבור כל מיקום. ואז כל עמדה משולבת עבור וקטור תכונה יחיד.
כמו SIFT, סולם התמונה מותאם על ידי פירמידה.
בעבר השתמשנו בהתאמות כמו FLANN ו- BFMatcher, אך HOGs עושים זאת בצורה שונה בעזרת מסווגי SVM (מכונת וקטור תמיכה), כאשר כל מתאר HOG שמחושב מוזן למסווג SVM כדי לקבוע אם האובייקט נמצא או לא.
הנה הקישור למאמר נהדר מאת דלאל וטריגס על שימוש ב- HOGs לגילוי אנושי:
היסטוגרמה של שיפועים מכוונים (HOG), שלב אחר שלב:
הבנת HOG יכולה להיות מורכבת למדי, אך כאן אנו נעסוק רק בתיאוריה של HOG מבלי להעמיק במתמטיקה הקשורה אליה.
אז בואו ניקח את התמונה הזו היא קצת מפוקסלת, ובפינה העליונה נמצאת כאן תיבת 8x8 פיקסלים, כך שבתיבה זו אנו מחשבים את וקטור השיפוע או כיווני הקצה בכל פיקסל. אז זה אומר שבתיבה זו אנו מחשבים את וקטור שיפוע התמונה של פיקסלים בתוך התיבה (הם סוג של כיוון או זרימה של עוצמת התמונה עצמה), וזה מייצר 64 וקטורי שיפוע (8 x 8) אשר מיוצגים אז כהיסטוגרמה. אז דמיין היסטוגרמה המייצגת כל וקטור מעבר. אז אם כל הנקודות או העוצמות שיקרו בכיוון אחד, ההיסטוגרמה לכיוון זה נניח 45 מעלות, ההיסטוגרמה תהיה בשיאה ב 45 מעלות.
אז מה שאנחנו עושים עכשיו זה שאנחנו מחלקים כל תא לפחים זוויתיים, כאשר כל סל מתאים לכיוון שיפוע (למשל x, y). בעיתון דלאל וטריגס השתמשו ב -9 פחים 0-180 מעלות (20 מעלות לכל סל). זה מפחית למעשה 64 וקטורים ל -9 ערכים בלבד. אז מה שעשינו מקטין את הגודל אבל שומר את כל המידע המרכזי הדרוש.
השלב הבא בחישוב החזירים הוא הנורמליזציה. אנו מנרמלים את הדרגתיות בכדי להבטיח שינויים בשינויי תאורה, כלומר בהירות וניגודיות.
בתמונה זו ערכי העוצמה מוצגים בריבוע לפי הכיוון בהתאמה ולכולם ההבדל של 50 זה לזה
∆ H = 50, ∆ v = 50; │∆│ = √50 2 +50 = 70.72, 70.72 / 100 = 0.707
אנו מחלקים את הווקטורים לפי עוצמת הדרגתיות שאנו מקבלים 0.707 לכולם, זו נורמליזציה.
באופן דומה, אם אנו משנים את העוצמה או משנים את הניגוד נקבל את הערכים שלהלן.
∆ H = 50, ∆ v = 50; │∆│ = √50 2 +50 = 70.72, 70.72 / 100 = 0.707; ∆ H = 100, ∆ v = 100; │∆│ = √100 2 +100 = 141.42, 141.42 / 100 = 1.41
הנורמליזציה אינה מתרחשת ברמת התא, במקום זאת היא מתרחשת ברמת בלוק, כך שכאן הבלוקים הם בעצם קבוצה של 4 תאים, זה לוקח בחשבון בלוקים שכנים כל כך מנורמלים תוך התחשבות בקטעים גדולים יותר של התמונה.
עכשיו בואו נסתכל על הקוד
ייבא מטומטם כמו np ייבא cv2 ייבא matplotlib.pyplot כ- plt # טען תמונה ואז תמונה בגווני אפור = cv2.imread ('elephant.jpg') אפור = cv2.cvt צבע (תמונה, cv2.COLOR_BGR2GRAY) # הצג תמונה מקורית cv2.imshow (' תמונת קלט ', תמונה) cv2.waitKey (0) # הגדרת הפרמטרים, גודל התא וגודל הבלוק # hxw בפיקסלים cell_size = (8, 8) # hxw בתאים block_size = (2, 2) # מספר פחי כיוון nbins = 9 # שימוש ב- HOG Descriptor של OpenCV # winSize הוא גודל התמונה שנחתכה לכפולה של גודל התא hog = cv2.HOGDescriptor (_winSize = (אפור. צורה // תא_גודל * תא_גודל, אפור. צורה // תא_גודל * תא_גודל), _blockSize = (גודל_תא * * גודל_תא, גודל_תא * גודל_תא), _blockStride = (גודל_תא, גודל_תא), _cellSize = (גודל_תא, גודל_תא), _ nbins = nbins) # צור צורת מערך מטופשת שבה אנו משתמשים כדי ליצור hog_features n_cells = (grey.shape // cell_size, grey.shape // cell_size) # ראשית אנו מקדמים בלוקים לפי שורות. # hog_feats מכיל כעת את משרעת השיפוע לכל כיוון, # לכל תא בקבוצה שלו לכל קבוצה. יצירת האינדקס היא לפי שורות ואז עמודות. hog_feats = hog.compute (אפור). reshape (n_cells - block_size + 1, n_cells - block_size + 1, block_size, block_size, nbins).transpose ((1, 0, 2, 3, 4)) # צור את מערך השיפועים שלנו עם ממדי nbin לאחסון כיווני מעבר צבעים מעבר np.zeros ((n_cells, n_cells, nbins)) # צור מערך של מימדים cell_count = np.full ((n_cells, n_cells, 1), 0, dtype = int) # נורמליזציה של חסום עבור off_y בטווח (block_size): עבור off_x בטווח (block_size): שיפועים - block_size + off_y + 1, off_x: n_cells - block_size + off_x + 1] + = \ hog_feats cell_count - block_size + off_y + 1, off_x: n_cells - block_size + off_x + 1] + = 1 # Gradients gradients gradients / = Cell_count # העלילה של HOGs באמצעות Matplotlib # זווית היא 360 / nbins * כיוון color_bins = 5 plt.pcolor (gradients) plt.gca (). invert_yaxis () plt.gca (). set_aspect ('שווה', מתכוונן = 'תיבה') plt.colorbar () plt.show () cv2.destroyAllWindows ()
התמונה מראה כיצד תמונת הקלט מיוצגת כייצוג HOG.
מסווגי מפל של HAAR
כפי שנדון בעבר, אנו יכולים לחלץ תכונות מתמונה ולהשתמש בתכונות אלה כדי לסווג או לזהות עצמים.
מהם מסווגי אשד של HAAR?
שיטת זיהוי אובייקטים המכניסה את מאפייני Haar לסדרת מסווגים (מפל) לזיהוי אובייקטים בתמונה. הם מאומנים לזהות סוג אחד של אובייקטים, אולם אנו יכולים להשתמש בכמה מהם במקביל, למשל גילוי עיניים ופנים יחד.
מסווגי HAAR הסבירו:
מסווגי HAAR מאומנים באמצעות הרבה תמונות חיוביות (כלומר תמונות עם האובייקט קיים)
ותמונות שליליות (כלומר תמונות ללא האובייקט קיים).
ברגע שיש לנו את התמונות האלה, אנו מחלצים תכונות באמצעות חלונות הזזה של בלוקים מלבניים. מאפיינים אלה (תכונות HAAR) מוערכים בודדים ומחושבים על ידי הפחתת סכום עוצמות הפיקסלים מתחת למלבנים הלבנים מהמלבנים השחורים.
עם זאת, זהו מספר מגוחך של חישובים, אפילו עבור חלון בסיס של 24 x 24 פיקסלים (180,000 תכונות שנוצרו).
לכן החוקרים תכננו שיטה בשם תמונות אינטגרליות שחישבה זאת עם ארבע הפניות למערך. עם זאת, עדיין היו להם 180,000 מאפיינים ורובם לא הוסיפו ערך ממשי.
Boosting שימש אז לקביעת התכונות האינפורמטיביות ביותר, עם AdaBoost של Freund & Schapire והוא מצא את התכונות האינפורמטיביות ביותר בתמונה. הגברה היא התהליך שבו אנו משתמשים בסווגים חלשים לבניית מסווגים חזקים, פשוט על ידי הקצאת עונשים משוקללים כבדים יותר על סיווגים שגויים. הפחתת 180,000 התכונות ל 6000, וזה עדיין לא מעט תכונות.
בתכונות 6000 אלה, חלקן יהיו אינפורמטיביות יותר מאחרות. אז אם השתמשנו בתכונות האינפורמטיביות ביותר כדי לבדוק תחילה אם האזור יכול להיות בעל פנים (תוצאות חיוביות שגויות לא יהיו עניין גדול). פעולה זו מבטלת את הצורך בחישוב כל 6000 התכונות בבת אחת. מושג זה מכונה Cascade of Classifiers - לצורך זיהוי פנים השתמשה שיטת ויולה ג'ונס ב -38 שלבים.
זיהוי פנים ועיניים
אז לאחר שנשיג ידע תיאורטי כלשהו על מפל ה- HAAR אנו הולכים ליישם אותו סוף סוף, כדי להבהיר את הדברים די ברור שנפרץ את השיעורים בחלקים, ראשית נגלה פנים קדמיות לאחר מכן נעבור לזהות פנים פרונטליות עם ולבסוף היינו מבצעים זיהוי חי של פנים ועיניים דרך מצלמת האינטרנט.
אז בשביל זה נשתמש במסווגים שהוכשרו מראש שסופקו על ידי OpenCV כקבצי.xml, xml מייצג שפת סימון הניתנת להרחבה, שפה זו משמשת לאחסון כמות עצומה של נתונים, אתה יכול אפילו לבנות עליה מסד נתונים.
תוכל לקבל גישה למסווגים אלה בקישור זה .
זיהוי פנים
בואו ננסה לאתר את זיהוי הפנים הקדמי, אתה יכול לקבל גישה למפל של גלאי הפנים הקדמיים כאן. פשוט לחלץ את קובץ ה- zip כדי לקבל את קובץ ה- XML.
ייבא numpy כ- np יבוא cv2 # אנו מצביעים על פונקציית CascadeClassifier של OpenCV למקום שבו מאוחסן המסווג # שלנו (פורמט קובץ XML), זכור לשמור את הקוד ואת המסווג באותה תיקיה face_cascade = cv2.CascadeClassifier ('haarcascade_frontalface_default.xml') # Load התמונה שלנו ואז ממירה אותה לתמונה בגווני אפור = cv2.imread ('Trump.jpg') אפור = cv2.cvtColor (תמונה, cv2.COLOR_BGR2GRAY) # המסווג שלנו מחזיר את החזר ה- ROI של הפנים שזוהו ככפול # הוא מאחסן את השמאלית העליונה קואורדינטות ובצד ימין למטה קואורדינטות # זה מחזיר את רשימת הרשימות, שהן המיקום של פנים שונות שזוהו. פרצופים = face_cascade.detectMultiScale (אפור, 1.3, 5) # כשאין פרצופים מזוהים, face_classifier חוזר וכפול ריק אם פרצופים הם (): הדפס ("לא נמצאו פרצופים") # אנו חוזרים דרך מערך הפנים שלנו ומציירים מלבן # על כל פנים בפנים עבור (x, y, w, h) בפנים: cv2.rangle (תמונה, (x, y), (x + w, y + h), (127,0,255), 2) cv2.imshow ('זיהוי פנים', תמונה) cv2.waitKey (0) cv2.destroyAllWindows ()
עכשיו בואו נשלב את זיהוי הפנים והעיניים יחד, תוכלו לקבל גישה למפל של גלאי העיניים באותו קובץ zip.
ייבא מטומטם כ- np יבוא cv2 face_classifier = cv2.CascadeClassifier ('haarcascade_frontalface_default.xml') eye_classifier = cv2.CascadeClassifier ('haarcascade_eye.xml') img = cv2.imread ('Trump.jpg') אפור = cv2.cv2. cv2.COLOR_BGR2GRAY) פרצופים = face_classifier.detectMultiScale (אפור, 1.3, 5) # כאשר לא זוהו פנים, Face_classifier מחזיר ריק tuple אם הפנים הם (): הדפס ("לא נמצאו פנים") עבור (x, y, w, h) בפנים: cv2. מלבן (img, (x, y), (x + w, y + h), (127,0,255), 2) cv2.imshow ('img', img) roi_gray = אפור roi_color = img עיניים = eye_classifier.detectMultiScale (roi_gray) cv2.waitKey (0) עבור (לשעבר, ey, ew, eh) בעיניים: cv2.rectangle (roi_color, (ex, ey), (ex + ew, ey + eh), (255,255,0), 2) cv2.imshow ('img', img) cv2.waitKey (0) cv2.destroyAllWindows () cv2.waitKey (0)
אז קוד זה זהה לזה של קוד לזיהוי הפנים, אך כאן הוספנו מפל עיניים ושיטה לאיתורם, כפי שניתן לראות בחרנו בגרסת הפנים בגודל אפור של הפנים כפרמטר לזיהוי MultiScale עבור העיניים, מה שמביא אותנו לירידה בחישוב שכן אנו הולכים לזהות עיניים רק באזור זה בלבד.
זיהוי פנים ועיניים חי
אז עד עכשיו עשינו איתור פנים ועיניים, עכשיו בואו נבצע את אותו הדבר עם זרם הווידאו החי ממצלמת האינטרנט. בכך אנו מבצעים את אותה זיהוי של פנים ועיניים אך הפעם נעשה זאת עבור השידור החי של מצלמת הרשת. ברוב היישום היית מוצא את הפנים שלך מודגשות עם תיבה מסביב, אבל כאן עשינו משהו אחרת שתמצא את הפנים שלך חתוכות ועיניים יזהו רק בזה.
אז לפה אנחנו מייבאים גם את מסווג הפנים וגם את העין, והגדרנו פונקציה לביצוע כל העיבוד לזיהוי הפנים והעיניים. ואחרי זה התחיל את זרם מצלמת הרשת והתקשר לפונקציית גלאי הפנים לצורך זיהוי הפנים והעיניים. הפרמטר שאנו מגדירים בתוך פונקציית גלאי הפנים הם התמונות הרציפות מזרם מצלמות רשת בשידור חי
ייבא cv2 ייבוא מטומטם כמו np face_classifier = cv2.CascadeClassifier ('haarcascade_frontalface_default.xml') eye_classifier = cv2.CascadeClassifier ('haarcascade_eye.xml') def face_detector (img, size = 0.5): # להמיר תמונה לגווני cv2. (img, cv2.COLOR_BGR2GRAY) פרצופים = face_classifier.detectMultiScale (אפור, 1.3, 5) אם פרצופים הם (): להחזיר img עבור (x, y, w, h) בפנים: x = x - 50 w = w + 50 y = y - 50 h = h + 50 cv2. מלבן (img, (x, y), (x + w, y + h), (255,0,0), 2) roi_gray = אפור roi_color = img עיניים = eye_classifier.detectMultiScale (roi_gray) עבור (לשעבר, ey, ew, eh) בעיניים: cv2.rectangle (roi_color, (ex, ey), (ex + ew, ey + eh), (0,0,255), 2) roi_color = cv2.flip (roi_color, 1) return roi_color cap = cv2. VideoCapture (0) בעוד נכון: ret, frame = cap.read () cv2.imshow ('Extractor Face' שלנו, face_detector (frame)) אם cv2.waitKey (1) == 13: # 13 הוא כובע הפסקה של Enter Key. release () cv2.destroyAllWindows ()
כוונון מסווגים של אשדות
הפרמטרים המוגדרים בתוך detectMultiScale מלבד תמונת הקלט הם בעלי המשמעות הבאה
המסווג שלנו. detectMultiScale (תמונת קלט, גורם קנה מידה, מיני שכנים)
- גורם קנה מידה מציין כמה אנו מקטינים את גודל התמונה בכל פעם שאנו משנים אותם. למשל בזיהוי פנים אנו משתמשים בדרך כלל ב -1.3. המשמעות היא שאנחנו מקטינים את התמונה ב -30% בכל פעם שמדובר בקנה מידה. ייקח זמן רב יותר לחישוב ערכים קטנים יותר, כמו 1.05, אך יגדילו את קצב הזיהוי.
- שכנים מינימליים מציין את מספר השכנים שכל חלון פוטנציאלי צריך שיהיה בכדי לראות בו גילוי חיובי. בדרך כלל מוגדר בין 3-6. זה משמש כקביעת רגישות, ערכים נמוכים יזהו לעיתים פנים מרובות על פני פנים בודדות. ערכים גבוהים יבטיחו פחות תוצאות חיוביות כוזבות, אך אתה עלול לפספס כמה פרצופים.
איתור מכוניות והולכי רגל בסרטונים
כעת נזהה הולכי רגל ומכוניות בסרטונים באמצעות מפל ה- HAAR, אך במקרה שלא נטען סרטון וקומפילציה של קוד ללא שגיאה עליכם לבצע את השלבים הבאים:
אם שום סרטון לא נטען לאחר הפעלת הקוד, ייתכן שיהיה עליך להעתיק את opencv_ffmpeg.dl שלנו מ : opencv \ sources \ 3rdparty \ ffmpeg כדי להדביק אותו במקום שבו פייתון שלך מותקן, למשל C: \ Anaconda2
לאחר העתקתו תצטרך לשנות את שם הקובץ בהתאם לגירסת OpenCV בה אתה משתמש. Eg אם אתה משתמש ב- OpenCV 2.4.13 ואז לשנות את שם הקובץ כך: opencv_ffmpeg2413_64.dll או opencv_ffmpeg2413.dll (אם אתה באמצעות מכונת X86) opencv_ffmpeg310_64.dll או opencv_ffmpeg310.dll (אם אתה משתמש במכונת X86)
כדי לברר היכן מותקן python.exe, פשוט הפעל את שתי שורות הקוד האלה, זה היה מדפיס את המיקום שבו מותקן הפיתון.
ייבוא הדפסת sys (sys.executable)
עכשיו אם ביצעת את הצעדים האלה בהצלחה, בוא נעבור לקוד לזיהוי הולכי רגל, אתה יכול לקבל את המפל לזיהוי הולכי רגל ומתוך קובץ ה- zip המצורף כאן.
ייבא cv2 ייבוא מטומטם כמו np # צור את מסווג הגוף שלנו body_classifier = cv2.CascadeClassifier ('haarcascade_fullbody.xml') # התחל לכידת וידאו לקובץ וידאו, כאן אנו משתמשים בקובץ הווידיאו בו יתגלו הולכי רגל cap = cv2.VideoCapture ('walking.avi') # לולאה לאחר שהווידאו נטען בהצלחה בזמן cap.is נפתח (): # קריאת כל פריים של הווידאו ret, frame = cap.read () # כאן אנו משנים את גודל המסגרת, למחצית מגודלה, אנו עושים כדי לזרז את הסיווג # מכיוון שלתמונות גדולות יותר יש הרבה יותר חלונות להחליק, כך שבסך הכל אנו מקטינים את הרזולוציה מספר וידאו בחצי זה מה שמציין 0.5, ואנחנו משתמשים גם בשיטת אינטרפולציה מהירה יותר שהיא #interlineear frame = cv2.resize (frame, None, fx = 0.5, fy = 0.5, interpolation = cv2.INTER_LINEAR) אפור = cv2. cvtColor (frame, cv2.COLOR_BGR2GRAY) # העבר מסגרת לגופי הסיווג של הגוף שלנו = body_classifier.detectMultiScale (אפור, 1.2, 3) # חלץ תיבות תוחמות לגופים שזוהו עבור (x, y, w, h) בגופים: cv2. מלבן (מסגרת, (x, y), (x + w, y + h), (0, 255, 255), 2) cv2.imshow ('הולכי רגל', מסגרת) אם cv2.waitKey (1) == 13: # 13 הוא מכסת הפסקת מפתח Enter. Release () cv2.destroyAllWindows ()
לאחר שזיהינו בהצלחה הולכי רגל בסרטון, בואו נעבור לקוד לזיהוי מכוניות, תוכלו לקבל את המפל לזיהוי הולכי רגל מכאן.
ייבוא cv2 יבוא זמן יבוא numpy כפי NP # יצירת הגוף שלנו מסווג car_classifier = cv2.CascadeClassifier ("haarcascade_car.xml") # ליזום לכידת וידאו עבור קובץ הווידאו כובע = cv2.VideoCapture ("cars.avi") # Loop לאחר שהסרטון הוא בהצלחה נטען בזמן cap.isOpened (): time.sleep (.05) # קרא את המסגרת הראשונה ret, frame = cap.read () אפור = cv2.cvtColor (frame, cv2.COLOR_BGR2GRAY) # העבר מסגרת למכוניות המסווג שלנו = מכונית סיווג .detectMultiScale (אפור, 1.4, 2) # תיבות תוחמות תמציות עבור כל הגופים שזוהו עבור (x, y, w, h) במכוניות: cv2.rangle (frame, (x, y), (x + w, y + h), (0, 255, 255), 2) cv2.imshow ('מכוניות', מסגרת) אם cv2.waitKey (1) == 13: # 13 הוא מכסת ההפסקה של Enter Key. release () cv2.destroyAllWindows ()
שמתם לב שהוספנו את time.sleep (.05) , זה רק עיכוב בקצב המסגרות, כך שתוכלו לאשר שכל המכוניות מזוהות כהלכה, או שתוכלו להסיר אותו פשוט על ידי הוספת תווית תגובה אליו.
מאמר זה מופנה מתוך Master Computer Vision ™ OpenCV4 בקורס Python with Deep Learning על Udemy, שנוצר על ידי Rajeev Ratan, הירשם כמנוי כדי ללמוד עוד על ראיית מחשבים ו- Python.