Android NDK (C)에서 카메라 이미지 손떨림 보정

이제 ARCore에서 EIS (전자식 이미지 손떨림 보정)를 지원하므로 매끄러운 카메라 미리보기를 만들 수 있습니다. EIS는 자이로를 사용하여 스마트폰의 움직임을 관찰하고 카메라 텍스처의 경계 내에 보정 호모그래피 메시를 적용하여 미세한 흔들림에 대응하여 안정화를 실현합니다. EIS는 기기의 세로 방향에서만 지원됩니다. ARCore 1.39.0 버전에서 모든 방향이 지원됩니다.

EIS 지원 쿼리 및 EIS 사용 설정

EIS를 사용 설정하려면 AR_IMAGE_STABILIZATION_MODE_EIS를 사용하도록 세션을 구성합니다. 기기가 EIS 기능을 지원하지 않으면 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);

좌표 변환

EIS가 사용 설정된 경우 렌더기는 카메라 배경을 렌더링할 때 EIS 보상을 통합하는 수정된 기기 좌표와 일치하는 텍스처 좌표를 사용해야 합니다. EIS 보상 좌표를 가져오려면 ArFrame_transformCoordinates3d을 사용하여 AR_COORDINATES_2D_OPENGL_NORMALIZED_DEVICE_COORDINATES를 입력으로 사용하고 AR_COORDINATES_3D_EIS_NORMALIZED_DEVICE_COORDINATES를 출력으로 사용하여 3D 기기 좌표를 가져오고 AR_COORDINATES_3D_EIS_TEXTURE_NORMALIZED을 출력으로 사용하여 3D 텍스처 좌표를 가져옵니다. 현재 ArFrame_transformCoordinates3d에 지원되는 유일한 입력 좌표 유형은 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_);

EIS가 꺼져 있으면 출력 3D 좌표는 2D 좌표와 동등하며, z 값은 변경되지 않도록 설정됩니다.

셰이더 수정

계산된 3D 좌표는 배경 렌더링 셰이더에 전달되어야 합니다. 이제 꼭짓점 버퍼가 EIS를 통해 3D로 표시됩니다.

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

또한 프래그먼트 셰이더는 원근 보정을 적용해야 합니다.

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

자세한 내용은 hello_eis_kotlin 샘플 앱을 참고하세요.