מדריך למפתחים בנושא תמונות מורחבות ב-Android

איך משתמשים בתמונות משופר באפליקציות שלכם

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

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

יצירת מסד נתונים של תמונות

כל מסד נתונים של תמונות יכול לאחסן מידע לגבי עד 1,000 תמונות.

יש שתי דרכים ליצור AugmentedImageDatabase:

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

טעינה של מסד נתונים של תמונות שמורות

משתמשים ב-AugmentedImageDatabase.deserialize() כדי לטעון מסד נתונים קיים של תמונות:

JavaKotlin
AugmentedImageDatabase imageDatabase;
try (InputStream inputStream = this.getAssets().open("example.imgdb")) {
  imageDatabase = AugmentedImageDatabase.deserialize(session, inputStream);
} catch (IOException e) {
  // The Augmented Image database could not be deserialized; handle this error appropriately.
}
val imageDatabase = this.assets.open("example.imgdb").use {
  AugmentedImageDatabase.deserialize(session, it)
}

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

יצירת מסד נתונים חדש ריק

כדי ליצור מסד נתונים ריק של תמונות בזמן הריצה, משתמשים במגדיר AugmentedImageDatabase:

JavaKotlin
AugmentedImageDatabase imageDatabase = new AugmentedImageDatabase(session);
val imageDatabase = AugmentedImageDatabase(session)

הוספת תמונות למסד נתונים קיים

כדי להוסיף תמונות למסד הנתונים של התמונות, צריך להפעיל את AugmentedImageDatabase.addImage() לכל תמונה, ולציין widthInMeters אופציונלי.

JavaKotlin
Bitmap bitmap;
try (InputStream bitmapString = getAssets().open("dog.jpg")) {
  bitmap = BitmapFactory.decodeStream(bitmapString);
} catch (IOException e) {
  // The bitmap could not be found in assets; handle this error appropriately.
  throw new AssertionError("The bitmap could not be found in assets.", e);
}

// If the physical size of the image is not known, use addImage(String, Bitmap) instead, at the
// expense of an increased image detection time.
float imageWidthInMeters = 0.10f; // 10 cm
int dogIndex = imageDatabase.addImage("dog", bitmap, imageWidthInMeters);
val bitmap = assets.open("dog.jpg").use { BitmapFactory.decodeStream(it) }
// If the physical size of the image is not known, use addImage(String, Bitmap) instead, at the
// expense of an increased image detection time.
val imageWidthInMeters = 0.10f // 10 cm
val dogIndex = imageDatabase.addImage("dog", bitmap, imageWidthInMeters)

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

הפעלת מעקב אחר תמונות

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

JavaKotlin
Config config = new Config(session);
config.setAugmentedImageDatabase(imageDatabase);
session.configure(config);
val config = Config(session)
config.augmentedImageDatabase = imageDatabase
session.configure(config)

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

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

JavaKotlin
Collection<AugmentedImage> updatedAugmentedImages =
    frame.getUpdatedTrackables(AugmentedImage.class);
for (AugmentedImage img : updatedAugmentedImages) {
  if (img.getTrackingState() == TrackingState.TRACKING) {
    // Use getTrackingMethod() to determine whether the image is currently
    // being tracked by the camera.
    switch (img.getTrackingMethod()) {
      case LAST_KNOWN_POSE:
        // The planar target is currently being tracked based on its last
        // known pose.
        break;
      case FULL_TRACKING:
        // The planar target is being tracked using the current camera image.
        break;
      case NOT_TRACKING:
        // The planar target isn't been tracked.
        break;
    }

    // You can also check which image this is based on img.getName().
    if (img.getIndex() == dogIndex) {
      // TODO: Render a 3D version of a dog in front of img.getCenterPose().
    } else if (img.getIndex() == catIndex) {
      // TODO: Render a 3D version of a cat in front of img.getCenterPose().
    }
  }
}
val updatedAugmentedImages = frame.getUpdatedTrackables(AugmentedImage::class.java)

for (img in updatedAugmentedImages) {
  if (img.trackingState == TrackingState.TRACKING) {
    // Use getTrackingMethod() to determine whether the image is currently
    // being tracked by the camera.
    when (img.trackingMethod) {
      AugmentedImage.TrackingMethod.LAST_KNOWN_POSE -> {
        // The planar target is currently being tracked based on its last known pose.
      }
      AugmentedImage.TrackingMethod.FULL_TRACKING -> {
        // The planar target is being tracked using the current camera image.
      }
      AugmentedImage.TrackingMethod.NOT_TRACKING -> {
        // The planar target isn't been tracked.
      }
    }

    // You can also check which image this is based on AugmentedImage.getName().
    when (img.index) {
      dogIndex -> TODO("Render a 3D version of a dog at img.getCenterPose()")
      catIndex -> TODO("Render a 3D version of a cat at img.getCenterPose()")
    }
  }
}

תמיכה בתרחישי שימוש שונים

כש-ARCore מזהה תמונה מורחבת, היא יוצרת Trackable לאותה תמונה מורחבת ומגדירה את TrackingState לערך TRACKING ואת TrackingMethod לערך FULL_TRACKING. כשהתמונה שבמעקב יוצאת מהטווח של המצלמה, ARCore משנה את הערך של TrackingMethod ל-LAST_KNOWN_POSE תוך המשך מתן המידע על הכיוון והמיקום של התמונה.

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

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

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

תרחיש לדוגמה תמונה קבועה תמונה מונפשת
דוגמה פוסטר שתלוי על קיר מודעה בצד של אוטובוס
אפשר
להתייחס לתנוחה כתקפה אם
TrackingState == TRACKING TrackingState == TRACKING
וגם
TrackingMethod == FULL_TRACKING

ראה גם