4.16. תצוגה מקדימה של תמונה

מאגר חוצצי הפריימים הוא המקום שבו היישום קורא את הפריימים שלו. בעוד היישום עובד על הפריימים הללו, מה שמחובר למצלמה כדי להציג אותם בתצוגה מקדימה זקוק גם הוא לעותק של כל פריים. למצלמה יש חוצץ שני ייעודי למטרה זו, וכלל יחיד למתי הוא מתמלא: בכל פעם שהיישום קורא ל- snapshot(), הפריים הקודם שנלכד מועתק אל חוצץ התצוגה המקדימה לפני שהפריים החדש מוחזר.

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

4.16.1. חוצץ הפריימים של הזרם

חוצץ התצוגה המקדימה – חוצץ הפריימים של הזרם – הוא אזור יחיד בגודל קבוע ב-RAM הנפרד ממאגר חוצצי הפריימים. גודלו נקבע בזמן בניית הקושחה ואינו משתנה עם framesize() או pixformat(). כמגה-בייט אחד הוא טיפוסי ב-OpenMV Cams עדכניות – גדול מספיק כדי להכיל תצוגה מקדימה ברזולוציה בינונית, קטן בהרבה מפריים ברזולוציה מלאה בגדלי החיישן הגדולים ביותר.

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

4.16.2. מה תמונת בזק עושה עבור התצוגה המקדימה

בכל קריאה ל-snapshot(), לפני שמנהל ההתקן משחרר את חוצץ הפריימים הקודם של היישום בחזרה אל המאגר ומוסר את החדש, הוא מעתיק את הפריים הקודם אל חוצץ התצוגה המקדימה – עם כל מה שהיישום צייר מעליו במהלך העיבוד עדיין על התמונה. שני ענפים אפשריים. איזה מהם רץ נבחר על ידי המציג, ולא על ידי המצלמה: הצרכן שפתח את התצוגה המקדימה מודיע למנהל ההתקן אם הוא רוצה את התמונה הגולמית או JPEG, ואיזה גודל חלון גולמי הוא יכול לקבל.

  • עותק גולמי מוקטן. כאשר המציג ביקש פריימים גולמיים, מנהל ההתקן מעתיק את הפריים הקודם בפורמט הפיקסל המקורי שלו (RGB565, גווני אפור וכו«). אם הפריים גדול מחלון התצוגה הגולמי שהמציג ביקש, מנהל ההתקן מקטין אותו בסינון דו-ליניארי עד שהוא מתאים; אחרת הפיקסלים עוברים ללא שינוי. ללא ארטיפקטים של דחיסה; המציג רואה את אותם הפיקסלים שהיישום עבד עליהם.

  • דחיסת JPEG. כאשר המציג ביקש JPEG – או כאשר העותק הגולמי כלל לא יתאים בחוצץ הזרם – מנהל ההתקן דוחס את הפריים הקודם ב-JPEG ברזולוציה המלאה שלו אל תוך חוצץ הזרם. האיכות מותאמת אדפטיבית פר-פריים כך שהפלט הדחוס נשאר בתוך הקיבולת של חוצץ הזרם. כאשר פריים מתאים, מנהל ההתקן מעלה את האיכות בחזרה בצעד אחד לעבר תקרה התלויה בגודל הפיקסל של הפריים הלכוד (פריימים קטנים יותר רשאים לקבל איכות גבוהה יותר; פריימים גדולים יותר מוגבלים נמוך יותר כך שלא יוכלו לעבור את הקיבולת בעת שינוי תוכן קטן). כאשר פריים אינו מתאים, מנהל ההתקן חוצה לחצי את האיכות הנוכחית, מחזיק אותה ברמה המופחתת למשך כמה עשרות הפריימים הבאים כך שלהגדרה החדשה יהיה זמן להתייצב, ומשמיט את הפריים שהציף מהתצוגה המקדימה. לולאת היישום ממשיכה לרוץ ללא הפרעה; רק המציג מחמיץ את הפריים שנשמט.

פריימים שהמצלמה מפיקה בפורמט שכבר דחוס (פורמט הפיקסל JPEG בחיישנים הפולטים JPEG ישירות) מדלגים על שני הענפים: ה-bitstream המקודד מועתק ישירות אל חוצץ התצוגה המקדימה כפי שהוא.

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

4.16.3. דחיפת הפריים האחרון ידנית

מכיוון שהתצוגה המקדימה מתעדכנת כתופעת לוואי של snapshot(), סקריפט שמסתיים מבלי לקרוא שוב לתמונת בזק משאיר את מה ששלח אחרון לתצוגה המקדימה יושב אצל המציג ללא הגבלת זמן – מה שעבור סקריפט שמבצע את עבודתו לפני תמונת הבזק הראשונה ואז יוצא, הוא תצוגה מקדימה ריקה. image.Image.flush() (או המקבילה flush() על אובייקט CSI) מעתיק את התוכן הנוכחי של חוצץ הפריימים של היישום אל חוצץ הזרם לפי דרישה, מבלי ללכוד פריים חדש:

img = csi0.snapshot()
# process the image and draw on it
img.flush()                               # previewer sees the annotated frame

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

הערה

יישום התצוגה המקדימה צריך לקרוא את הפריים מתוך חוצץ הזרם לפני שהסקריפט יוצא. flush בסוף סקריפט קצר רק מעמיד את הפריים; אם הסקריפט מחזיר את השליטה למצלמה לפני שהמציג דגם, החוצץ יעשה בו שימוש חוזר בהרצה הבאה ואותו פריים אחרון יאבד. עבור תצוגות מקדימות בסוף סקריפט, תנו למציג רגע לאסוף את הפריים (sleep קצר לאחר ה-flush, או פשוט אי-יציאה מיידית) לפני שהסקריפט מסתיים.