Checkers Cheaters Eliran Moyal & Moti Berger מבוא 1 בפרוייקט שלנו ממשנו זיהוי לוח דמקה וכלי המשחק עליו יחד עם הצגת המהלך האופטימלי במהירות רבה. המשימה התחלקה למספר תתי משימות: זיהוי לוח המשחק. זיהוי כלי המשחק. מציאת המהלך האופטימלי והצגתו. ממשק השחקן מצלם את לוח הדמקה על ידי לחיצה על המסך. לאחר מכן, יוצג במרכז המסך לוח המשחק כאשר עליו יוצג חץ אחד או יותר במרווח זמן של 055 מילישניות בין חץ לחץ על מנת להמחיש את הצעד האופטימלי. על מנת לצלם את לוח הדמקה פעם נוספת, יש ללחוץ על כפתור ה- Retry הנמצא מימין ללוח הדמקה )כפתור זה יופיע רק לאחר הצילום ויעלם לאחר לחיצה עליו(. כמו כן, על מנת לתמוך בתצורת משחק בה ישנם מלכים, יש ללחוץ על כפתור ה- Place Kings הנמצא משמאל ללוח הדמקה )כפתור זה יופיע רק לאחר הצילום(. לאחר לחיצה זו, על השחקן ללחוץ על כלי המשחק שברצונו להצהיר עליהם כמלכים. לאחר שסיים השחקן לסמן את המלכים )שלו ושל היריב(, עליו ללחוץ על כפתור ה-.Solve כפתור זה מופיע במקום כפתור ה- Place Kings לאחר שזה נלחץ. לאחר שכפתור ה- Solve נלחץ, הוא יעלם ובמקומו יופיע כפתור ה- Place Kings בשנית. הועמדה לרשות השחקן היכולת להתאים את הפרמטרים של האלגוריתם )ראה בהמשך( על מנת להתאים אותו ללוחות ותנאי תאורה משתנים. על מנת לגשת לפרמטרים אלה, על המשתמש ללחוץ על הכפתור המציג את התפריט ולבחור ב-.Settings 1 אופטימלי ביחס להיוריסטיקות שבחרנו להשתמש בהן על מנת להעריך את טיב המצב הנוכחי של הלוח.
הFLOW : 1. מסך אשר מראה את המצלמה, נלחץ על כל מקום לצילום 2. קבלת מהלך אופטימלי ע"י חץ ירוק: 3. לאחר לחיצה על סימון מלכים )PlaceKings( נוכל ללחוץ על חיילים והודעה על הפיכתם למלך תופיע
4. נלחץ על SOLVE ומהלך אופטימלי אשר מתחשב במלכים יופיע:
מימוש זיהוי לוח המשחק: על מנת לעשות זאת, אנחנו משתמשים בפילטר על מנת לזהות את כל הנקודות המתקבלות ממפגש משבצות מהצורה: לאחר מכן, אנחנו מחשבים את המרחק בין הנקודות החיצוניות ביותר שמצאנו לבין הנקודות הנמצאות באלכסון מהן פנימה, באופן הבא: כאשר הנקודות הכחולות הן הנקודות החיצוניות ביותר והנקודות הירוקות הן הנקודות אשר אנו מחשבים את המרחק מהם אל הכחולים )נקרא למרחק הזה d(. בשלב הבא, אנחנו מוצאים את הנקודות הנמצאות במרחק d מהנקודות הכחולות בכיוון השני. הנקודות הללו מהוות את קצוות הלוח.
זיהוי לוח המשחק מתבצע ע"י פונקציה שלנו בשם.findCheckersBoardWithFilter הפונקציה מבצעת את הדברים הבאים: אם הפרמטר החמישי של הפונקציה )usebinaryfilterbefore( הוא,True אזי 1. מייצרת תמונה בינארית ע"י שימוש בפונקציה threshold של הספרייה Imgproc על מנת ליצור ערכים אחידים יותר בנקודות המקסימום בלי binaryfilter אם יש תאורה חזקה על צד אחד של הלוח נקודות המקסימום במקום אחד בלוח שונות ממקום אחר. בונה פילטר כפי שתואר לעיל יחד עם נורמליזציה לאיבריו חלוקה ב kernelsize^2 2/ 2. על מנת לא לחרוג מערכי הלבן )200( הפילטר הוא מהצורה: 1 1 1 1 1 1 1 1 1 1 1 1 [ 1 1 1 1 ] 20x20 כאשר המטריצה )המגדירה את הפילטר( מחולקת ל- 4 בלוקים בגודל 10x10, כאשר שני בלוקים מכילים 1 נמצאים על האלכסון הראשי ושני הבלוקים האחרים המכילים 1- נמצאים על האלכסון המשני. 3. משתמשת בפונקציה filter2d של הספרייה Imgproc על מנת להעביר את הפילטר על פני התמונה. 4. מוצאת את כל הנקודות שעברו את סף מסוים )מוגדר על ידי הפרמטר filterthresh מהקונפיגורציה, דיפולטי 255( 0. מסירה נקודות רחוקות מדי )מתייחסים אליהם כאל רעש(. הפרמטר הרביעי לפונקציה זו הוא maxdistbetweentwopoints והוא מגדיר מהו המרחק המקסימלי בין שתי נקודות )הוגדר hard-coded ל- 05 ב-,)MainActivity אם יש נקודה שנמצאת במרחק גדול מזה מנקודה אחרת היא מסוננת 6. אם בשלב הזה לא נמצאו לפחות 8 נקודות, לא ניתן יהיה למצוא את הלוח ועל כן מוצגת הודעה מתאימה לשחקן ועליו לצלם את לוח הדמקה פעם נוספת. 7. אחרת, מאתרים את ארבעת הנקודות החיצוניות ביותר ואת הנקודה הנמצאת באלכסון מכל אחת מהנקודות החיצוניות על מנת לקבל את המרחק ביניהן ולהשליך אותו לכיוון השני. המרחק הזה מהנקודות החיצוניות )בכיוון המנוגד לכיוון בו נמצאות הנקודות הפנימיות יותר( הוא המרחק אל פינות הלוח. 8. מבצעת הטלה פרספקטיבית מארבעת הנקודות הללו לארבע פינות של ריבוע בגודל 455 על 455 במטרה ליצור לוח הזהה בזוויותיו ללוח המקורי. זיהוי כלי המשחק: לאחר שזיהינו את לוח המשחק, אנו יודעים את גודלו ומכאן גם את גודלה של כל משבצת. אנחנו מניחים כי כלי המשחק שיעשה בהם שימוש אינם עולים בגודלם על המשבצות )כמובן מניחים שכלי המשחק הם בצורת עיגול(. האלגוריתם שבו השתמשנו על מנת לזהות עיגולים פועל טוב יותר כאשר ישנו חסם על גודלו של העיגול שאותו רוצים למצוא, דבר שאנו יכולים בקלות לדעת בשלב הזה. זיהוי כלי המשחק מתבצע ע"י פונקציה שלנו בשם.findAllCircles הפונקציה מקבלת את הפרמטרים הבאים: 1. תמונה של לוח המשחק לאחר עיבוד ראשוני )פלט של פונקצית זיהוי לוח המשחק(. 2. סף עבור.Canny 3. סף עבור זיהוי מרכזי העיגולים פרמטר לhoughcircles אשר מגדיר את הסף לזיהוי העיגול על פי כמות הנקודות שנמדדו מהרדיוס.
הפונקציה מחזירה רשימה של מרכזי עיגולים ורדיוס של העיגול המינימלי. זיהוי העיגולים מתבצע באופן הבא: השתמשנו בפונקציה HoughCircles של הספרייה.Imgproc נרחיב על הפרמטרים העיקריים: המרחק המינימלי בין שני עיגולים הוא 85% מגודל של משבצת. רדיוס מינימלי עבור עיגול הוא 35% מגודל של משבצת. רדיוס מקסימלי עבור עיגול הוא 45% מגודל של משבצת. - נבחר אחרי אופטימיזציות על כמה סף נמוך עבור זיהוי מרכזי העיגולים 20 תמונות כך שמזהים את השחורים ועם כמות קטנה של.false alarms בהמשך, ב-,MainActivity אנו בודקים אם פונקצית זיהוי כלי המשחק החזירה למעלה מ- 24 עיגולים. במידה וכן, אנחנו מציגים הודעה אינפורמטיבית ומפסיקים את האלגוריתם שכן מצב זה אינו תקין )מספר מקסימלי של כלי משחק בדמקה במצב תקין הוא 12 לכל שחקן(. באותה מידה, אם לא נמצאו עיגולים כלל, מוצגת הודעה אינפורמטיבית לשחקן והאלגוריתם נעצר. מציאת המהלך האופטימלי והצגתו: מימשנו את אלגוריתם החיפוש Minimax ואת האופטימיזציה שלו.Alpha-Beta כמו כן, הגדרנו מספר יוריסטיקות: ככל שכמות כלי משחק רבים יותר, כך מצב משחק טוב יותר. ככל שיש יותר כלי משחק בסכנת אכילה, כך מצב המשחק רע יותר. ככל שהשחקנים נמצאים קרוב יותר לבית של היריב וככל שיש יותר מלכים, כך מצב המשחק טוב יותר. הגדרנו היוריסטיקה נוספת המשלבת את שלושת היוריסטיקות הללו כאשר השפעתה של כל יוריסטיקה על התוצאה הסופית הוא שונה. באלגוריתם החיפוש אנו מסתכלים כברירת מחדל 4 מהלכים קדימה )ניתן לשינוי במסך ההגדרות( על מנת לא לעכב את תצוגת המהלך האופטימלי לשחקן. במידה ולשחקן יש מהלך אותו הוא יכול לבצע, תוצג לו אנימציה של המהלך באמצעות חצים. הצגת המהלך: אנו טוענים תמונה של חץ הנמצא בזווית של 40 מעלות נגד כיוון השעון. מכיוון שמהלך הוא רשימה של צעדים )כאשר צעד מוגדר כהתקדמות למשבצת קרובה או אכילה של כלי משחק אחד של השחקן היריב(, עבור כל אחד מהם אנחנו מחשבים את הזווית של הצעד ומסובבים את תמונת החץ בהתאם. סיבוב התמונה נעשה ע"י בניית מטריצת סיבוב באמצעות הפונקציה getrotationmatrix2d של הספרייה Imgproc והסיבוב עצמו ע"י הפונקציה warpaffine של הספרייה.Imgproc לאחר מכן, אנחנו מרחיבים את התמונה של החץ לאחר הסיבוב כך שהיא תהיה בגודל של תמונת הלוח. ההרחבה נעשית באמצעות הפונקציה copymakeborder של הספרייה.Imgproc הצמדת התמונה של החץ על תמונת לוח המשחק נעשית באמצעות הפונקציה.Core של הספרייה addweighted
תוצאות ומגבלות מגבלות האלגוריתם: כאשר הזווית בין הנורמל של לוח הדמקה לבין המצלמה היא גדולה מדי האלגוריתם מתקשה לזהות את העיגולים השחורים. יש לצלם כך שהמצלמה יחסית אנכית ללוח ולא הפילטר לא יעבוד. כאשר אין מספיק תאורה לא ניתן לזהות את המתאר של עיגולים שחורים על שחור. ביבליוגרפיה ויקיפדיה מצגות הקורס http://docs.opencv.org/doc/tutorials/imgproc/imgtrans/hough_circle/hough _circle.html