Hình ảnh tăng cường ARCore

1. Tổng quan

ARCore là một nền tảng để tạo các ứng dụng thực tế tăng cường trên Android. Hình ảnh tăng cường cho phép bạn tạo các ứng dụng AR có thể nhận dạng hình ảnh 2D đã đăng ký trước trong thế giới thực và neo nội dung ảo lên trên các hình ảnh đó.

Lớp học lập trình này hướng dẫn bạn cách sửa đổi một ứng dụng mẫu ARCore hiện có để kết hợp Hình ảnh tăng cường di chuyển hoặc cố định tại chỗ.

Sản phẩm bạn sẽ tạo ra

Trong lớp học lập trình này, bạn sẽ xây dựng dựa trên một ứng dụng mẫu ARCore có sẵn. Khi kết thúc lớp học lập trình này, ứng dụng của bạn sẽ có thể:

  • Phát hiện một mục tiêu hình ảnh và đính kèm một mê cung ảo vào mục tiêu đó
  • Theo dõi mục tiêu di chuyển miễn là mục tiêu đó nằm trong tầm nhìn của camera

6bc6605df89de525.gif

Đây có phải là lần đầu tiên bạn tạo ứng dụng ARCore không?

Không

Bạn có dự định viết mã mẫu trong lớp học lập trình này hay chỉ muốn đọc các trang này?

Viết mã mẫu Chỉ cần đọc các trang này

Kiến thức bạn sẽ học được

  • Cách sử dụng Hình ảnh tăng cường trong ARCore bằng Java
  • Cách đánh giá khả năng nhận dạng hình ảnh của ARCore
  • Cách đính kèm nội dung ảo vào hình ảnh và theo dõi chuyển động của nội dung đó

Điều kiện tiên quyết

Bạn sẽ cần phần cứng và phần mềm cụ thể để hoàn tất lớp học lập trình này.

Yêu cầu về phần cứng

Yêu cầu về phần mềm

  • ARCore APK 1.9.0 trở lên. APK này thường được tự động cài đặt trên thiết bị thông qua Cửa hàng Play
  • Một máy phát triển đã cài đặt Android Studio (phiên bản 3.1 trở lên)
  • Có quyền truy cập vào Internet vì bạn sẽ cần tải các thư viện xuống trong quá trình phát triển

Giờ thì bạn đã sẵn sàng, hãy bắt đầu thôi!

2. Thiết lập môi trường phát triển

Tải SDK xuống

Chúng ta sẽ bắt đầu bằng cách tải SDK Android ARCore mới nhất xuống từ GitHub. Giải nén tệp đó vào vị trí bạn muốn. Đối với lớp học lập trình này, phiên bản SDK sớm nhất là 1.18.1. Thư mục này sẽ được gọi là arcore-android-sdk-x.xx.x, giá trị chính xác sẽ là phiên bản SDK mà bạn sử dụng.

Khởi chạy Android Studio rồi nhấp vào Open an existing Android Studio project (Mở một dự án hiện có trong Android Studio).

5fbf2b21609187cc.png

Chuyển đến thư mục đã giải nén này:

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

Nhấp vào Mở.

Chờ Android Studio hoàn tất quá trình đồng bộ hoá dự án. Nếu Android Studio của bạn không có các thành phần cần thiết, thì có thể sẽ gặp lỗi và hiển thị thông báo Install missing platform and sync project. Làm theo hướng dẫn để khắc phục vấn đề.

Chạy ứng dụng mẫu

Giờ đây, bạn đã có một dự án ứng dụng ARCore đang hoạt động, hãy chạy thử dự án đó.

Kết nối thiết bị ARCore với máy phát triển và sử dụng trình đơn Run > Run ‘app' (Chạy > Chạy "ứng dụng") để chạy phiên bản gỡ lỗi trên thiết bị. Trong hộp thoại nhắc bạn chọn thiết bị để chạy, hãy chọn thiết bị thông minh đã kết nối rồi nhấp vào OK.

1aa2c6faa7ecdbd0.png

92e4c144a632b4ca.png

Dự án mẫu này sử dụng targetSdkVersion 28. Nếu bạn gặp lỗi bản dựng như Failed to find Build Tools revision 28.0.3, hãy làm theo hướng dẫn trong Android Studio để tải xuống và cài đặt phiên bản Android Build Tools cần thiết.

Nếu mọi thứ đều thành công, ứng dụng mẫu sẽ khởi chạy trên thiết bị và nhắc bạn cấp quyền cho Hình ảnh tăng cường để chụp ảnh và quay video. Nhấn vào CHO PHÉP để cấp quyền.

Thử nghiệm bằng hình ảnh mẫu

Giờ đây, sau khi thiết lập môi trường phát triển, bạn có thể kiểm thử ứng dụng bằng cách cung cấp cho ứng dụng một hình ảnh để xem.

Trong Android Studio, trong cửa sổ Project (Dự án), hãy chuyển đến app > assets (ứng dụng > tài sản) rồi nhấp đúp vào tệp default.jpg để mở tệp đó.

9b333680e7b9f247.jpeg

Hướng camera của thiết bị vào hình ảnh Trái Đất trên màn hình, rồi làm theo hướng dẫn để đưa hình ảnh bạn đang quét vào tâm của dấu thập.

Khung hình sẽ phủ lên trên hình ảnh, như thế này:

999e05ed35964f6e.png

Tiếp theo, chúng ta sẽ cải thiện một chút cho ứng dụng mẫu.

3. Hiển thị mô hình mê cung trên Hình ảnh 2D

Bạn có thể bắt đầu chơi với Hình ảnh tăng cường bằng cách hiển thị một mô hình 3D ở trên cùng.

Tải mô hình 3D xuống

Trong lớp học lập trình này, chúng ta sẽ sử dụng "Circle Maze – Green" của Evol và được cấp phép theo CC-BY 3.0. Tôi đã lưu trữ một bản sao của mô hình 3D này trong kho lưu trữ github của lớp học lập trình này. Bạn có thể tìm thấy bản sao đó tại đây.

Hãy làm theo các bước sau để tải mô hình xuống và đưa mô hình đó vào Android Studio.

  1. Chuyển đến kho lưu trữ GitHub của lớp học lập trình này, thư mục third_party.
  2. Nhấp vào GreenMaze_obj.zip rồi nhấp vào nút Tải xuống.

Thao tác này sẽ tải một tệp có tên là GreenMaze_obj.zip xuống.

  1. Trong Android Studio, hãy tạo thư mục green-maze trong app > assets > models
  2. Giải nén GreenMaze_obj.zip và sao chép nội dung vào vị trí này: arcore-android-sdk-x.xx.x/samples/augmented_image_java/app/src/main/assets/models/green-maze
  3. Trong Android Studio, hãy chuyển đến app > assets > models > green-maze.

Thư mục này phải có hai tệp: GreenMaze.objGreenMaze.mtl.

a1f33a2d2d407e03.png

Kết xuất mô hình mê cung

Hãy làm theo các bước sau để hiển thị mô hình 3D GreenMaze.obj ở trên cùng của hình ảnh 2D hiện có.

Trong AugmentedImageRenderer.java, hãy thêm một biến thành phần có tên là mazeRenderer để kết xuất mô hình mê cung. Vì mê cung sẽ gắn vào hình ảnh, nên việc đặt mazeRenderer bên trong lớp AugmentedImageRenderer là hợp lý.

AugmentedImageRenderer.java

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

Trong hàm createOnGlThread(), hãy tải GreenMaze.obj. Để đơn giản, hãy sử dụng cùng một hoạ tiết khung hình làm hoạ tiết.

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);

  }

Thay thế định nghĩa của hàm draw() bằng nội dung sau. Thao tác này điều chỉnh kích thước của mê cung theo kích thước của hình ảnh được phát hiện và hiển thị hình ảnh đó trên màn hình.

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);
  }

Giờ đây, mê cung sẽ xuất hiện trên bức ảnh default.jpg về Trái Đất.

Lưu ý: Vì bạn không có toàn quyền kiểm soát mô hình 3D mẫu này, nên mã ở trên sử dụng một số con số "kỳ diệu". Kích thước của mô hình mê cung là 492,65 x 120 x 492,65, với tâm ở vị trí (251,3, 60, -129,0). Phạm vi giá trị toạ độ X, Y và Z của các đỉnh tương ứng là [5,02, 497,67], [0, 120] và [-375,17, 117,25]. Do đó, tỷ lệ của mô hình mê cung cần là image_size / 492.65. mazeModelLocalOffset xuất hiện vì mô hình 3D của mê cung không được đặt ở tâm (0, 0, 0).

Tường của mê cung vẫn hơi cao so với bức tranh. Tạo một hàm trợ giúp updateModelMatrix() có thể điều chỉnh tỷ lệ X, Y, Z không đồng đều để điều chỉnh tỷ lệ chiều cao của Mê cung theo hệ số 0,1. Xin lưu ý rằng bạn phải giữ lại updateModelMatrix(float[] modelMatrix, float scaleFactor) hiện có và thêm phương thức nạp chồng hàm updateModelMatrix(float[] modelMatrix, float scaleFactorX, float scaleFactorY, float scaleFactorZ) làm một hàm mới.

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);
}

Chạy mã. Giờ đây, mê cung sẽ vừa khít phía trên hình ảnh.

772cbe2a8baef3ba.png

4. Thêm Andy vào mê cung

Bây giờ bạn đã có một mê cung, hãy thêm một nhân vật để di chuyển bên trong mê cung đó. Sử dụng tệp andy.obj có trong SDK Android ARCore. Giữ nguyên hoạ tiết khung hình ảnh vì hoạ tiết này khác với mê cung màu xanh lục được hiển thị trên hình ảnh.

Trong AugmentedImageRenderer.java, hãy thêm ObjectRenderer riêng tư để kết xuất Andy.

AugmentedImageRenderer.java

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

Tiếp theo, hãy khởi chạy andyRenderer ở cuối 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);
  }

Cuối cùng, hãy kết xuất Andy đứng trên đỉnh mê cung ở cuối hàm 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);

  }

Chạy mã. Bạn sẽ thấy Andy đứng trên đỉnh mê cung.

cb1e74569d7ace69.png

Xác định chất lượng hình ảnh mục tiêu

ARCore dựa vào các đặc điểm trực quan để nhận dạng hình ảnh. Do chất lượng khác nhau, nên không phải hình ảnh nào cũng có thể nhận dạng dễ dàng.

arcoreimg là một công cụ dòng lệnh cho phép bạn xác định mức độ nhận dạng của một hình ảnh đối với ARCore. Chỉ số này cho ra một số từ 0 đến 100, trong đó 100 là giá trị dễ nhận dạng nhất.

. Sau đây là một ví dụ:

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

maze.jpg có giá trị là 100, nên ARCore dễ dàng nhận ra.

5. Không bắt buộc: Di chuyển Andy trong mê cung

Cuối cùng, bạn có thể thêm một số mã để làm cho andy di chuyển trong mê cung. Ví dụ: sử dụng công cụ Vật lý nguồn mở jBullet để xử lý quy trình mô phỏng vật lý. Bạn hoàn toàn có thể bỏ qua phần này.

Tải PhysicsController.java xuống rồi thêm tệp này vào dự án của bạn trong thư mục

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

Trong Android Studio, hãy thêm GreenMaze.obj vào thư mục tài sản dự án để có thể tải tệp này trong thời gian chạy. Sao chép GreenMaze.obj từ app > assets > models > green-maze sang app > assets.

Thêm các phần phụ thuộc sau vào tệp build.gradle của ứng dụng.

app/build.gradle

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

Xác định một biến andyPose để lưu trữ vị trí của tư thế hiện tại của Andy.

AugmentedImageRenderer.java

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

Sửa đổi AugmentedImageRenderer.java để kết xuất Andy bằng biến andyPose mới.

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);
  }

Thêm một hàm hiệu dụng mới, updateAndyPose(), để nhận thông tin cập nhật về tư thế của Andy.

AugmentedImageRenderer.java

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

Trong AugmentedImageActivity.java, hãy tạo một đối tượng PhysicsController sử dụng công cụ vật lý JBullet để quản lý tất cả các chức năng liên quan đến vật lý.

AugmentedImageActivity.java

import com.google.ar.core.Pose;

  // Declare the PhysicsController object
  private PhysicsController physicsController;

Trong công cụ Vật lý, chúng ta thực sự sử dụng một quả bóng cứng để biểu thị Andy và cập nhật tư thế của Andy bằng tư thế của quả bóng. Gọi PhysicsController để cập nhật vật lý bất cứ khi nào ứng dụng nhận dạng một hình ảnh. Để di chuyển quả bóng như trong thế giới thực, hãy áp dụng trọng lực của thế giới thực để di chuyển quả bóng trong mê cung.

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;

Chạy ứng dụng. Giờ đây, Andy sẽ di chuyển một cách chân thực khi bạn nghiêng hình ảnh.

Ví dụ dưới đây sử dụng một chiếc điện thoại khác để hiển thị hình ảnh. Bạn có thể thoải mái sử dụng bất cứ thứ gì thuận tiện cho mình, chẳng hạn như máy tính bảng, bìa sách in hoặc chỉ cần một tờ giấy in được gắn trên một vật thể phẳng.

2f0df284705d3704.gif

Vậy là xong! Hãy thử đưa Andy vượt qua mê cung. Lưu ý: Bạn sẽ dễ dàng tìm thấy lối thoát hơn khi lật ngược hình ảnh mục tiêu.

6. Xin chúc mừng

Xin chúc mừng, bạn đã hoàn thành lớp học lập trình này và đã:

  • Tạo và chạy mẫu AugmentedImage Java của ARCore.
  • Cập nhật mẫu để hiển thị một mô hình mê cung trên hình ảnh, ở tỷ lệ thích hợp.
  • Sử dụng tư thế của hình ảnh để làm điều gì đó thú vị.

Nếu muốn tham khảo mã hoàn chỉnh, bạn có thể tải mã này xuống tại đây.

Bạn có thấy thú vị khi thực hiện lớp học lập trình này không?

Không

Bạn có học được điều gì hữu ích khi thực hiện lớp học lập trình này không?

Không

Bạn đã hoàn tất việc tạo ứng dụng trong lớp học lập trình này chưa?

Không

Bạn có dự định tạo một ứng dụng ARCore trong 6 tháng tới không?

Có thể Không