Langzeitbelichtung
Langzeitbelichtung
Sonntag, 28. Juli 2013
Eine Langzeitbelichtung stellt immer eine gewisse Herausforderung dar. Das bekannteste Stichwort bei der analogen Fotografie ist „Schwarzschild“, bei der digitalen „Rauschen“. Beide Herausforderungen werden an uns vorbeigehen: Mit Digital haben wir nichts am Hut und das Papier scheint für lange Belichtungszeiten ausgelegt.
Bei den ersten Probeaufnahmen mit dem Papier ist mir „Schwarzschild“ kurz begegnet. Testaufnahmen mit einer 6x9 Kamera (Objektiv) und einer Belichtungszeit zwischen 1-2 Sekunden, hinterließen weniger Helligkeit auf dem Papier als die Aufnahmen im Minutenbereich hinter einem Loch. Der Schwarzschild-Effekt schlägt also beim Papier eher bei zu kurzer Belichtungszeit zu.
Bezüglich der Langzeitlichtung beschäftigt uns im Moment eher die Herausforderungen schwankender Lichtsituationen. Man misst gewissenhaft, ermittelt bspw. 25 Minuten Belichtungszeit, nimmt die Kappe ab, 5 Minuten später verschwindet die Sonne hinter einer Wolke, kommt irgendwann wieder raus oder auch nicht. Oder, anderes Szenario. Wir ermitteln, an einem der Oktobernachmittage an denen wir unterwegs sein werden, um 16:30 Uhr eine Belichtungszeit von einer Stunde. Gibt der Sonnenstand um 17:00 Uhr dann noch das gleiche Licht her?
Ideal wäre ein Belichtungsmesser der nach der Erstmessung permanent weiter misst und die Restzeit dann ständig aktualisiert. Vielleicht gibt es einen solchen sogar, gefunden habe ich aber keinen.
Also habe ich mir für unser Projekt selbst einen zusammen gebaut, genauer, zusammen programmiert!
Ein Android Tablet hat (wie andere Tablets und Smartphones natürlich auch) einen Helligkeitssensor. Dieser Sensor wird benötigt um die Helligkeit des Displays der Umgebungsbeleuchtung anzupassen. Diesen Sensor kann man auslesen. Zurückgeliefert wird ein Wert, welcher der Umgebungshelligkeit in Lux entsprechen soll. Ob der nun mehr oder weniger genau justiert ist, wäre nicht unbedingt das entscheidende. Einzig wichtig wäre, dass die gelieferten Werte sich linear zur aktuellen Lichtmenge verhalten. In anderen Worten: Bei doppelter Lichtmenge sollte sich der gemessene Wert verdoppeln, bei halber Lichtmenge halbieren.
Mit ein paar Zeilen Java konnte ich, bei recht spartanisch gehaltener Oberfläche, eine Lösung für diesen Zweck erstellen. Das Programm geht dabei wie folgt vor:
•Es wird die (wie auch immer gemessene) Belichtungszeit in Sekunden eingegeben
•Bei „Start“ ermittelt das Programm den aktuellen Wert der Umgebungshelligkeit und multipliziert diesen mit den eingegebenen Sekunden zu einem Wert „notwendige Belichtung“
•Jeder Sekunde ermittelt das Programm den neuen Wert der Helligkeit und zieht diesen Wert von „notwendige Belichtung“ ab. Dessen neuer Wert, geteilt durch den aktuellen Helligkeitswert, ergibt die aktuelle Restzeit in Sekunden
Die Applikation misst auch im Hintergrund, also auch dann wenn das Display von selbst ausgeht, brav weiter. Ist das Display ausgeschaltet, signalisieren wiederkehrende Beeps das Ende der Belichtungszeit.

Beispiel: 1504 Lux | 10.55 LW | 600 Sek. Vorgabe | 546 Sek. ohne Korrektur | 534 Sek. mit Korrektur
Nun muss die Praxis in den nächsten Wochen zeigen, ob das alles „graue Theorie“ ist oder dieses Programm dann auch hält was es verspricht. Unser „Baby-Bauwagen“, die 16 x 24 " Kamera, ist inzwischen einsatzbereit...
Ralf Tossenberger

Für Interessierte, die Applikation gibt es hier:
http://www.licht21.de/bauwagen/download/LightMeter.apk
Für ganz Neugeirige, der aktuelle Sourcecode des Programmes:
(Update auf Version 1.4 am 17.09.2013)
package de.bit_impulse.lightmeter;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
package de.bit_impulse.lightmeter;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class MainActivity extends Activity implements SensorEventListener {
WakeLock screenWakeLock;
private SensorManager mSensorManager;
private Sensor mLight;
private Timer mTimer;
private boolean paused;
private OnClickListener mOnClickListener;
private float luxCurrent;
private double luxDesired;
private double luxActual;
private int seconds1;
private int seconds2;
private int seconds3;
@Override
protected void onCreate(Bundle savedInstanceState) {
Log.i("state", "onCreateBundle");
super.onCreate(savedInstanceState);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_NOSENSOR);
setContentView(R.layout.activity_main);
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mLight = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
mSensorManager.registerListener(this, mLight,
SensorManager.SENSOR_DELAY_NORMAL);
mOnClickListener = new OnClickListener() {
public void onClick(View v) {
if (seconds3 == 0) {
seconds1 = Integer
.parseInt(((EditText) findViewById(R.id.textSeconds1))
.getText().toString());
seconds2 = seconds1;
seconds3 = seconds1;
luxActual = 0;
luxDesired = luxCurrent * seconds1;
mTimer = new Timer();
mTimer.schedule(new MTimerTask(), 1000, 1000);
paused = false;
}
}
};
((Button) findViewById(R.id.buttonStart))
.setOnClickListener(mOnClickListener);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
protected void onResume() {
Log.i("state", "onResume");
if (screenWakeLock != null) {
if (screenWakeLock.isHeld())
screenWakeLock.release();
screenWakeLock = null;
}
paused = false;
updateUI();
super.onResume();
}
@Override
protected void onPause() {
Log.i("state", "onPause");
super.onPause();
paused = true;
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
screenWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"screenWakeLock");
screenWakeLock.acquire();
}
@Override
protected void onStop() {
Log.i("state", "onStop");
super.onPause();
}
@Override
protected void onDestroy() {
Log.i("state", "onDestroy");
mSensorManager.unregisterListener(this);
if (mTimer != null) {
mTimer.cancel();
mTimer.purge();
}
super.onDestroy();
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
if (sensor.getType() == Sensor.TYPE_LIGHT) {
// Log.i("Sensor Changed", "Accuracy :" + accuracy);
}
}
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_LIGHT) {
// Log.i("Sensor Changed", "onSensor Change :" + event.values[0]);
luxCurrent = event.values[0];
((EditText) findViewById(R.id.textLux)).setText(""
+ event.values[0]);
((EditText) findViewById(R.id.textEv)).setText(""
+ Math.log(event.values[0] / 2.5) / Math.log(2));
}
}
private void updateUI() {
((EditText) findViewById(R.id.textSeconds1)).setText("" + seconds1);
((EditText) findViewById(R.id.textSeconds2)).setText("" + seconds2);
((EditText) findViewById(R.id.textSeconds3)).setText("" + seconds3);
if (seconds3 == 0) {
((EditText) findViewById(R.id.textSeconds1)).setFocusable(true);
((EditText) findViewById(R.id.textSeconds1))
.setFocusableInTouchMode(true);
} else {
((EditText) findViewById(R.id.textSeconds1)).setFocusable(false);
((EditText) findViewById(R.id.textSeconds1))
.setFocusableInTouchMode(false);
}
}
class MTimerTask extends TimerTask {
public void run() {
if (seconds3 != 0) {
seconds2--;
luxActual += luxCurrent;
seconds3 = (int) ((luxDesired - luxActual) / luxCurrent);
if (seconds3 < 0) {
seconds3 = 0;
}
Log.i("actual", " Sec1:" + seconds1 + " Sec2:" + seconds2
+ " Sec3:" + seconds3 + " luxDesired:" + luxDesired
+ " LuxActual:" + luxActual + " luxCurrent:"
+ luxCurrent);
if (!paused) {
runOnUiThread(new Runnable() {
public void run() {
updateUI();
}
});
}
}
if (seconds3 == 0) {
if (!paused) {
mTimer.cancel();
mTimer.purge();
if (screenWakeLock != null) {
if (screenWakeLock.isHeld()) {
screenWakeLock.release();
screenWakeLock = null;
}
}
} else {
new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 100)
.startTone(ToneGenerator.TONE_PROP_ACK, 400);
}
}
}
}
}
...stellen uns den Bauwagen
in Kooperation mit