Stabiliser les images de l'appareil photo sur le NDK Android (C)

ARCore est désormais compatible avec la stabilisation électronique de l'image (EIS), qui permet d'obtenir un aperçu fluide de l'appareil photo. L'EIS atteint la stabilisation en observant le mouvement du téléphone à l'aide d'un gyroscope et en appliquant un maillage d'homographie de compensation dans les limites de la texture de l'appareil photo, ce qui permet de compenser les petits tremblements. L'EIS n'est compatible qu'avec l'orientation portrait de l'appareil. Toutes les orientations seront compatibles avec la version 1.39.0 d'ARCore.

Demander la compatibilité avec l'EIS et l'activer

Pour activer EIS, configurez votre session afin d'utiliser AR_IMAGE_STABILIZATION_MODE_EIS. Si l'appareil n'est pas compatible avec la fonctionnalité EIS, une exception sera générée par ARCore.

int enableEis = 0;
ArSession_isImageStabilizationModeSupported(
    ar_session, AR_IMAGE_STABILIZATION_MODE_EIS, &enableEis);
if (!enableEis) {
  return;
}
// Create a session config.
ArConfig* ar_config = NULL;
ArConfig_create(ar_session, &ar_config);

// Enable Electronic Image Stabilization.
ArConfig_setImageStabilizationMode(ar_session, ar_config, AR_IMAGE_STABILIZATION_MODE_EIS);
CHECK(ArSession_configure(ar_session, ar_config) == AR_SUCCESS);

// Release config resources.
ArConfig_destroy(ar_config);

Transformer des coordonnées

Lorsqu'EIS est activé, le moteur de rendu doit utiliser les coordonnées modifiées de l'appareil et les coordonnées de texture correspondantes qui intègrent la compensation EIS lors du rendu de l'arrière-plan de l'appareil photo. Pour obtenir les coordonnées compensées par l'EIS, utilisez ArFrame_transformCoordinates3d, en utilisant AR_COORDINATES_2D_OPENGL_NORMALIZED_DEVICE_COORDINATES comme entrée et AR_COORDINATES_3D_EIS_NORMALIZED_DEVICE_COORDINATES comme sortie pour obtenir les coordonnées 3D de l'appareil et AR_COORDINATES_3D_EIS_TEXTURE_NORMALIZED en sortie pour obtenir les coordonnées de texture 3D. Pour l'instant, le seul type de coordonnées d'entrée accepté pour ArFrame_transformCoordinates3d est AR_COORDINATES_2D_OPENGL_NORMALIZED_DEVICE_COORDINATES.

int kNumVertices = 4;
// Positions of the quad vertices in clip space (X, Y).
const GLfloat kVertices[] = {
    -1.0f, -1.0f, +1.0f, -1.0f, -1.0f, +1.0f, +1.0f, +1.0f,
};
float transformed_vertices_[4 * 3];
float transformed_uvs_[4 * 3];

ArFrame_transformCoordinates3d(
    session, frame, AR_COORDINATES_2D_OPENGL_NORMALIZED_DEVICE_COORDINATES,
    kNumVertices, kVertices,
    AR_COORDINATES_3D_EIS_NORMALIZED_DEVICE_COORDINATES,
    transformed_vertices_);
ArFrame_transformCoordinates3d(
    session, frame, AR_COORDINATES_2D_OPENGL_NORMALIZED_DEVICE_COORDINATES,
    kNumVertices, kVertices, AR_COORDINATES_3D_EIS_TEXTURE_NORMALIZED,
    transformed_uvs_);

glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_EXTERNAL_OES, camera_texture_id_);
glUseProgram(camera_program_);
glUniform1i(camera_texture_uniform_, 0);

// Set the vertex positions and texture coordinates.
glVertexAttribPointer(camera_position_attrib_, 3, GL_FLOAT, false, 0,
                      transformed_vertices_);
glVertexAttribPointer(camera_tex_coord_attrib_, 3, GL_FLOAT, false, 0,
                      transformed_uvs_);
glEnableVertexAttribArray(camera_position_attrib_);
glEnableVertexAttribArray(camera_tex_coord_attrib_);

Lorsque la fonctionnalité EIS est désactivée, les coordonnées 3D de sortie sont équivalentes à leurs équivalents 2D, et les valeurs z sont définies pour ne produire aucun changement.

Modifier les nuanceurs

Les coordonnées 3D calculées doivent être transmises aux nuanceurs de rendu en arrière-plan. Les tampons de sommets sont désormais en 3D avec EIS:

layout(location = 0) in vec4 a_Position;
layout(location = 1) in vec3 a_CameraTexCoord;
out vec3 v_CameraTexCoord;
void main() {
  gl_Position = a_Position;
  v_CameraTexCoord = a_CameraTexCoord;
}

De plus, le nuanceur de fragments doit appliquer une correction de perspective:

precision mediump float;
uniform samplerExternalOES u_CameraColorTexture;
in vec3 v_CameraTexCoord;
layout(location = 0) out vec4 o_FragColor;
void main() {
  vec3 tc = (v_CameraTexCoord / v_CameraTexCoord.z);
  o_FragColor = texture(u_CameraColorTexture, tc.xy);
}

Pour en savoir plus, consultez l'application exemple hello_eis_kotlin.