Estabilización de imágenes de la cámara en el NDK de Android (C)

ARCore ahora admite la estabilización electrónica de imagen (EIS), que ayuda a producir una vista previa de la cámara fluida. La EIS logra estabilización mediante la observación del movimiento del teléfono con el giroscopio y la aplicación de una malla de homografía de compensación dentro de los límites de la textura de la cámara que contrarresta las agitaciones menores. EIS solo se admite en la orientación vertical del dispositivo. Todas las orientaciones serán compatibles con la versión 1.39.0 de ARCore.

Cómo consultar la compatibilidad con EIS y habilitarlo

Si quieres habilitar EIS, configura tu sesión para que use AR_IMAGE_STABILIZATION_MODE_EIS. Si el dispositivo no admite la función EIS, se generará una excepción de 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);

Cómo transformar coordenadas

Cuando EIS está activado, el renderizador debe usar las coordenadas modificadas del dispositivo y las coordenadas de textura coincidentes que incorporan la compensación EIS cuando renderiza el fondo de la cámara. Para obtener las coordenadas compensadas de EIS, usa ArFrame_transformCoordinates3d, con AR_COORDINATES_2D_OPENGL_NORMALIZED_DEVICE_COORDINATES como entrada y AR_COORDINATES_3D_EIS_NORMALIZED_DEVICE_COORDINATES como salida para obtener coordenadas 3D del dispositivo y AR_COORDINATES_3D_EIS_TEXTURE_NORMALIZED como resultado para obtener coordenadas de texturas 3D. Por ahora, el único tipo de coordenada de entrada que se admite para ArFrame_transformCoordinates3d es 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_);

Cuando EIS está desactivado, las coordenadas 3D resultantes son equivalentes a sus equivalentes en 2D, con valores z configurados para no producir cambios.

Cómo modificar sombreadores

Las coordenadas 3D calculadas deben pasarse a sombreadores de renderización en segundo plano. Los búferes de Vertex ahora están en 3D con 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;
}

Además, el sombreador de fragmentos debe aplicar la corrección de perspectiva:

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

Consulta la app de ejemplo hello_eis_kotlin para obtener más detalles.