صور ARCore المعزَّزة

1. نظرة عامة

ARCore هو نظام أساسي لإنشاء تطبيقات الواقع المعزّز على Android. تتيح لك ميزة الصور المعزَّزة إنشاء تطبيقات الواقع المعزّز التي يمكنها التعرّف على الصور الثنائية الأبعاد المسجَّلة مسبقًا في العالم الواقعي وتثبيت المحتوى الافتراضي فوقها.

يرشدك هذا الدرس التطبيقي حول الترميز خلال عملية تعديل نموذج تطبيق ARCore الحالي من أجل دمج "الصور المعزَّزة" المتحركة أو الثابتة في مكانها.

ما الذي ستقوم ببنائه

في هذا الدرس التطبيقي حول الترميز، ستعتمد على نموذج تطبيق ARCore موجود مسبقًا. في نهاية الدرس التطبيقي حول الترميز، سيتمكّن تطبيقك من إجراء ما يلي:

  • اكتشِف أهدافًا للصور وثبِّت متاهة افتراضية على الهدف.
  • تتبَّع الهدف المتحرّك طالما أنّه في وضع الكاميرا.

6bc6605df89de525.gif

هل هذه هي المرة الأولى التي تنشئ فيها تطبيق ARCore؟

نعم لا

هل تخطط لكتابة رمز نموذجي في هذا الدرس التطبيقي حول الترميز أم تريد قراءة هذه الصفحات فقط؟

كتابة نموذج الرمز اقرأ هذه الصفحات فقط

ما ستتعرَّف عليه

  • كيفية استخدام الصور المعزَّزة في ARCore بلغة Java
  • كيفية قياس قدرة ARCore على التعرّف على صورة
  • كيفية إرفاق محتوى افتراضي على صورة وتتبُّع حركته

المتطلبات الأساسية

ستحتاج إلى أجهزة وبرامج معيّنة لإكمال هذا الدرس التطبيقي حول الترميز.

متطلبات الأجهزة

متطلبات البرامج

  • ARCore APK 1.9.0 أو إصدار أحدث. يتم عادةً تثبيت حزمة APK هذه تلقائيًا على الجهاز عبر متجر Play
  • جهاز تطوير يتضمن Android Studio (الإصدار 3.1 أو إصدار أحدث)
  • الاتصال بالإنترنت، حيث ستحتاج إلى تنزيل المكتبات أثناء التطوير

لنبدأ الآن بعد أن أصبح كل شيء جاهزًا.

2. إعداد بيئة التطوير

تنزيل حزمة SDK

سنبدأ بتنزيل أحدث إصدار من ARCore Android SDK من GitHub. فك ضغط الملف إلى موقعك المفضل. بالنسبة إلى هذا الدرس التطبيقي، إنّ الإصدار 1.18.1 الأقدم من حزمة SDK هو. ستتم الإشارة إلى المجلد باسم "arcore-android-sdk-x.xx.x"، وستكون القيمة الدقيقة هي إصدار حزمة تطوير البرامج (SDK) الذي تستخدمه.

افتح "استوديو Android" وانقر على فتح مشروع حالي في "استوديو Android".

5fbf2b21609187cc.png

انتقل إلى هذا المجلد غير المضغوط:

arcore-android-sdk-x.xx.x/samples/augmented_image_java

انقر على فتح.

انتظِر إلى أن تنتهي "استوديو Android" من مزامنة المشروع. إذا لم يكن "استوديو Android" يحتوي على المكونات المطلوبة، قد يتعذّر عرضه مع رسالة Install missing platform and sync project. اتّبِع التعليمات لحلّ المشكلة.

تشغيل نموذج التطبيق

الآن بعد أن أصبح لديك مشروع تطبيق ARCore قيد التشغيل، لنجربه.

وصِّل جهاز ARCore بجهاز التطوير، واستخدِم القائمة Run (تشغيل) > شغِّل "التطبيق" لتشغيل إصدار تصحيح الأخطاء على الجهاز. في مربّع الحوار الذي يطلب منك اختيار الجهاز الذي تريد تشغيله، اختَر الجهاز المتصل وانقر على حسنًا.

1aa2c6faa7ecdbd0.png

92e4c144a632b4ca.png

يستخدم هذا النموذج النموذجي من المشروع targetSdkVersion 28. إذا كان لديك خطأ إصدار مثل Failed to find Build Tools revision 28.0.3، اتّبِع التعليمات الموضّحة في "استوديو Android" لتنزيل الإصدار المطلوب من "أدوات إنشاء تطبيقات Android" وتثبيته.

في حال نجاح الإجراء، سيتم تشغيل نموذج التطبيق على الجهاز وسيطلب منك الحصول على إذن للسماح لميزة "صورة محسَّنة" بالتقاط الصور والفيديوهات. انقر على السماح لمنح الإذن.

الاختبار باستخدام نموذج صورة

الآن وبعد إعداد بيئة التطوير، يمكنك اختبار التطبيق من خلال إعطائه صورة للاطلاع عليها.

الرجوع في "استوديو Android" إلى نافذة المشروع والانتقال إلى التطبيق > الأصول، وانقر مرّتين على الملف default.jpg لفتحه.

9b333680e7b9f247.jpeg

وجِّه كاميرا الجهاز إلى صورة الأرض التي تظهر على الشاشة، واتّبع التعليمات لتلائم الصورة التي تمسحها ضوئيًا في الشعيرات المتقاطعة.

سيتم تركيب إطار صورة فوق الصورة، كما يلي:

999e05ed35964f6e.png

بعد ذلك، سنُجري تحسينات بسيطة على نموذج التطبيق.

3- عرض نموذج متاهة على الصورة الثنائية الأبعاد

يمكنك بدء تشغيل الصور المُعزّزة من خلال عرض تصميم ثلاثي الأبعاد فوقها.

تنزيل تصميم ثلاثي الأبعاد

في هذا الدرس التطبيقي حول الترميز، سنستخدم "Circle Maze - Green". بواسطة Evol، ومرخّصة بموجب CC-BY 3.0. لقد خزّنتُ نسخة من هذا التصميم الثلاثي الأبعاد في مستودع GitHub الخاص بهذا الدرس التطبيقي حول الترميز، ويمكنك العثور عليه هنا.

اتّبِع الخطوات التالية لتنزيل النموذج وتضمينه في "استوديو Android".

  1. انتقِل إلى مستودع GitHub الخاص بالدرس التطبيقي حول الترميز، وهو دليل خارجي.
  2. انقر على GreenMaze_obj.zip، وانقر على الزر GreenMaze_obj.zip.

يؤدي هذا الإجراء إلى تنزيل ملف باسم "GreenMaze_obj.zip".

  1. في "استوديو Android"، أنشِئ دليل green-maze ضمن التطبيق >. الأصول > النماذج
  2. فك ضغط GreenMaze_obj.zip وانسخ المحتوى إلى هذا المكان: arcore-android-sdk-x.xx.x/samples/augmented_image_java/app/src/main/assets/models/green-maze
  3. في "استوديو Android"، انتقل إلى التطبيق > الأصول > النماذج > المتاهة الخضراء

من المفترض أن يكون هناك ملفان في هذا المجلد: GreenMaze.obj وGreenMaze.mtl.

a1f33a2d2d407e03.png

عرض نموذج المتاهة

اتّبِع الخطوات التالية لعرض التصميم الثلاثي الأبعاد GreenMaze.obj أعلى الصورة الثنائية الأبعاد الحالية.

في AugmentedImageRenderer.java، أضِف متغيّرًا تابعًا للعنصر mazeRenderer لعرض نموذج المتاهة. وبما أنّه يجب إرفاق المتاهة بالصورة، من المنطقي وضع السمة mazeRenderer داخل الفئة AugmentedImageRenderer.

AugmentedImageRenderer.java

  // Add a member variable to hold the maze model.
  private final ObjectRenderer mazeRenderer = new ObjectRenderer();

في الدالة createOnGlThread()، حمِّل GreenMaze.obj. ولتبسيط الأمر، استخدِم زخرفة الإطار نفسها المستخدَمة في زخرفة الإطار.

AugmentedImageRenderer.java

  // Replace the definition of the createOnGlThread() function with the
  // following code, which loads GreenMaze.obj.
  public void createOnGlThread(Context context) throws IOException {

    mazeRenderer.createOnGlThread(
        context, "models/green-maze/GreenMaze.obj", "models/frame_base.png");
    mazeRenderer.setMaterialProperties(0.0f, 3.5f, 1.0f, 6.0f);

  }

استبدِل تعريف دالة draw() بما يلي. يعمل ذلك على ضبط حجم المتاهة ليتلاءم مع حجم الصورة التي تم اكتشافها، ويعرضها على الشاشة.

AugmentedImageRenderer.java

  // Adjust size of detected image and render it on-screen
  public void draw(
      float[] viewMatrix,
      float[] projectionMatrix,
      AugmentedImage augmentedImage,
      Anchor centerAnchor,
      float[] colorCorrectionRgba) {
    float[] tintColor =
        convertHexToColor(TINT_COLORS_HEX[augmentedImage.getIndex() % TINT_COLORS_HEX.length]);

    final float mazeEdgeSize = 492.65f; // Magic number of maze size
    final float maxImageEdgeSize = Math.max(augmentedImage.getExtentX(), augmentedImage.getExtentZ()); // Get largest detected image edge size

    Pose anchorPose = centerAnchor.getPose();

    float mazeScaleFactor = maxImageEdgeSize / mazeEdgeSize; // scale to set Maze to image size
    float[] modelMatrix = new float[16];

    // OpenGL Matrix operation is in the order: Scale, rotation and Translation
    // So the manual adjustment is after scale
    // The 251.3f and 129.0f is magic number from the maze obj file
    // You mustWe need to do this adjustment because the maze obj file
    // is not centered around origin. Normally when you
    // work with your own model, you don't have this problem.
    Pose mazeModelLocalOffset = Pose.makeTranslation(
                                -251.3f * mazeScaleFactor,
                                0.0f,
                                129.0f * mazeScaleFactor);
    anchorPose.compose(mazeModelLocalOffset).toMatrix(modelMatrix, 0);
    mazeRenderer.updateModelMatrix(modelMatrix, mazeScaleFactor, mazeScaleFactor/10.0f, mazeScaleFactor); // This line relies on a change in ObjectRenderer.updateModelMatrix later in this codelab.
    mazeRenderer.draw(viewMatrix, projectionMatrix, colorCorrectionRgba, tintColor);
  }

والآن، من المفترض أن تظهر المتاهة فوق صورة default.jpg للأرض.

ملاحظة: نظرًا لأنك لا تتمتع بسيطرة كاملة على نموذج التصميم الثلاثي الأبعاد هذا، يستخدم الرمز أعلاه بعض "الأدوات السحرية" الأرقام. أبعاد نموذج المتاهة هي 492.65 × 120 × 492.65، ويقع مركزها عند (251.3، 60، -129.0). نطاق رؤوسها قيم الإحداثيات X وY وZ هي [5.02 و497.67] و[0 و120] و[-375.17 و117.25] على التوالي. وبالتالي، يجب أن يكون مقياس نموذج المتاهة image_size / 492.65. تم تقديم mazeModelLocalOffset لأنّ التصميم الثلاثي الأبعاد للمتاهة لا يتمحور حول المصدر (0 و0 و0).

لا يزال جدار المتاهة مرتفعًا جدًا بحيث لا يناسب أعلى الصورة. قم بإنشاء دالة مساعدة updateModelMatrix() يمكنها تغيير حجم X وY وZ بشكل غير متساوي لقياس ارتفاع المتاهة بمقدار 0.1. ملاحظة: عليك الاحتفاظ بـ updateModelMatrix(float[] modelMatrix, float scaleFactor) الحالي وإضافة قيمة updateModelMatrix(float[] modelMatrix, float scaleFactorX, float scaleFactorY, float scaleFactorZ) الخاصة بالتحميل الزائد للدالة كدالة جديدة.

common/rendering/ObjectRenderer.java

// Scale X, Y, Z coordinates unevenly
public void updateModelMatrix(float[] modelMatrix, float scaleFactorX, float scaleFactorY, float scaleFactorZ) {
    float[] scaleMatrix = new float[16];
    Matrix.setIdentityM(scaleMatrix, 0);
    scaleMatrix[0] = scaleFactorX;
    scaleMatrix[5] = scaleFactorY;
    scaleMatrix[10] = scaleFactorZ;
    Matrix.multiplyMM(this.modelMatrix, 0, modelMatrix, 0, scaleMatrix, 0);
}

شغِّل الرمز. من المفترض أن تكون المتاهة الآن مناسبة تمامًا فوق الصورة.

772cbe2a8baef3ba.png

4. إضافة "آندي" إلى المتاهة

الآن بعد أن أصبح لديك متاهة، أضف شخصية للتنقل داخلها. استخدِم ملف andy.obj المضمّن في حزمة تطوير البرامج (SDK) لنظام التشغيل Android من ARCore. أبقِ زخرفة إطار الصورة كزخرفة لها، لأنّها تبدو مختلفة عن المتاهة الخضراء المعروضة أعلى الصورة.

في AugmentedImageRenderer.java، يمكنك إضافة ObjectRenderer خاص لعرض Andy.

AugmentedImageRenderer.java

// Render for Andy
  private final ObjectRenderer andyRenderer = new ObjectRenderer();

بعد ذلك، عليك إعداد andyRenderer في نهاية createOnGlThread().

AugmentedImageRenderer.java

public void createOnGlThread(Context context) throws IOException {

    // Initialize andyRenderer
    andyRenderer.createOnGlThread(
        context, "models/andy.obj", "models/andy.png");
    andyRenderer.setMaterialProperties(0.0f, 3.5f, 1.0f, 6.0f);
  }

أخيرًا، يمكنك عرض "آندي" وهو يقف أعلى المتاهة في نهاية دالة draw().

AugmentedImageRenderer.java

public void draw(
      float[] viewMatrix,
      float[] projectionMatrix,
      AugmentedImage augmentedImage,
      Anchor centerAnchor,
      float[] colorCorrectionRgba) {


    // Render Andy, standing on top of the maze
    Pose andyModelLocalOffset = Pose.makeTranslation(
        0.0f,
        0.1f,
        0.0f);
    anchorPose.compose(andyModelLocalOffset).toMatrix(modelMatrix, 0);
    andyRenderer.updateModelMatrix(modelMatrix, 0.05f); // 0.05f is a Magic number to scale
    andyRenderer.draw(viewMatrix, projectionMatrix, colorCorrectionRgba, tintColor);

  }

شغِّل التعليمة البرمجية. سترى آندي واقفًا فوق المتاهة.

cb1e74569d7ace69.png

تحديد جودة الصور المستهدَفة

يعتمد ARCore على الميزات المرئية للتعرّف على الصور. لا يمكن التعرّف على جميع الصور بسهولة بسبب الاختلافات في الجودة.

arcoreimg هي أداة سطر أوامر تتيح لك تحديد مدى إمكانية التعرّف على صورة في ARCore. تكون الناتج رقمًا بين 0 إلى 100، ويكون الرقم 100 أسهل في التعرّف عليه.

. وفي ما يلي مثال لذلك:

arcore-android-sdk-x.xx.x/tools/arcoreimg/macos$
$ ./arcoreimg  eval-img --input_image_path=/Users/username/maze.jpg
100

تبلغ قيمة maze.jpg 100، لذا يسهل التعرّف عليها من خلال ARCore.

5- اختياري: تحرك "آندي" في المتاهة

أخيرًا، يمكنك إضافة بعض التعليمات البرمجية لتحريك andy في المتاهة. على سبيل المثال، يمكنك استخدام محرك فيزياء مفتوح المصدر jBullet لمعالجة محاكاة الفيزياء. لا بأس في ذلك تمامًا إذا تخطيت هذا الجزء.

تنزيل PhysicsController.java وإضافته إلى مشروعك في الدليل

arcore-android-sdk-x.xx.x/samples/augmented_image_java/app/src/main/java/com/google/ar/core/examples/java/augmentedimage/

في "استوديو Android"، أضِف GreenMaze.obj إلى دليل أصول المشروع، حتى يمكن تحميله في وقت التشغيل. نسخ GreenMaze.obj من التطبيق > مواد العرض > طُرز > green-maze إلى تطبيق > مواد العرض:

أضِف الاعتماديات التالية إلى ملف build.gradle للتطبيق.

app/build.gradle

    // jbullet library
    implementation 'cz.advel.jbullet:jbullet:20101010-1'

حدد متغيرًا andyPose لتخزين وضعية آندي الحالية.

AugmentedImageRenderer.java

  // Create a new pose for the Andy
  private Pose andyPose = Pose.IDENTITY;

عدِّل AugmentedImageRenderer.java لعرض Andy باستخدام متغيّر andyPose الجديد.

AugmentedImageRenderer.java

public void draw(
      float[] viewMatrix,
      float[] projectionMatrix,
      AugmentedImage augmentedImage,
      Anchor centerAnchor,
      float[] colorCorrectionRgba) {

    // Use these code to replace previous code for rendering the Andy object
    // 
    // Adjust the Andy's rendering position
    // The Andy's pose is at the maze's vertex's coordinate
    Pose andyPoseInImageSpace = Pose.makeTranslation(
        andyPose.tx() * mazeScaleFactor,
        andyPose.ty() * mazeScaleFactor,
        andyPose.tz() * mazeScaleFactor);

    anchorPose.compose(andyPoseInImageSpace).toMatrix(modelMatrix, 0);
    andyRenderer.updateModelMatrix(modelMatrix, 0.05f);
    andyRenderer.draw(viewMatrix, projectionMatrix, colorCorrectionRgba, tintColor);
  }

أضف وظيفة مساعدة جديدة، updateAndyPose()، لتلقي تحديثات وضع آندي.

AugmentedImageRenderer.java

  // Receive Andy pose updates
  public void updateAndyPose(Pose pose) {
    andyPose = pose;
  }

في AugmentedImageActivity.java، يمكنك إنشاء عنصر PhysicsController يستخدم محرّك JBullet الفيزيائي لإدارة جميع الوظائف المتعلقة بالفيزياء.

AugmentedImageActivity.java

import com.google.ar.core.Pose;

  // Declare the PhysicsController object
  private PhysicsController physicsController;

وفي محرك الفيزياء، نستخدم كرة صلبة لتمثيل آندي وتعديل وضعية آندي باستخدام وضعية الكرة. يمكنك طلب الرقم PhysicsController لتعديل المعلومات الفيزيائية عندما يتعرّف التطبيق على صورة. لتحريك الكرة كما لو كانت في العالم الحقيقي، استخدم الجاذبية الواقعية لتحريك الكرة في المتاهة.

AugmentedImageActivity.java

// Update the case clause for TRACKING to call PhysicsController
// whenever the app recognizes an image
  private void drawAugmentedImages(

    ...

        case TRACKING:
          // Switch to UI Thread to update View
          this.runOnUiThread(
              new Runnable() {
                @Override
                public void run() {
                  fitToScanView.setVisibility(View.GONE);
                }
              });

          // Create a new anchor for newly found images
          if (!augmentedImageMap.containsKey(augmentedImage.getIndex())) {
            Anchor centerPoseAnchor = augmentedImage.createAnchor(augmentedImage.getCenterPose());
            augmentedImageMap.put(
                augmentedImage.getIndex(), Pair.create(augmentedImage, centerPoseAnchor));

            physicsController = new PhysicsController(this);
          } else {
            Pose ballPose = physicsController.getBallPose();
            augmentedImageRenderer.updateAndyPose(ballPose);


            // Use real world gravity, (0, -10, 0), as gravity
            // Convert to Physics world coordinate(maze mesh has to be static)
            // Use the converted coordinate as a force to move the ball
            Pose worldGravityPose = Pose.makeTranslation(0, -10f, 0);
            Pose mazeGravityPose = augmentedImage.getCenterPose().inverse().compose(worldGravityPose);
            float mazeGravity[] = mazeGravityPose.getTranslation();
            physicsController.applyGravityToBall(mazeGravity);

            physicsController.updatePhysics();
          }
          break;

شغِّل التطبيق. يجب أن يتحرك آندي الآن بشكل واقعي عند إمالة الصورة.

يستخدم المثال أدناه هاتفًا آخر لعرض الصورة، ويمكنك استخدام أي شيء يناسبك، مثل جهاز لوحي أو غلاف كتاب في نسخة ورقية، أو مجرد ورقة مطبوعة مرفقة بعنصر مسطح.

2f0df284705d3704.gif

هذا كل شيء! استمتع بمحاولة اصطحاب آندي في المتاهة. تلميح: من الأسهل العثور على المخرج عندما تحمل الصورة الهدف مقلوبة رأسًا على عقب.

6- تهانينا

تهانينا، لقد وصلت إلى نهاية هذا الدرس التطبيقي حول الترميز، وأصبح بإمكانك تحقيق ما يلي:

  • تم إنشاء واستخدام نموذج AugmentedImage Java من ARCore.
  • تم تحديث النموذج لعرض نموذج متاهة على الصورة، على المقياس المناسب.
  • تم استخدام وضعية الصورة لإضفاء بعض المرح.

إذا أردت الإشارة إلى الرمز الكامل، يمكنك تنزيله من هنا.

هل استمتعت في هذا الدرس التطبيقي حول الترميز؟

نعم لا

هل تعلمت أي شيء مفيد أثناء القيام بهذا الدرس التطبيقي حول الترميز؟

نعم لا

هل أكملت إنشاء التطبيق في هذا الدرس التطبيقي حول الترميز؟

نعم لا

هل تخطِّط لإنشاء تطبيق ARCore خلال الأشهر الستة المقبلة؟

نعم ربما لا