Painting with Light: Long Exposure on Android





Hello everyone, my name is Dmitry and I am an Android developer at MEL Science. Today I want to tell you how you can implement support for long exposure on smartphones, so that the resulting picture can be observed right in the process of creation. And for those interested, at the end of the article, I prepared a link to a test application - so that you can take a cool photo with a long exposure yourself.





Long exposure

Shutter speed is a term from the world of photography that defines the time the shutter opens when shooting. The longer the shutter is open, the longer the light is exposed to the light sensor. Simply put, it makes the photo brighter. Modern cameras use shutter speeds of 1/2000 second, which allows you to get an illuminated, but not overexposed photograph. A slow shutter speed means opening the shutter for a second or more. With the right scene, this allows for fantastic photographs capable of capturing the movement of light through the camera lens. And you can take pictures of anything: night streets with racing cars or a pendulum with a flashlight attached to it, allowing you to draw Lissajous figures . Or you can paint with light yourself and get whole pictures, photographs.





City streets photographed using long exposure
,

:





  • -





  • -





- . - . - 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()}")
}
      
      







.





  1. , .





  2. , .





  3. .





, . . , . 





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



:





  1. .













, , - β€œ ”. , , , . , , .. , . 





. . . , .





:





if (newBrightness > oldBrightness) {
  gl_FragColor = color;
} else {
  gl_FragColor = oldColor;
}
      
      



, . .





Long exposure

, .. ! - , , ? . - . . ( , - ).  





if (newBrightness > oldBrightness) {  
  gl_FragColor = mix(color, oldColor, 0.01);
} else { 
  gl_FragColor = mix(oldColor, color, 0.01);
}
      
      



Here are some examples with different light decay rates and times.
Odds 0.001
Odds 0.001
Coefficient 0.01
Coefficient 0.01
Odds 0.5
Odds 0.5

Conclusion

Here are some examples of what the resulting application can do.  After all, I'm not an artist: (What will you draw?
Here are some examples of what the resulting application can do. After all, I'm not an artist: (What will you draw?

That's all for today. For those wishing to try the complete application code and apk can be found here .








All Articles