Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert 3D world (arcore anchor/pose) to its corresponding 2D screen coordinates

I'm struggling to get this transformation. Given an anchor Pose in arcore how can I obtain its corresponding 2D coordinates in the screen?

like image 562
rkachach Avatar asked Feb 28 '18 09:02

rkachach


2 Answers

Finally, after some days of investigation and getting the information from different resources I was able to get this working. Following is a code snippet (based on the arcore sample java app) to convert from World coordinates (Pose in arcore) to 2D screen coordinates:

First we need to calculate the matrix to transform from world --> screen:

  public float[] calculateWorld2CameraMatrix(float[] modelmtx, float[] viewmtx, float[] prjmtx) {

    float scaleFactor = 1.0f;
    float[] scaleMatrix = new float[16];
    float[] modelXscale = new float[16];
    float[] viewXmodelXscale = new float[16];
    float[] world2screenMatrix = new float[16];

    Matrix.setIdentityM(scaleMatrix, 0);
    scaleMatrix[0] = scaleFactor;
    scaleMatrix[5] = scaleFactor;
    scaleMatrix[10] = scaleFactor;

    Matrix.multiplyMM(modelXscale, 0, modelmtx, 0, scaleMatrix, 0);
    Matrix.multiplyMM(viewXmodelXscale, 0, viewmtx, 0, modelXscale, 0);
    Matrix.multiplyMM(world2screenMatrix, 0, prjmtx, 0, viewXmodelXscale, 0);

    return world2screenMatrix;

}

Once we have this matrix, then we can project points from 3D world to 2D, but during this projection we have to convert from NDC coordinates to screen. Following is the method that performs this conversion:

  double[] world2Screen(int screenWidth, int screenHeight, float[] world2cameraMatrix)
  {
    float[] origin = {0f, 0f, 0f, 1f};
    float[] ndcCoord = new float[4];
    Matrix.multiplyMV(ndcCoord, 0,  world2cameraMatrix, 0,  origin, 0);

    ndcCoord[0] = ndcCoord[0]/ndcCoord[3];
    ndcCoord[1] = ndcCoord[1]/ndcCoord[3];

    double[] pos_2d = new double[]{0,0};
    pos_2d[0] = screenWidth  * ((ndcCoord[0] + 1.0)/2.0);
    pos_2d[1] = screenHeight * (( 1.0 - ndcCoord[1])/2.0);

    return pos_2d;
  }

Finally, a simple example of usage:

        DisplayMetrics displayMetrics = new DisplayMetrics();
        getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        int height = displayMetrics.heightPixels;
        int width = displayMetrics.widthPixels;

        // Get projection matrix.
        float[] projmtx = new float[16];
        camera.getProjectionMatrix(projmtx, 0, 0.1f, 100.0f);

        // Get camera matrix and draw.
        float[] viewmtx = new float[16];
        camera.getViewMatrix(viewmtx, 0);

        float[] anchorMatrix = new float[16];
        anchor.getPose().toMatrix(anchorMatrix, 0);
        float[] world2screenMatrix =    
        virtualObject.calculateWorld2CameraMatrix(anchorMatrix, viewmtx, projmtx);
        double[] anchor_2d =  world2Screen(width, height, world2screenMatrix);
like image 97
rkachach Avatar answered Nov 17 '22 03:11

rkachach


arSceneView.getScene().getCamera().worldToScreenPoint(); worked for me as described here.

like image 44
Elnatan Derech Avatar answered Nov 17 '22 03:11

Elnatan Derech