בניית המרות וביצוע בריכות

1. לפני שמתחילים

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

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

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

דרישות מוקדמות

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

מה תלמדו

  • מהן המרות
  • איך ליצור מפת תכונות
  • מה זה מאגר

מה תיצור

  • מפת תכונות של תמונה

מה צריך?

תוכלו למצוא את הקוד עבור שאר קוד הקוד פועל ב-Colab.

צריך גם להתקין את TensorFlow ואת הספריות שהתקנתם ב-Codelab הקודם.

2. מהן המרות?

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

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

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

למשל:

תנועת גולשים בתמונה

במקרה כזה, צוינה מטריצה של המרה מסוג 3x3, או תמונה גרעינית.

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

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

תוכיחו זאת באמצעות התמונה שמופיעה מ-SciPy. זוהי תמונה מובנית ונעימה עם זוויות וקווים רבים.

3. התחלת הקידוד

התחילו על ידי ייבוא של מספר ספריות Python ותמונת העלייה:

import cv2
import numpy as np
from scipy import misc
i = misc.ascent()

בשלב הבא מציירים את תמונת הספרייה של matplotlib כך שתוכלו לדעת איך היא נראית:

import matplotlib.pyplot as plt
plt.grid(False)
plt.gray()
plt.axis('off')
plt.imshow(i)
plt.show()

edb460dd5397f7f4.png

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

התמונה מאוחסנת כמערך NumPy, כדי שנוכל ליצור את התמונה שעברה טרנספורמציה על ידי העתקת המערך. משתני size_x ו-size_y יקיימו את המידות של התמונה, כדי שתוכל להעביר את העכבר מעליה מאוחר יותר.

i_transformed = np.copy(i)
size_x = i_transformed.shape[0]
size_y = i_transformed.shape[1]

4. יצירת מטריצת החיבורים

תחילה, יוצרים מטריצה של פיתול (או ליבה) כמערך בגודל 3x3:

# This filter detects edges nicely
# It creates a filter that only passes through sharp edges and straight lines. 
# Experiment with different values for fun effects.
#filter = [ [0, 1, 0], [1, -4, 1], [0, 1, 0]] 
# A couple more filters to try for fun!
filter = [ [-1, -2, -1], [0, 0, 0], [1, 2, 1]]
#filter = [ [-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]
 # If all the digits in the filter don't add up to 0 or 1, you 
# should probably do a weight to get it to do so
# so, for example, if your weights are 1,1,1 1,2,1 1,1,1
# They add up to 10, so you would set a weight of .1 if you want to normalize them
weight  = 1

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

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

לבסוף, טוענים את הערך החדש בתמונה שהומרה:

for x in range(1,size_x-1):
  for y in range(1,size_y-1):
      output_pixel = 0.0
      output_pixel = output_pixel + (i[x - 1, y-1] * filter[0][0])
      output_pixel = output_pixel + (i[x, y-1] * filter[0][1])
      output_pixel = output_pixel + (i[x + 1, y-1] * filter[0][2])
      output_pixel = output_pixel + (i[x-1, y] * filter[1][0])
      output_pixel = output_pixel + (i[x, y] * filter[1][1])
      output_pixel = output_pixel + (i[x+1, y] * filter[1][2])
      output_pixel = output_pixel + (i[x-1, y+1] * filter[2][0])
      output_pixel = output_pixel + (i[x, y+1] * filter[2][1])
      output_pixel = output_pixel + (i[x+1, y+1] * filter[2][2])
      output_pixel = output_pixel * weight
      if(output_pixel<0):
        output_pixel=0
      if(output_pixel>255):
        output_pixel=255
      i_transformed[x, y] = output_pixel

5. בחינת התוצאות

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

# Plot the image. Note the size of the axes -- they are 512 by 512
plt.gray()
plt.grid(False)
plt.imshow(i_transformed)
#plt.axis('off')
plt.show()   

48ff667b2df812ad.png

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

אם תשתמשו במספרים [ -1,0,1,-2,0,2,-1,0,1], תקבלו סט חזק מאוד של קווים אנכיים:

מזהה מסנן של קווים אנכיים

אם תשתמשו בערך [-1,-2,-1,0,0,0,1,2,1], יוצגו לכם קווים אופקיים:

זיהוי קווים אופקיים

אפשר לגלות ערכים שונים. בנוסף, אפשר לנסות מסננים בגודל אחר, כמו 5x5 או 7x7.

6. הסבר על המאגר

עכשיו, לאחר שזיהית את התכונות החיוניות של התמונה, מה את/ה עושה? איך אתם משתמשים במפת התכונות שנוצרה כדי לסווג תמונות?

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

יש כמה סוגים שונים של בריכות, אבל אתה משתמש בשיטה שנקראת "מקסימום" (מקסימום).

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

7. כתיבת קוד למאגר

הקוד הבא יציג מאגר של (2, 2) של מאגר. מריצים אותו כדי לראות את הפלט.

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

new_x = int(size_x/2)
new_y = int(size_y/2)
newImage = np.zeros((new_x, new_y))
for x in range(0, size_x, 2):
  for y in range(0, size_y, 2):
    pixels = []
    pixels.append(i_transformed[x, y])
    pixels.append(i_transformed[x+1, y])
    pixels.append(i_transformed[x, y+1])
    pixels.append(i_transformed[x+1, y+1])
    pixels.sort(reverse=True)
    newImage[int(x/2),int(y/2)] = pixels[0]
 
# Plot the image. Note the size of the axes -- now 256 pixels instead of 512
plt.gray()
plt.grid(False)
plt.imshow(newImage)
#plt.axis('off')
plt.show()

1f5ebdafd1db2595.png

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

8. מזל טוב

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