تصاویر افزوده شده ARCore

۱. مرور کلی

ARCore پلتفرمی برای ساخت برنامه‌های واقعیت افزوده در اندروید است. تصاویر افزوده به شما این امکان را می‌دهد که برنامه‌های واقعیت افزوده‌ای بسازید که می‌توانند تصاویر دوبعدی از پیش ثبت‌شده در دنیای واقعی را تشخیص داده و محتوای مجازی را روی آنها قرار دهند.

این آزمایشگاه کد شما را در اصلاح یک برنامه نمونه ARCore موجود برای گنجاندن تصاویر افزوده‌ای که در حال حرکت یا ثابت در محل هستند، راهنمایی می‌کند.

آنچه خواهید ساخت

در این آزمایشگاه کد، شما بر اساس یک برنامه نمونه ARCore که از قبل موجود است، برنامه خود را خواهید ساخت. در پایان این آزمایشگاه کد، برنامه شما قادر خواهد بود:

  • تشخیص یک هدف تصویری و اتصال یک هزارتوی مجازی به هدف
  • هدف متحرک را تا زمانی که در دید دوربین است، ردیابی کنید

6bc6605df89de525.gif

آیا این اولین باری است که یک برنامه ARCore می‌سازید؟

بله خیر

آیا قصد دارید در این آزمایشگاه کد، کد نمونه بنویسید یا فقط می‌خواهید این صفحات را بخوانید؟

کد نمونه بنویسید فقط این صفحات را بخوانید

آنچه یاد خواهید گرفت

  • نحوه استفاده از تصاویر افزوده در ARCore در جاوا
  • چگونه می‌توان توانایی تشخیص یک تصویر توسط ARCore را سنجید؟
  • نحوه اتصال یک محتوای مجازی به یک تصویر و ردیابی حرکت آن

پیش‌نیازها

برای تکمیل این آزمایشگاه کد، به سخت‌افزار و نرم‌افزار خاصی نیاز دارید.

الزامات سخت‌افزاری

نیازمندی‌های نرم‌افزاری

  • ARCore APK 1.9.0 یا بالاتر. این APK معمولاً به طور خودکار از طریق فروشگاه Play روی دستگاه نصب می‌شود.
  • یک دستگاه توسعه با اندروید استودیو (نسخه ۳.۱ یا بالاتر)
  • دسترسی به اینترنت، زیرا در طول توسعه نیاز به دانلود کتابخانه‌ها خواهید داشت.

حالا که همه چیز را آماده کرده‌اید، بیایید شروع کنیم!

۲. محیط توسعه را راه‌اندازی کنید

دانلود SDK

ما با دانلود آخرین نسخه ARCore Android SDK از GitHub شروع می‌کنیم. آن را در محل دلخواه خود از حالت فشرده خارج کنید. برای این codelab، قدیمی‌ترین نسخه SDK، نسخه ۱.۱۸.۱ است. نام پوشه arcore-android-sdk-x.xx.x خواهد بود، مقدار دقیق آن، نسخه SDK مورد استفاده شما خواهد بود.

اندروید استودیو را اجرا کنید و روی «باز کردن یک پروژه اندروید استودیو موجود» کلیک کنید.

5fbf2b21609187cc.png

به این پوشه‌ی از حالت فشرده خارج شده بروید:

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

روی باز کردن کلیک کنید.

صبر کنید تا اندروید استودیو همگام‌سازی پروژه را تمام کند. اگر اندروید استودیو شما اجزای مورد نیاز را نداشته باشد، ممکن است با پیام Install missing platform and sync project مواجه شود. برای رفع مشکل، دستورالعمل‌ها را دنبال کنید.

اجرای برنامه نمونه

حالا که یک پروژه اپلیکیشن ARCore دارید که کار می‌کند، بیایید آن را امتحان کنیم.

دستگاه ARCore خود را به دستگاه توسعه متصل کنید و از منوی Run > Run 'app' برای اجرای نسخه اشکال‌زدایی روی دستگاه استفاده کنید. در پنجره‌ای که از شما خواسته می‌شود دستگاه مورد نظر برای اجرا را انتخاب کنید، دستگاه متصل را انتخاب کرده و روی OK کلیک کنید.

۱aa2c6faa7ecdbd0.png

92e4c144a632b4ca.png

این پروژه نمونه از targetSdkVersion 28 استفاده می‌کند. اگر با خطای ساخت مانند Failed to find Build Tools revision 28.0.3 مواجه شدید، دستورالعمل‌های شرح داده شده در Android Studio را برای دانلود و نصب نسخه مورد نیاز Android Build Tools دنبال کنید.

اگر همه چیز موفقیت‌آمیز باشد، برنامه نمونه روی دستگاه اجرا می‌شود و از شما اجازه می‌گیرد تا به Augmented Image اجازه عکس‌برداری و فیلم‌برداری بدهید. برای اعطای مجوز، روی ALLOW ضربه بزنید.

با یک تصویر نمونه تست کنید

اکنون که محیط توسعه خود را تنظیم کرده‌اید، می‌توانید با ارائه یک تصویر برای بررسی، برنامه را آزمایش کنید.

به اندروید استودیو برگردید، در پنجره پروژه ، به app > assets بروید و روی فایل default.jpg دوبار کلیک کنید تا باز شود.

9b333680e7b9f247.jpeg

دوربین دستگاه خود را به سمت تصویر زمین روی صفحه بگیرید و دستورالعمل‌ها را دنبال کنید تا تصویری که اسکن می‌کنید در کادر ضربدر قرار گیرد.

یک قاب تصویر روی تصویر قرار می‌گیرد، مانند این:

999e05ed35964f6e.png

در مرحله بعد، بهبودهای کوچکی در برنامه نمونه ایجاد خواهیم کرد.

۳. نمایش مدل هزارتو روی تصویر دوبعدی

شما می‌توانید با نمایش یک مدل سه‌بعدی روی تصاویر افزوده، بازی با آن‌ها را شروع کنید.

یک مدل سه بعدی دانلود کنید

برای این آزمایشگاه کد، ما از « Circle Maze - Green » ساخته‌ی Evol و دارای مجوز CC-BY 3.0 استفاده خواهیم کرد. من یک کپی از این مدل سه‌بعدی را در مخزن گیت‌هاب این آزمایشگاه کد ذخیره کرده‌ام که می‌توانید آن را اینجا پیدا کنید.

برای دانلود مدل و اضافه کردن آن به اندروید استودیو، این مراحل را دنبال کنید.

  1. به مخزن گیت‌هاب این codelab، دایرکتوری third_party، بروید.
  2. روی GreenMaze_obj.zip کلیک کنید و دکمه دانلود را بزنید.

این دستور فایلی به نام GreenMaze_obj.zip را دانلود می‌کند.

  1. در اندروید استودیو، دایرکتوری green-maze را در مسیر app > assets > models ایجاد کنید.
  2. فایل GreenMaze_obj.zip را از حالت فشرده خارج کرده و محتویات آن را در این مسیر کپی کنید: arcore-android-sdk-x.xx.x/samples/augmented_image_java/app/src/main/assets/models/green-maze
  3. در اندروید استودیو، به مسیر app > assets > models > green-maze بروید.

باید دو فایل در این پوشه وجود داشته باشد: GreenMaze.obj و GreenMaze.mtl .

a1f33a2d2d407e03.png

مدل هزارتو را رندر کنید

برای نمایش مدل سه‌بعدی GreenMaze.obj روی تصویر دوبعدی موجود، این مراحل را دنبال کنید.

در AugmentedImageRenderer.java ، یک متغیر عضو به نام mazeRenderer برای رندر مدل هزارتو اضافه کنید. از آنجا که هزارتو باید به تصویر متصل شود، منطقی است که mazeRenderer درون کلاس AugmentedImageRenderer قرار دهیم.

رندرکننده تصویر افزوده‌شده.java

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

در تابع createOnGlThread() ، فایل GreenMaze.obj را بارگذاری کنید. برای سادگی، از همان بافت فریم به عنوان بافت آن استفاده کنید.

رندرکننده تصویر افزوده‌شده.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() را با کد زیر جایگزین کنید. این کد، اندازه هزارتو را با اندازه تصویر شناسایی شده تنظیم می‌کند و آن را روی صفحه نمایش می‌دهد.

رندرکننده تصویر افزوده‌شده.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 x 120 x 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 را به طور ناهموار مقیاس‌بندی کند تا ارتفاع هزارتو را به اندازه ۰.۱ افزایش دهد. توجه داشته باشید که باید تابع updateModelMatrix(float[] modelMatrix, float scaleFactor) موجود را نگه دارید و تابع overload شده 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

۴. اندی را به هزارتو اضافه کنید

حالا که یک هزارتو دارید، یک شخصیت اضافه کنید تا درون آن حرکت کند. از فایل andy.obj موجود در ARCore Android SDK استفاده کنید. بافت قاب تصویر را به عنوان بافت آن نگه دارید، زیرا با هزارتوی سبز رندر شده روی تصویر متفاوت به نظر می‌رسد.

در AugmentedImageRenderer.java ، یک ObjectRenderer خصوصی برای رندر کردن Andy اضافه کنید.

رندرکننده تصویر افزوده‌شده.java

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

در مرحله بعد، andyRenderer در انتهای createOnGlThread() مقداردهی اولیه کنید.

رندرکننده تصویر افزوده‌شده.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() در حالی که بالای هزارتو ایستاده است، رندر کنید.

رندرکننده تصویر افزوده‌شده.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 را تعیین کنید. این ابزار عددی بین ۰ تا ۱۰۰ را نمایش می‌دهد که ۱۰۰ ساده‌ترین عدد برای تشخیص است.

. در اینجا یک مثال آورده شده است:

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

maze.jpg مقدار ۱۰۰ دارد، بنابراین به راحتی توسط ARCore شناسایی می‌شود.

۵. اختیاری: کاری کنید که اندی در هزارتو حرکت کند

در نهایت، می‌توانید کدی اضافه کنید تا اندی در هزارتو حرکت کند. برای مثال، از موتور فیزیک متن‌باز jBullet برای مدیریت شبیه‌سازی فیزیک استفاده کنید. اگر از این بخش صرف‌نظر کنید، کاملاً مشکلی نیست.

PhysicsController.java را دانلود کنید و آن را به پروژه خود در دایرکتوری اضافه کنید.

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

در اندروید استودیو، فایل GreenMaze.obj را به دایرکتوری assets پروژه اضافه کنید تا در زمان اجرا قابل بارگذاری باشد. فایل GreenMaze.obj از مسیر app > assets > models > green-maze در مسیر app > assets کپی کنید.

وابستگی‌های زیر را به فایل build.gradle برنامه اضافه کنید.

برنامه/ساخت.gradle

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

متغیری به andyPose تعریف کنید تا موقعیت فعلی اندی را ذخیره کند.

رندرکننده تصویر افزوده‌شده.java

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

فایل AugmentedImageRenderer.java را طوری تغییر دهید که Andy را با استفاده از متغیر جدید andyPose رندر کند.

رندرکننده تصویر افزوده‌شده.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() اضافه کنید تا به‌روزرسانی‌های ژست Andy را دریافت کند.

رندرکننده تصویر افزوده‌شده.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

همین! از تلاش برای عبور دادن اندی از هزارتو لذت ببرید. راهنمایی: وقتی تصویر هدف را وارونه نگه دارید، پیدا کردن خروجی آسان‌تر است.

۶. تبریک

تبریک می‌گویم، شما به پایان این آزمایشگاه کد رسیده‌اید و بنابراین:

  • یک نمونه جاوا از ARCore AugmentedImage ساخته و اجرا شد.
  • نمونه به‌روزرسانی شد تا مدل هزارتو روی تصویر، در مقیاس مناسب، نمایش داده شود.
  • از ژست تصویر برای انجام کاری جالب استفاده کردم.

اگر مایل به مشاهده کد کامل هستید، می‌توانید آن را از اینجا دانلود کنید.

آیا از انجام این کدنویسی لذت بردی؟

بله خیر

آیا در انجام این کدلاگ چیز مفیدی یاد گرفتید؟

بله خیر

آیا ساخت برنامه را در این آزمایشگاه کد کامل کردید؟

بله خیر

آیا قصد دارید در ۶ ماه آینده یک اپلیکیشن ARCore بسازید؟

بله شاید خیر