środa, 24 kwietnia 2013

Time lapse: end of first experiment

Because my tomatoes are growing unexpectedly fast I had to stop capturing pictures quicker than I have planned as they do not fit in the frame.

So 2664 pictures was taken from 16.03 to 23.04 at 20 minutes interval. The video size is about 715 Mb and the video length is 3min 43 seconds (at 12 fps or 1:47 at 25 fps).

The videos are available at YouTube: 25 fps | 12 fps

niedziela, 21 kwietnia 2013

Augmenting video files with GPS data

This post describes in detail how to add GPS data to video file using `visual correlation' (see also: Video geocoding with gpsbabel).

Zebra crossing at Osowa
Crossing at Osowa

There is an easy way to augment video files with GPS data using GPSbabel. Since version 1.4 of GPSBabel is able to create a subtitle file from a GPS tracklog. The subtitle contains latitude/longitude/altitude as well as the time. With a simple Perl scripts I have added current speed (not particularly accurate however).

To convert GPX file to subtitles one have to execute:


gpsbabel -i gpx -f FILE.gpx -o subrip,video_time=hhmmss,gps_time=hhmmss,gps_date=YYYYMMDD -F FILE.srt

Where: video_time -- video position (relative to beginning of video) for which exact corresponding GPS timestamp is known. gps_time -- the time part of the GPS timestamp which corresponds to a known position in the video. gps_date -- the date part of the GPS timestamp which corresponds to a known position in the video.

On a video (see below) you can see that in 34 second I passed the zebra crossing. The zebra's crossing coordinates can be easily identified at Google Maps (cf. picture Crossing at Osowa). Now one have to search the GPX track for the point which is nearest to 54.429591/18.477973. I developed a simple Perl script for that purpose:


$ perl My_GPX_nearest_timestamp.pl -c 54.429591:18.477973 20130420.gpx
*** USAGE: My_GPX_nearest_timestamp.pl -c latitude:longitude GPX-file
*** Looking for 20 points near: 54.429591:18.477973 (lat/lon) ***
> 15.3758195746663 2013-04-20T10:27:09Z 54.429509640:18.477780819
> 22.0617273294607 2013-04-20T09:05:15Z 54.429701502:18.478256240
> 32.6458959467509 2013-04-20T10:27:15Z 54.429787332:18.478348190
> 43.3771684316959 2013-04-20T09:05:24Z 54.429531014:18.477310427
> 47.7727043140018 2013-04-20T09:05:11Z 54.429905936:18.478475260
> 63.903936892351 2013-04-20T10:27:00Z 54.429627573:18.476987137
> 70.171200323179 2013-04-20T09:05:28Z 54.429655485:18.476893930

One can stipulate from the above output that I passed a point 15,4 meters away from 54.429591/18.477973 at 10:27:09 GMT as well as I passed another point which is 22 meters away from 54.429591/18.477973 at 09:05:15. As I cycled back and forth along the same route the second point is valid, the first is accidentally closer but as the time is almost one and half hours later it is clear that I was there on returning home. So gpsbabel should be executed as follows (20130420.gpx contains GPX track):


gpsbabel -i gpx -f 20130420.gpx -o subrip,video_time=000034,gps_time=090515,gps_date=20130420 -F 20130420_1.srt

Speed is added with another very simple Perl script:


perl add_speed_2_srt.pl 20130420_1.srt > 20130420_1_S.srt

Just to remind: internally all GPS units record time/date using Coordinated Universal Time aka Greenwich Mean Time vel Zulu time (for army enthusiasts). What the unit displays is another matter (usually it displays local time).

poniedziałek, 15 kwietnia 2013

Pierwszy film poklatkowy

Ustaliłem empirycznie w jaki sposób podłączyć aparat do Raspberry Pi (do SheevaPlug zresztą też) żeby nic się nie zacinało. W skrócie:

  1. Używam kompakta Nikon S3000 (Canon A620 się zacinał/odłączał--sprzedałem go na Allegro).

  2. Podłączam aparat poprzez aktywny USB hub (kupiłem w tym celu cztero-portowy HUB firmy Vivanco).

  3. Po każdym zdjęciu wykonuję reset stosownego portu USB za pomocą programiku pn. usb_reset (zobacz tutaj oraz tutaj).

Kilka aparatów

Używam dwóch aparatów Nikon S3000 (kupionych na Allegro oczywiście), więc jest problem z ustaleniem który jest który:


$gphoto2 --auto-detect
Model Port
----------------------------------------------------------
Nikon Coolpix S3000 (PTP mode) usb:001,022
Nikon Coolpix S3000 (PTP mode) usb:001,021

Można użyć opcji --port usb:001,022 aby wykonać coś z ,,pierwszym'' aparatem oraz --port usb:001,021, aby dostać się do drugiego. Oczywiście umieszczenie numerów portów na-zicher w skryptach byłoby kiepskim pomysłem ponieważ nie są one ustalone, ale się zmienią jeżeli urządzenie zostanie odłączone/przyłączone ponownie. Lepszym sposobem zidentyfikowania aparatów jest wykorzystanie numeru seryjnego:


## $gphoto2 --get-config serialnumber --port PORT
## example
$gphoto2 --get-config serialnumber --port usb:001,022
Label: Serial Number
Type: TEXT
Current: 000047514512

Mam czarnego Nikona o numerze 000041076602 oraz różowego o numerze 000047514512. Używam następującego skryptu do wykonania zdjęcia określonym aparatem:


#!/bin/bash
PINK_CAM_ID='000047514512'
BLACK_CAM_ID='000041076602'

while test $# -gt 0; do
case "$1" in
-b|--black) REQ_CAM="$BLACK_CAM_ID";;
-p|--pink) REQ_CAM="$PINK_CAM_ID";;
esac
shift
done

## Nazwa pliku ze zdjęciem:
FILENAME="NIK`date +"%Y%m%d%H%M"`.jpg"

## Przejrzyj wszystkie podłączone aparaty:
while read PORT_ID
do
##echo $PORT_ID
## -n means string is non-empty
if [ -n "$PORT_ID" ] ; then
CAM_ID=`gphoto2 --get-config serialnumber --port $PORT_ID | awk '/Current:/ { print $2 }' `
if [ $CAM_ID = "$REQ_CAM" ] ; then
REQ_CAM_PORT="$PORT_ID"
##echo "*** Req Camera ID: #$CAM_ID."
fi
fi

done <<< "`gphoto2 --auto-detect | grep usb | awk '{ print $6}'`"

# Na wypadek błędu wyślij alarmowego SMSa
if [ -z "$REQ_CAM_PORT" ] ; then
echo "*** Error: Camera $REQ_CAM not found ***"
## sent a SMS cf http://pinkaccordions.homelinux.org/wblog/sms_alerts_with_google_calendar.html
sms_reminder.sh
exit 1
fi

## reset USB
REQ_CAM_PORT_DEVNAME=`echo $REQ_CAM_PORT | sed 's/^.*://' | sed 's/,/\//'`
usb_reset /dev/bus/usb/${REQ_CAM_PORT_DEVNAME}

LANG=C gphoto2 --port "$REQ_CAM_PORT" --force-overwrite --set-config flashmode=1 \
--set-config d002=4 \
--capture-image-and-download --filename "$FILENAME"

## reset USB (powtórny)
usb_reset /dev/bus/usb/${REQ_CAM_PORT_DEVNAME}

Właściwość d002 ustawia rozdzielczość zdjęcia (4 oznacza 2592x1944).

Wartość 1 właściwościflashmode wyłącza flash.

Z moich eksperymentów wynika, że bez wykonania usb_reset bateria aparatu nie jest doładowywana (czemu?) i po pewnym czasie z powodu braku zasilania aparat odłącza się.

Film

Po czterech tygodniach mam wystarczająco dużo zdjęć aby spróbować zrobić pierwszy film.

Najpierw konwertuję wszystkie zdjęcia do rozdzielczości 1920x1080 za pomocą programu convert (z zestawu ImageMagick) uruchamianego z ,,wewnątrz'' prostego skryptu Perla. Ponieważ nazwy plików wejściowych są konstruowane wg schematu NIKYYYYMMDDHHMM.jpg (gdzie YYY to rok, MM oznacza miesiąc, itd.) sortowanie alfabetyczne oznacza ustawienie ich także we właściwym porządku chronologicznym. Nazwy plików wynikowych są zaś konstruowane jako: hd1920_00001.jpg, hd1920_00002.jpg, itd.


#!/usr/bin/perl

opendir (DIR, ".");
my @files = sort { $a cmp $b } readdir(DIR);

while (my $file = shift @files ) {
if ($file =~ /.jpg$/) { $fileNo++;
$file_out = sprintf "hd1920_%05d.jpg", $fileNo;
print "$file -> $file_out\n";
system ("convert", $file, "-geometry", "1920x1080", "$file_out");
}
}

Okazało się, że jest dokładnie 1784 zdjęć:


$ls -l hd1920_0* | wc -l
1784

Konwersja trwała około 30 min na moim przeciętnym zupełnie PC-cie. Każdy plik wynikowy miał około 0,5Mb; wszystkie razem zajmowały około 0,85Gb:


$ls -l hd1920_0* | awk '{t+=$5}; END{print t}'
853332231

Film został wykonany za pomocą programu ffmpeg:


ffmpeg -r 12 -qscale 2 -i hd1920_%05d.jpg Tomato_12.mp4

Gdzie -r 12 oznacza liczbę klatek na sekundę (12 fps) a -qscale określa jakość (1 oznacza najlepszą, 32 najgorszą jakość).

Film ma około 450 Mb. Konwersja zajmuje około 3min (on my decent PC) a długość filmu to 2min i 29 sekundy.

Film przedstawia sadzonkę pomidora (Pinkaccordion oczywiście :-). Zdjęcia były robione co 20 minut od 16 marca do 11 kwietnia.

Są także wersje na 25 fps oraz 6 fps.

sobota, 13 kwietnia 2013

Ponura historia sprzed lat

Jak byłem dawno temu w Anglii, to akurat w BBC puszczono film dokumentalny nt. następujących zdarzeń: Aidan Starrs, Gregory Burns i John Dignam -- agenci FRU oraz członkowie IRA mordują 30 czerwca 1992 r. Margaret Perry z obawy, że ta ostatnia może ich wydać. Morderstwo M. Perry pozostaje niewyjaśnione przez ponad rok -- do czasu aż mordercy Perry zostają porwani i zabici przez ISU, czyli kontrwywiad Armii Republikańskiej. Na dokładkę okazało się po latach, że w ISU latami działał inny agent FRU Freddie Scappaticci. Tak mi się to przypomniało a szczegóły wyguglałem, bo przecież po latach tych wszystkich detali i nazwisk nie pamiętałem.

Notka w BBC na temat.

piątek, 12 kwietnia 2013

Time lapse: first production

After almost 4 weeks I have enough pictures to create my first video production. (How to capture images with a still camera attached to Raspberry Pi is described here and here.)

I started from converting all pictures to 1920x1080 resolution with convert run from a simple Perl script. As the input file names are constructed as NIKYYYYMMDDHHMM.jpg (where YYY denotes year, MM denotes month etc) alphabetic sorting is OK. The resulting files are named as hd1920_00001.jpg, hd1920_00002.jpg, etc.


#!/usr/bin/perl

opendir (DIR, ".");
my @files = sort { $a cmp $b } readdir(DIR);

while (my $file = shift @files ) {
if ($file =~ /.jpg$/) { $fileNo++;
$file_out = sprintf "hd1920_%05d.jpg", $fileNo;
print "$file -> $file_out\n";
system ("convert", $file, "-geometry", "1920x1080", "$file_out");
}
}

There are exactly 1784 pictures:


$ls -l hd1920_0* | wc -l
1784

Conversion of all images lasted circa half an hour on my decent PC. Each picture size is about 0,5Mb, while the total size is 0,85Gb:


$ls -l hd1920_0* | awk '{t+=$5}; END{print t}'
853332231

To create a video from the images I run ffmpeg now:


ffmpeg -r 12 -qscale 2 -i hd1920_%05d.jpg Tomato_12.mp4

Where -r 12 means frames ratio (12 fps) and -qscale determines video quality (1 denotes best quality and 32 is the lowest one).

The video size is about 450 Mb. The conversion takes circa 3min (on my decent PC) and the video length is 2min 29 seconds.

The movie's subject is a growing tomato (Pinkaccordion variety of course:-). The photographs were taken every 20 minutes from March 16th to April 11th.

There are versions at 25 fps and 6 fps as well.

czwartek, 4 kwietnia 2013

Raspberry Pi: some progress with time-lapse photography

I have made some progress in accessing still camera with gphoto2 (cf. here). The detailed description of my set-up will be disclosed within a few weeks (as I am still not sure if it is 100% success:-). In short:

I changed camera from Canon A620 to Nikon S3000.

I connected camera with active USB hub.

On every capture USB port is reset with usb_reset utility (cf here and here)

Multiple cameras

I use two Nikon S3000 compact cameras so there is a problem how to identify which is which.


$gphoto2 --auto-detect
Model Port
----------------------------------------------------------
Nikon Coolpix S3000 (PTP mode) usb:001,022
Nikon Coolpix S3000 (PTP mode) usb:001,021

So one can use --port usb:001,022 option to access first attached camera and --port usb:001,021 to access the second one. Of course hard-coded port numbers are troublesome as they are not fixed and change if the device is disconnected/connected again. Better way to identify the camera is to use it's serial number:


## $gphoto2 --get-config serialnumber --port PORT
## example
$gphoto2 --get-config serialnumber --port usb:001,022
Label: Serial Number
Type: TEXT
Current: 000047514512

I have black Nikon with 000041076602 serial number and pink one with 000047514512 serial number. I use the following bash script to access the cameras:


#!/bin/bash
PINK_CAM_ID='000047514512'
BLACK_CAM_ID='000041076602'

while test $# -gt 0; do
case "$1" in
-b|--black) REQ_CAM="$BLACK_CAM_ID";;
-p|--pink) REQ_CAM="$PINK_CAM_ID";;
esac
shift
done

## Picture filename:
FILENAME="NIK`date +"%Y%m%d%H%M"`.jpg"

## Scan all attached cameras:
while read PORT_ID
do
##echo $PORT_ID
## -n means string is non-empty
if [ -n "$PORT_ID" ] ; then
CAM_ID=`gphoto2 --get-config serialnumber --port $PORT_ID | awk '/Current:/ { print $2 }' `
if [ $CAM_ID = "$REQ_CAM" ] ; then
REQ_CAM_PORT="$PORT_ID"
##echo "*** Req Camera ID: #$CAM_ID."
fi
fi

done <<< "`gphoto2 --auto-detect | grep usb | awk '{ print $6}'`"


if [ -z "$REQ_CAM_PORT" ] ; then
echo "*** Error: Camera $REQ_CAM not found ***"
## sent a SMS cf http://pinkaccordions.blogspot.com/2013/03/automatic-sms-alerts-using-google.html
sms_reminder.sh
exit 1
fi

## reset the USB device
REQ_CAM_PORT_DEVNAME=`echo $REQ_CAM_PORT | sed 's/^.*://' | sed 's/,/\//'`
usb_reset /dev/bus/usb/${REQ_CAM_PORT_DEVNAME}

LANG=C gphoto2 --port "$REQ_CAM_PORT" --force-overwrite --set-config flashmode=1 \
--set-config d002=4 \
--capture-image-and-download --filename "$FILENAME"

## reset the USB device again
usb_reset /dev/bus/usb/${REQ_CAM_PORT_DEVNAME}

Property d002 sets picture resolution (4 means 2592x1944).

Value 1 of flashmode turns-off flash.

It seems that without usb_reset there are problems with battery charging (why?)