Zeitraffer aus Einzelfotos

Ich habe eine Schwäche für Zeitrafferaufnahmen. Um gutes Ausgangsmaterial zu erhalten, kann man seine Kamera auf ein Stativ stellen und regelmäßig auslösen lassen oder man nutzt eine der zahlreichen Webcams an imposanten Orten auf der Welt. Ende letzten Jahres hat die Webcam auf dem Münchner Olympiaturm eine spannende Weitwinkeloptik bekommen. Der Bildausschnitt hat mich inspiriert daraus ein Zeitraffervideo zu erstellen.
Hierfür speichere ich das öffentlich zur Verfügung gestellte Webcambild regelmäßig ab.


Da ich derzeit keinen V-Server habe, auf dem ich Cronjobs ausführen könnte, habe ich auf meinem Router einen Cronjob eingerichtet, der das Script auf dem Server regelmäßig aufruft.

* * * * * root /usr/bin/wget -q -O /dev/null http://meinserver.de/olympiaturmWebcam.php

Wenn genug Bildmaterial zusammengekommen ist, starte ich ein kleines Script, das die Fotos vom Server Zwischenspeicher herunterlädt, zu einem Video zusammensetzt und etwas Hintergrundmusik hinzufügt.

# !/bin/sh
# Timelapse Script
cd /media/Timelapse/Olympiaturm

# neue Webcambilder laden
wget -A jpg -m -p -np -nd -N -l 1 http://meinserver.de/OlympiaturmBilder/

# 7 Tage Rückblick ###########################################################

# Bilder der letzten 7 Tage raussuchen
mkdir img_in_order
x=1;
for i in `find . -maxdepth 1 -name "*.jpg" -mtime -7 | sort -n`; do
	counter=$(printf %04d $x);
	ln "$i" img_in_order/img"$counter".jpg;
	x=$(($x+1));
done;

# Bilder mit zu wenig Inhalt, z.B. Nachtbilder, anhand der Größe rausschmeißen. Eignet sich auch, um fehlerhaft übertragene Bilder zu entfernen.
find img_in_order/ -size -15k -name "*.jpg" -exec rm -rf {} \;

# Einzelbilder zu Film zusammenfügen
mencoder mf://img_in_order/*.jpg -mf fps=25:type=jpg -ovc copy -oac copy -o film_letzte_woche.avi

# Tonspur hinzufügen
ffmpeg -shortest -i film_letzte_woche.avi -vcodec copy -i sound.mp3 -acodec libmp3lame -ac 2 -ab 128k -y film_letzte_woche_sound.avi
 
# Fürs Web kodieren

# h2.64
ffmpeg -i film_letzte_woche_sound.avi -strict experimental -f mp4 -vcodec mpeg4 -r 25 -b 2000k -s 640x480 -acodec aac -ac 2 -ab 128k -y olympiaturm_letzte_woche.mp4

# ogv
ffmpeg -i film_letzte_woche_sound.avi -acodec libvorbis -r 25 -b 2000k -s 640x480 -ab 128k -y olympiaturm_letzte_woche.ogv

# aufräumen
rm -r img_in_order

Das Ergebnis sieht dann so aus.

Wer hat Lust hat etwas lebhaftere Zeitraffer mit virtuellen Kameraschwenks zu erzeugen, dem kann ich das Tool LRTimelapse nur wärmstens empfehlen.

Meine Foursquare Fotowand

Ich schleppe meine Nikon ja fast überall mit hin, aber greife dennoch zwischendurch auch gern zum Telefon, um einen Moment unmittelbar mit Familien und Freunden zu teilen. Allein auf Foursquare sind dabei inzwischen schon so einige Schnappschüsse zusammen gekommen. Durch die neueren App-Versionen, die die Fotos stärker in den Fokus rücken, wurde ich auf diesen kleinen Schatz aufmerksam und blätterte mit Freude durch die eingefrorenen Momente der letzten Monate. Dabei kam ich auf die Idee dieses Fototagebuch mit Schnappschüssen neben meiner eigentlichen Fotogalerie auch auf dieser Homepage zur Verfügung zu stellen. Ich nenne die Sammlung schlicht ‚Orte‘.

Hierfür habe ich in die Foursqaure-API geschaut und ein kleines Script gebastelt. Im ersten Schritt werden alle Checkins geladen und die, bei denen ich ein Foto gemacht habe mit allen für mich relevanten Informationen in einem Array gespeichert.

function getPhotos($limit=1)
{
	$foursquare_token = 'XXX';
	$count = 0;
	$jsonString = file_get_contents('https://api.foursquare.com/v2/users/self/checkins?oauth_token='.$foursquare_token.'&v=20120824&limit=1000');

	$obj = json_decode($jsonString);

	$checkins = $obj->{'response'}->{'checkins'}->{'items'};

	foreach ($checkins as $checkin)
	{		
		foreach ($checkin->{'photos'}->{'items'} as $picture)
		{
			$photos[] = array('date' => $checkin->{'createdAt'}, 
                  'name'   => $checkin->{'venue'}->{'name'},
				  'city'   => $checkin->{'venue'}->{'location'}->{'city'},
				  'country'   => $checkin->{'venue'}->{'location'}->{'country'},
				  'comment' => $checkin->{'shout'},
                  'imageURL'  => $picture->{'prefix'}."original".$picture->{'suffix'},
				  'thumbURL'  => $picture->{'prefix'}."200x200".$picture->{'suffix'});
			$count++;
			if ($count >= $limit)
				return $photos;
		}
	}
	return $photos;
}

Für den Zugriff wird der persönliche Account-Token benötigt, den man z.B. nach Anmeldung auf der API Explorer Seite auslesen kann.

Eine simple Demofunktion gibt die Fotos aus.

function getPhotosHTML($limit=1, $picturesPerRow=4)
{
	$photos = getPhotos($limit);
	$i=0;

	foreach ($photos as $photo)
	{
		echo ""; echo "";
		$i++;
		if ($i%$picturesPerRow == 0)
			echo "
";
	}
}

Um nicht bei jeder Seitenanfrage auf die API zu gehen, kann man sich bei Bedarf die Antwort auch noch in einem kleinen Cache zwischenspeichern.

function getPhotosCached($limit=1)
{
	$cache_file = "";
	$cache_life = 60*60*2; //caching time, in seconds

	$filemtime = @filemtime($cache_file);  // returns FALSE if file does not exist
	$photos = '';

	if (!$filemtime or (time() - $filemtime >= $cache_life)){
		$photos = getPhotos($limit);
		file_put_contents($cache_file, serialize($photos));
	}
	else
	{
		$photos = unserialize(file_get_contents($cache_file));
	}
	return $photos;
}

Python: XML / HTML konforme Strings

Kleine Hilfsfunktion, um XML / HTML konforme Strings zu erzeugen

def encodeHTML(self,text):
        """
        Encodes strings to valid HTML.
        @type text: String
        @param text: Text
        """
        l=[]
        for c in text:
            b=ord(c)
            if c=="\n":
                c=""
            else:
                if b<32 or b>127 or c in ['<','>','"',';','&','@','%','#',' ','(', ')']:
                    c="&#%03d;"%b
            l.append( c )
        s="".join( l )
        return s

Worker Thread von wxPython GUI

Um die GUI für längere Berechnungen nicht zu blockieren sollte man einen neuen Thread erzeugen. Dieser kann die GUI nach dem Observer Pattern über seinen aktuellen Zustand informieren:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import wx
import os, sys, time
import threading
import wx.lib.newevent

[wxID_FRAME1, wxID_FRAME1BT_START,
] = [wx.NewId() for _init_ctrls in range( 2 )]

modules ={'Frame1': [1, 'Main frame of Application', u'Frame1.py']}

( NewStatusEvent, EVT_NEW_STATUS ) = wx.lib.newevent.NewEvent()

class BoaApp( wx.App ):
	def OnInit( self ):
		self.main = Frame1( None )
		self.main.Show()
		self.SetTopWindow( self.main )

		return True

class Frame1( wx.Frame ):
	def _init_ctrls( self, prnt ):
		# generated method, don't edit
		wx.Frame.__init__( self, id=wxID_FRAME1, name='', parent=prnt,
		pos=wx.Point( 470, 586 ), size=wx.Size( 400, 250 ),
		style=wx.DEFAULT_FRAME_STYLE, title='Working Thread' )
		self.SetClientSize( wx.Size( 392, 216 ) )

		self.bt_start = wx.Button( id=wxID_FRAME1BT_START,
		label=u'run Worker', name=u'bt_start', parent=self,
		pos=wx.Point( 264, 160 ), size=wx.Size( 107, 23 ), style=0 )
		self.bt_start.Bind( wx.EVT_BUTTON, self.OnBt_startButton,
		id=wxID_FRAME1BT_START )

	def __init__( self, parent ):
		self._init_ctrls( parent )

		# worker thread
		self.myworkingthread = None

		# bind event from worker thread to event-handler method
		self.Bind( EVT_NEW_STATUS, self.updateStatus )

	def updateStatus( self, event ):
		"""Eventhandler."""
		print(event.current_state )

	def OnBt_startButton( self, event ):
		self.myworkingthread = MyWorkingThread( self )
		# add observer
		self.myworkingthread.add_event_recipient( self )
		self.myworkingthread.start()

	def __del__( self ):
		self.myworkingthread.stop()
		self.myworkingthread.join()

class MyWorkingThread( threading.Thread ):

	def __init__( self, referrer ):
		threading.Thread.__init__( self )
		self.cancel = threading.Event()
		self.gui = referrer

		# observer list
		self.event_recipients = []

		self.running = True

	def add_event_recipient( self, recipient ):
		"""add observer."""
		self.event_recipients.append( recipient )

	def run( self ):
		# do a lot of work
		while self.running:
			evt = NewStatusEvent()
			evt.current_state = 'working…'
			# notify observers
			for recipient in self.event_recipients:
				if recipient:
					wx.CallAfter( recipient.ProcessEvent, evt )
			time.sleep(1)

	def stop( self ):
		# Cleanup
		self.cancel.set()
		self.event_recipients = []
		self.running = False

def main():
	application = BoaApp( 0 )
	application.MainLoop()

if __name__ == '__main__':
	main() 

Google Maps auf eigenen Seiten nutzen

http://www.google.com/apis/maps/

Google Maps basiert auf JavaScript und kann daher, ohne eine Software zu installieren, in jedem JavaScript fähigen Web Browser angezeigt werden. Momentan unterstützt Google Maps folgende Browser: Firefox/Mozilla, IE 5.5+, Safari 1.2+ und Opera. Google Maps kann Punkte/Marker, Linien und Infofenster anzeigen. Google Maps in eine Website einbinden

Um eine Google Maps Karte in eine Website zu integrieren benötigt man zuerst einen API-Key. Diesen bekommt man nur, wenn man sich zuvor für ein Google Konto angemeldet hat. Jeder registrierte API-Key ist jeweils nur für ein Verzeichnis auf dem Webserver gültig (z.B. http://www.meineseite.de/googlemap).

Beispiel 1 (Gizeh): Diese Karte ist auf Gizeh ausgerichtet, zwei Marker (mit Info-Fenster) verweisen auf die Pyramiden. Im folgenden der Code zu Beispiel 1 mit Erläuterungen (Update am 13.04.2006 auf API Version 2):

Code im Tag mit API-Key:


Code im Tag:


Excel: dynamische Summenzeile

Sub Summe_bilden()
	Dim i As Long
	Dim adress1, adress2 As String
	Range(”E2″).Select ‘hier deine spalte und zelle eintippen
	adress1 = ActiveCell.Address

	i = 0
	While ActiveCell.Value <> ""
		ActiveCell.Offset(1, 0).Select 'springst ne zeile runter
		i = i + 1
	Wend 'zählschleife is fertig, wenn ne zelle leer ist.

	ActiveCell.Offset(-1, 0).Select 'springst ne zeile hoch, nimmst die adresse mit:
	adress2 = ActiveCell.Address
	ActiveCell.Offset(3, 0).Select 'springst 2 zeile runter, hier kommt summe rein:

	ActiveCell.Value = "=SUM(" & adress1 & ":" & adress2 & ")"
End Sub

JavaScript: Cookie setzen und auslesen



Cookietest







Nachname:
Vorname:
Abteilung:

Excel: Erstellungsdatum

Sub GetDateCreated()
	'This requires a Reference to Microsoft Runtime Scripting Library
	Dim FSO As Scripting.FileSystemObject
	Dim FileItem As Scripting.File
	Dim DateCreated As String

Set FSO = New Scripting.FileSystemObject Set FileItem = FSO.GetFile(ActiveWorkbook.Path & "\" & ActiveWorkbook.Name) DateCreated = FileItem.DateCreated End Sub