Olá a todos, meu nome é Dmitry e sou um desenvolvedor Android na MEL Science. Hoje quero contar como é possível implementar suporte para longa exposição em smartphones, para que a imagem resultante possa ser observada logo no processo de criação. E para os interessados, no final do artigo, preparei um link para um aplicativo de teste - para que você mesmo possa tirar uma foto legal de longa exposição.
Exposição longa
Velocidade do obturador é um termo do mundo da fotografia que define o momento em que o obturador abre ao fotografar. Quanto mais tempo o obturador fica aberto, mais tempo a luz fica exposta ao sensor de luz. Simplificando, torna a foto mais brilhante. As câmeras modernas usam velocidades de obturador de 1/2000 segundo, o que permite obter uma fotografia iluminada, mas não superexposta. Uma velocidade lenta do obturador significa abri-lo por um segundo ou mais. Com a cena certa, isso permite fotografias fantásticas, capazes de capturar o movimento da luz através da lente da câmera. Além disso, você pode tirar fotos de qualquer coisa: ruas noturnas com carros de corrida ou um pêndulo com uma lanterna acoplada, permitindo desenhar as figuras de Lissajous. Ou você mesmo pode pintar com luz e obter imagens inteiras, fotografias.
:
-
-
- . - . - Android 30 .
.
API CameraX. . OpenGL ES . , , .
, usecase . , .
, Camera2Interop , Camera2API. , .. .
val imageCaptureBuilder = ImageCapture.Builder()
Camera2Interop.Extender(imageCaptureBuilder).apply {
setCaptureRequestOption(
CaptureRequest.CONTROL_AE_MODE,
CaptureRequest.CONTROL_AE_MODE_OFF
)
setCaptureRequestOption(
CaptureRequest.SENSOR_EXPOSURE_TIME,
EXPOSURE_TIME_SEC * NANO_IN_SEC
)
}
, , cameraCharacteristics
val manager = getSystemService(CAMERA_SERVICE) as CameraManager
for (cameraId in manager.cameraIdList) {
val chars = manager.getCameraCharacteristics(cameraId)
val range = chars.get(CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE)
Log.e("CameraCharacteristics", "Camera $cameraId range: ${range.toString()}")
}
.
, .
, .
.
, 2 : . .
#extension GL_OES_EGL_image_external : require
precision mediump float;
uniform mat4 stMatrix;
uniform texType0 tex_sampler;
uniform texType1 old_tex_sampler;
varying vec2 v_texcoord;
void main() {
vec4 color = texture2D(tex_sampler, (stMatrix * vec4(v_texcoord.xy, 0, 1)).xy);
vec4 oldColor = texture2D(old_tex_sampler, v_texcoord);
float oldBrightness = oldColor.r * 0.2126 + oldColor.g * 0.7152 + oldColor.b * 0.0722 + oldColor.a;
float newBrightness = color.r * 0.2126 + color.g * 0.7152 + color.b * 0.0722 + color.a;
//
}
:
.
, , - “ ”. , , , . , , .. , .
. . . , .
:
if (newBrightness > oldBrightness) {
gl_FragColor = color;
} else {
gl_FragColor = oldColor;
}
, . .
, .. ! - , , ? . - . . ( , - ).
if (newBrightness > oldBrightness) {
gl_FragColor = mix(color, oldColor, 0.01);
} else {
gl_FragColor = mix(oldColor, color, 0.01);
}
Aqui estão alguns exemplos com diferentes taxas e tempos de decaimento de luz.
Conclusão
Isso é tudo por hoje. Para quem quiser experimentar por conta própria, o código completo do aplicativo e o apk podem ser encontrados aqui .