איך לבנות את אפליקציית ראייה ממוחשבת הראשונה ב-Android או ב-iOS

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

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

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

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

מה תפתחו

  • אפליקציה ל-Android שמאפשרת לסווג תמונה של פרח
  • (אופציונלי) אפליקציה ל-iOS שיכולה לסווג תמונה של פרח

מה תצטרך להכין

  • Android Studio זמין בכתובת https://developer.android.com/studio לחלק החלק של Android ב-Codelab
  • Xcode, זמין ב-Apple App Store, עבור החלק של iOS ב-Codelab

2. כדי להתחיל:

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

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

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

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

צריך להתחיל בתהליך של בניית האפליקציה ב-Android באמצעות Android Studio. (דלגו לשלב 7 כדי לבצע את הפעולה המקבילה ב-iOS).

  1. פותחים את Android Studio, עוברים לתפריט 'קובץ' ובוחרים באפשרות 'יצירת פרויקט חדש'.
  2. תתבקשו לבחור תבנית לפרויקט. בוחרים באפשרות 'פעילות ריקה'.

859b1875e37c321a.png

  1. לוחצים על Next. תתבקשו להגדיר את הפרויקט. נותנים לו כל שם ושם חבילה שרוצים, אבל קוד הדגימה ב-codelab הזה משתמש בשם הפרויקט ImageClassifierstep1 ובשם החבילה com.google.imageclassifierstep1.

ee3b6a81bad87b3.png

  1. בוחרים את השפה המועדפת עליכם: Kotlin או Java. בשיעור Lab זה נעשה שימוש ב-Cotlin, לכן אם אתם רוצים לעקוב במדויק, כדאי לכם לבחור ב-Kotlin.
  2. בסיום, לוחצים על 'סיום'. Android Studio ייצור את האפליקציה עבורך. יכול להיות שיחלפו כמה דקות כדי להגדיר את הכול.

3. ייבוא ספריית תוויות התמונות של ML

ערכת למידה חישובית (https://developers.google.com/ml-kit) מציעה כמה פתרונות למפתחים, שעומדים בתרחישים הנפוצים בלמידה חישובית ומאפשרים להטמיע ולעבוד בקלות בפלטפורמות שונות. ערכת ML מספקת ספרייה מוכנה לשימוש, שבה ניתן להשתמש באפליקציה הזו בשם 'תיוג תמונות'. ספרייה זו כוללת מודל שעבר אימון מראש כדי לזהות יותר מ-600 מחלקות של תמונות. לכן זו דרך מושלמת להתחיל בעבודה.

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

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

  1. ב-Android Studio, באמצעות סייר הפרויקטים, מוודאים שהאפשרות Android נבחרה בחלק העליון.
  2. פותחים את התיקייה Grele Scripts ובוחרים את קובץ ה-build.gradle של האפליקציה. יכול להיות שיש 2 קבצים או יותר, לכן חשוב לוודא שאתם משתמשים בסקריפט של האפליקציה כפי שמוצג כאן:

93c2e157136671aa.png

  1. בחלק התחתון של הקובץ יופיע קטע בשם תלויות, שבו נשמרת רשימה של הגדרות implementation, testImplementation ו-androidImplementation. הוספת קובץ חדש לקובץ עם הקוד הזה:
implementation 'com.google.mlkit:image-labeling:17.0.3'

(מוודאים שהדבר נמצא בתוך התלות { })

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

5ef40c7a719077a0.png

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

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

4. בניית ממשק המשתמש

ב-Android Studio, אפשר לערוך את ממשק המשתמש של כל מסך (או פעילות) באמצעות קובץ פריסה מבוסס XML. לאפליקציה הבסיסית שיצרת יש פעילות אחת (הקוד שלו הוא בMainActivity, ותוכלו לראות זאת בקרוב), והצהרת ממשק המשתמש נמצאת בactivity_main.xml.

ניתן למצוא את התיקייה בתיקייה res > הפריסה בסייר הפרויקטים של Android – כך:

3ed772e9563061e9.png

פעולה זו תפתח עורך מלא שיאפשר לכם לעצב את ממשק המשתמש של 'פעילות'. יש כאן הרבה מידע, והכוונה של שיעור ה-Lab הזה לא ללמד אתכם איך להשתמש בו. מידע נוסף על עורך הפריסה זמין בכתובת: https://developer.android.com/studio/write/layout-editor

למטרות שיעור Lab זה, בוחרים בכלי Code בפינה השמאלית העליונה של העורך.

1f7dbdef48d9ade6.png

כעת יוצג רק קוד XML בחלק הראשי של החלון. משנים את הקוד כך:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <ImageView
            android:id="@+id/imageToLabel"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
        <Button
            android:id="@+id/btnTest"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Label Image"
            android:layout_gravity="center"/>
        <TextView
            android:id="@+id/txtOutput"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:ems="10"
            android:gravity="start|top" />
    </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

כך תקבלו פריסה פשוטה במיוחד המכילה ImageView (לרינדור התמונה), Button (למשתמש יש ללחוץ) ו-TextView שבו התוויות יוצגו.

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

5. קיבוץ תמונות באמצעות האפליקציה

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

  1. בסייר הפרויקטים, באפליקציה שלמעלה, לוחצים לחיצה ימנית ובוחרים באפשרות ספרייה חדשה.
  2. בתיבת הדו-שיח שמופיעה עם רשימה שונה של ספריות, בוחרים באפשרות src/main/assets.

c93650ea68bb60e9.png

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

444b4afab73433b8.png

  1. לחץ לחיצה ימנית על התיקייה הזו, שתראה חלון קופץ עם רשימה של אפשרויות. אחת מהאפשרויות האלה היא לפתוח את התיקייה במערכת הקבצים. מחפשים את התוסף המתאים למערכת ההפעלה ובוחרים בו. (ב-Mac, הוא יהיה מוצג ב-Finder, ב-Windows הוא יהיה Open ב-Explorer, וב-Ubuntu הוא יוצג ב-Files).

95e0eca881d35f6b.png

  1. מעתיקים קובץ לקובץ. אפשר להוריד תמונות מאתרים כמו Pixabay. מומלץ לשנות את שם התמונה למשהו פשוט. במקרה כזה, שם התמונה שונה ל-flower1.jpg.

לאחר מכן, חוזרים ל-Android Studio ו אמורים לראות את הקובץ בתיקיית הנכסים.

cfa53c9c75a033d8.png

עכשיו אפשר להוסיף תווית לתמונה!

6. יש לכתוב את קוד הסיווג כדי להוסיף תווית לתמונה

(וחלק שכולנו כבר מחכים לו, שעושים דרך ראייה ממוחשבת ב-Android!)

  1. יש לכתוב את הקוד בקובץ MainActivity, לכן יש למצוא אותו בתיקיית הפרויקט בקטע com.google.devrel.imageclassifierstep1 (או במרחב השמות המקביל אם בחרת בקובץ אחר). הערה: בדרך כלל קיימות 3 תיקיות של מרחב שמות בפרויקט Android Studio, אחת לאפליקציה לבדיקה ואחת לבדיקה ל-Android. תמצאו את ה-MainActivity בשדה "תיאור" שלא מופיע אחריו בסוגריים.

b5aef8dd5e26b6c2.png

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

  1. פותחים את קובץ ה-MainActivity, ותוכלו לראות קובץ כיתה בשם MasterActivity בעורך הקוד. הוא אמור להיראות כך:
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }
}

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

  1. הוספת הקוד הזה:
// extension function to get bitmap from assets
fun Context.assetsToBitmap(fileName: String): Bitmap?{
    return try {
        with(assets.open(fileName)){
            BitmapFactory.decodeStream(this)
        }
    } catch (e: IOException) { null }
}

סביר להניח ש-Android Studio יתלונן בשלב הזה, וידגיש חלק מהקוד באדום, כמו Context, Bitmap וIOException:

d2bde17e3c04aeed.png

אל דאגה! הסיבה לכך היא שעדיין לא ייבאת את הספריות שמכילות אותן. ב-Android Studio יש קיצור דרך מועיל.

  1. גוררים את הסמן מעל המילה ומקישים על AltT + Enter (Option + Enter ב-Mac) והייבוא יופק עבורכם.
  2. לאחר מכן תוכלו לטעון את מפת סיביות מהנכסים ולהציב אותה ב-ImageView. חזרה ב-onCreateFunction של CentralActivity, יש להוסיף את הקוד הזה מתחת לשורה setContentView:
val img: ImageView = findViewById(R.id.imageToLabel)
// assets folder image file name with extension
val fileName = "flower1.jpg"
// get bitmap from assets folder
val bitmap: Bitmap? = assetsToBitmap(fileName)
bitmap?.apply {
    img.setImageBitmap(this)
}
  1. כמו קודם, חלק מהקוד יודגש באדום. כדי להוסיף את הייבוא באופן אוטומטי, מציבים את הסמן על אותה שורה ולוחצים על Alt + Enter / Option + Enter.
  2. בקובץ layout.xml שיצרת קודם, נתת ל-ImageView את השם imageToLabel, ולכן השורה הראשונה תיצור מופע של אובייקט ImageView, בשם img, באמצעות פרטי הפריסה האלה. היא מוצאת את הפרטים באמצעות findViewById, פונקציית Android מובנית. לאחר מכן היא משתמשת בשם הקובץ flower1.jpg כדי לטעון תמונה מתיקיית הנכסים באמצעות הפונקציה assetsToBitmap שיצרת בשלב הקודם. לבסוף, הוא משתמש במחלקה המופשטת של מפת סיביות כדי לטעון את מפת סיביות אל img.
  3. לקובץ הפריסה הייתה TextView שתשמש לעיבוד התוויות שהוסקו לגבי התמונה. צריך לקבל את אובייקט הקוד הבא. מוסיפים את הקוד הבא מייד מתחת לקוד הקודם:
val txtOutput : TextView = findViewById(R.id.txtOutput)

מוקדם יותר, מתבצע חיפוש של פרטי קובץ הפריסה של תצוגת הטקסט באמצעות השם שלה (יש לבדוק את ה-XML שבו הוא נקרא txtOutput) ולהשתמש בו כדי ליצור אובייקט TextView בשם txtOutput.

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

בקובץ הפריסה שלחנו ללחצן btnTest כדי שנוכל ליצור אותו באופן הבא:

val btn: Button = findViewById(R.id.btnTest)

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

לפני שממשיכים, צריך לוודא שקוד onCreate נראה כך:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    val img: ImageView = findViewById(R.id.imageToLabel)
    // assets folder image file name with extension
    val fileName = "flower1.jpg"
    // get bitmap from assets folder
    val bitmap: Bitmap? = assetsToBitmap(fileName)
    bitmap?.apply {
        img.setImageBitmap(this)
    }
    val txtOutput : TextView = findViewById(R.id.txtOutput)
    val btn: Button = findViewById(R.id.btnTest)
}

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

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

בלחיצה על הלחצן שיצרת עכשיו, אפשר לעשות את כל זה באירוע onClickListener שלו. זהו הקוד המלא:

btn.setOnClickListener {
  val labeler = ImageLabeling.getClient(ImageLabelerOptions.DEFAULT_OPTIONS)
  val image = InputImage.fromBitmap(bitmap!!, 0)
  var outputText = ""
  labeler.process(image)
    .addOnSuccessListener { labels ->
      // Task completed successfully
      for (label in labels) {
        val text = label.text
        val confidence = label.confidence
        outputText += "$text : $confidence\n"
      }
      txtOutput.text = outputText
  }
    .addOnFailureListener { e ->
      // Task failed with an exception
  }
}
  • כאשר המשתמש לוחץ על הלחצן בפעם הראשונה, הקוד יוצר אפקט של תווית באמצעות ה-ImageLabeling.getClient ומעבירים אותו ל-ImageLabelerOptions. השירות כולל נכס DEFAULT_OPTIONS שמאפשר לנו להתחיל לעבוד במהירות.
  • בשלב הבא, InputImage ייווצר ממפת הסיביות באמצעות שיטת fromBitmap. InputImage הוא הפורמט הרצוי של ML Kit&#39.
  • לבסוף, המתייג יעבד את התמונה ויספק קריאה אסינכרונית, בין אם היא מוצלחת או נכשלה. אם ההסקה בוצעה בהצלחה, הקריאה החוזרת תכלול רשימה של תוויות. לאחר מכן תוכלו לנתח את רשימת התוויות הזו כדי לקרוא את הטקסט של התווית ואת ערך המהימנות. אם הוא ייכשל, הוא ישלח לך חריגה שבה תהיה לך אפשרות לדווח למשתמש.

זהו, סיימתם. עכשיו אפשר להפעיל את האפליקציה במכשיר Android או באמולטור. אם מעולם לא עשית זאת, ניתן ללמוד כאן: https://developer.android.com/studio/run/emulator

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

c07f5f307f070dc7.png

לוחצים על הלחצן, ואז מקבלת קבוצת תוויות של התמונה.

550ccaa783363551.png

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

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

בשלבים הבאים נסביר איך לבנות את אותה אפליקציה ב-iOS.

7. יצירת מסווג תמונות ב-iOS - תחילת העבודה

אפשר ליצור אפליקציה דומה ב-iOS באמצעות Xcode.

  1. מפעילים את Xcode, ובתפריט הקובץ בוחרים באפשרות Project New (פרויקט חדש). תיבת הדו-שיח תופיע:

8fb0e6a9d6ac275e.png

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

76c6bdb5aee7659c.png

  1. אם אתם רוצים לפרוס את הטלפון בטלפון ולהגדיר פרופיל מפתח, תוכלו לקבוע מה יהיה הצוות. אם לא, משאירים את הלחצן ללא ומשתמשים בסימולטור iOS כדי להפעיל את האפליקציה.
  2. לוחצים על הבא ובוחרים תיקייה לאחסון הפרויקט והקבצים שבו. זכרו את מיקומו של הפרויקט. תצטרכו אותו בשלב הבא.
  3. כדאי לסגור את Xcode בשלב זה, מאחר שלאחר מכן יש לפתוח אותו מחדש באמצעות קובץ אחר של סביבת עבודה.

8. שילוב מכונת ML באמצעות Cocoapods

מאחר ש-ML Kit פועל גם ב-iOS, אפשר להשתמש בו באופן דומה מאוד לבניית מסווג תמונות. כדי לשלב את החשבון, יש להשתמש ב-CocoaPods. אם עוד לא התקנת את אפליקציית YouTube, אפשר לעשות זאת לפי ההוראות בכתובת https://cocoapods.org/

  1. פותחים את הספרייה שבה יצרתם את הפרויקט. הוא צריך להכיל את קובץ ה- .xcodeproj.

כאן תוכלו לראות את קובץ ה- .xcodeproj מציין אני ובמיקום הנכון.

e2966a47e84eb398.png

  1. בתיקייה הזו, יוצרים קובץ חדש בשם Podfile. אין תוסף, זה רק קובץ Podfile. בתוך הקובץ, מוסיפים את הערכים הבאים:
platform :ios, '10.0'

target 'ImageClassifierStep1' do
        pod 'GoogleMLKit/ImageLabeling'
end
  1. שומרים אותו וחוזרים למסוף. באותה ספרייה אפשר להקליד pod install. Cocoapods יוריד את הספריות והתלויות המתאימות ויצור סביבת עבודה חדשה שמשלבת את הפרויקט עם התלות החיצוניות שלו.

3b4c628b0cbface8.png

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

32090e0024b6b5ef.png

עכשיו אפשר לעבור לשלב הבא וליצור את ממשק המשתמש.

9. יצירת ממשק משתמש ל-iOS באמצעות לוחות סיפור

  1. פותחים את הקובץ Main.storyboard. מופיעה פריסה של ממשק המשתמש עם משטח עיצוב לטלפון.
  2. בפינה השמאלית העליונה של המסך מופיע לחצן + שבאמצעותו ניתן להוסיף פקדים. אפשר ללחוץ עליו כדי להוריד את לוח הבקרה.

e63bc3bafa54cc21.png

  1. משם, גוררים ומשחררים ImageView, לחצן ותווית על משטח העיצוב. יש לארגן אותם מלמעלה למטה כפי שהם מוצגים:

f9dfc55616b25f11.png

  1. לוחצים לחיצה כפולה על הלחצן כדי לערוך את הטקסט שלו מלחצן לסיווג.
  2. גוררים את נקודות האחיזה לפקדים סביב התווית כדי להגדיל אותה. (יש להגיד על אותו רוחב כמו ה-UIImageView והגובה כפול).
  3. כשהתווית עדיין מסומנת, לוחצים על הלחצן בוררים בפינה השמאלית העליונה כדי להציג את לוח הבודקים.
  4. לאחר מכן, מאתרים את ההגדרה שורות ומוודאים שהיא מוגדרת כ-0. כך התווית יכולה לעבד מספר דינמי של שורות.

a39708b320b56b30.png

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

10. יצירת פעולות ושקעים

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

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

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

77255f7d6284750.png

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

7eb21c7f9d43c9bc.png

  1. בוחרים את ה-UIImageView מתצוגת העיצוב שמימין, ולאחר מכן לוחצים על מקש ה-Control וגוררים אותו לקוד בצד שמאל, ומשחררים אותו מתחת למילת המפתח class (בשורה 11 בצילום המסך שלמעלה).

יוצג לך חץ בעת גרירה, וכשמשחררים אותך יופיע חלון קופץ כך:

37477f0611948318.png

  1. ממלאים את השדה Name בתור "imageView" ולוחצים על Connect.
  2. חוזרים על התהליך הזה עם התווית ונותנים לו את השם "lblOutput."
  3. חשוב: ללחצן, עליך לבצע את אותה פעולה, אבל יש להגדיר את סוג החיבור כפעולה ולא כשקע!

7281b6eea9fb6c23.png

  1. נותנים לו את השם "doClassification" ולוחצים על Connect.

לאחר שמסיימים, הקוד אמור להיראות כך: (שימו לב שהתווית ותצוגת התמונה הצהירות כ-IBOutlet (Interface Builder Outlet) והלחצן כ-IBAvision (Interface Builder Action)).

import UIKit

class ViewController: UIViewController {

    @IBAction func doClassification(_ sender: Any) {
    }
    @IBOutlet weak var imageView: UIImageView!
    @IBOutlet weak var lblOutput: UILabel!
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }

}
  1. לבסוף, אפשר לצרף תמונה לאפליקציה כדי שנוכל לסווג אותה בקלות. לשם כך, גוררים את הקובץ מסייר הקבצים אל הסייר שמימין ל-Xcode. כאשר תורידו אותו, יוצג לכם חלון קופץ כזה:

889ff33eaec785ec.png

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

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

11. כתיבת הקוד לסיווג תמונות

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

  1. התחילו על ידי סגירת מעצב הסטוריבורד על ידי לחיצה על X בפינה הימנית העליונה מעל משטח העיצוב. כך תוכלו להתמקד רק בקוד. כדי לערוך את המעבדה הזו, עורכים את ViewController.swift.
  2. אפשר לייבא את הספריות של MLKitVision ו-MLKit ImageLabeling על ידי הוספת הקוד בחלק העליון של הקובץ, מתחת לייבוא של UIKit:
import MLKitVision
import MLKitImageLabeling
  1. לאחר מכן, בתוך הפונקציה viewDidLoad, מפעילים את ה-ImageView באמצעות הקובץ שנארז באפליקציה:
override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view.
    imageView.image = UIImage(named:"flower1.jpg")
}
  1. יש ליצור פונקציית סיוע לקבלת התוויות של התמונה, מתחת ל-viewDidLoad():
func getLabels(with image: UIImage){
  1. יצירת VisionImage מהתמונה. ערכת ML משתמשת בסוג הזה כשמבצעים סיווג של תמונות. אז, בקטע 'פונקציה של getLabels', מוסיפים את הקוד הבא:
let visionImage = VisionImage(image: image)
visionImage.orientation = image.imageOrientation
  1. לאחר מכן יוצרים את האפשרויות של תווית התווית. האפשרות הזו תאופס באמצעות האפשרויות האלה. במקרה כזה, עליך להגדיר אפשרות בסיסית של confidenceThreshold. משמעות הדבר היא שתבקשו מהלייבל רק להחזיר תוויות שהמהימנות שלהן היא 0.4 ומעלה. לדוגמה, עבור הפרחים, מחלקות כמו "plant" או "petal" יקבלו רמת מהימנות גבוהה, אך ערכים כמו "basketball" או "car" יקבלו ערך נמוך.
let options = ImageLabelerOptions()
options.confidenceThreshold = 0.4
  1. עכשיו אפשר ליצור את התווית באמצעות האפשרויות הבאות:
let labeler = ImageLabeler.imageLabeler(options: options)
  1. אחרי שמוסיפים את התווית, אפשר לעבד אותה. היא תספק קריאה חוזרת אסינכרונית עם תוויות (אם היא הצליחה) ושגיאה (אם היא נכשלה), ולאחר מכן תוכלו לעבד פונקציה אחרת שאנחנו ניצור בעוד רגע.
labeler.process(visionImage) { labels, error in
    self.processResult(from: labels, error: error)
  }

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

לנוחיותכם, כאן מופיע הכיתוב

// This is called when the user presses the button
func getLabels(with image: UIImage){
    // Get the image from the UI Image element and set its orientation
    let visionImage = VisionImage(image: image)
    visionImage.orientation = image.imageOrientation

    // Create Image Labeler options, and set the threshold to 0.4
    // so we will ignore all classes with a probability of 0.4 or less
    let options = ImageLabelerOptions()
    options.confidenceThreshold = 0.4

    // Initialize the labeler with these options
    let labeler = ImageLabeler.imageLabeler(options: options)

    // And then process the image, with the callback going to self.processresult
    labeler.process(visionImage) { labels, error in
        self.processResult(from: labels, error: error)
 }
}

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

אחרי שמסיימים, אפשר פשוט לחזור על שורת התוויות, למשוך את התיאור ואת ערך הביטחון, ולהוסיף אותם אל var בשם labeltexts. לאחר שתחזרו על כל הפעולות, תוכלו פשוט להגדיר את הערך lblOutput.text לערך הזה.

הפונקציה המלאה:

// This gets called by the labeler's callback
func processResult(from labels: [ImageLabel]?, error: Error?){
    // String to hold the labels
    var labeltexts = ""
    // Check that we have valid labels first
    guard let labels = labels else{
        return
    }
  // ...and if we do we can iterate through the set to get the description and confidence
    for label in labels{
        let labelText = label.text + " : " + label.confidence.description + "\n"
        labeltexts += labelText
    }
    // And when we're done we can update the UI with the list of labels
    lblOutput.text = labeltexts
}

כל שעליך לעשות הוא להתקשר אל getLabels כשהמשתמש לוחץ על הלחצן.

כשיצרת את הפעולה, המערכת קווית את כל הנתונים בשבילך, ולכן עליך לעדכן את IBAction בשם doClassificaiton שיצרת קודם כדי להתקשר אל getLabels.

זהו הקוד לקרוא לו רק עם תוכן imageview:

@IBAction func doClassification(_ sender: Any) {
    getLabels(with: imageView.image!)
}

עכשיו אפשר להפעיל את האפליקציה ולנסות אותה. ניתן לראות אותה בפעולה:

eb8e6c1b2e2c65e0.png

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

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

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

12. מעולה!

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

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