Skip to main content

Cheapo Time Lapse

Photography on a Budget

Who doesn't love a good time lapse, everything goes all fast like. Clouds zipping through the sky, cars turning into streaks across the image. So I wanted try my hand at making some, but I'm broke as a joke. Therefore I wondered with a bit of code and an old Android phone could I create one? Let have a go!

Shitty Hardware

I had in a box a old Android phone, an HTC Desire S S510e to be exact. It sports:

Screen size: 3.7"
Screen Resolution (pixels): 480 x 800
Operating system: Android 2.1
Camera resolution: 5MP camera
Stand-by time: 17.9 Days
Depth: 1.19cm deep
Height: 11.9cm high
Width: 6cm wide
Autofocus: Yes
Weight (g):130g
FM tuner: FM Radio
Release date: 5 Apr 2011


So a badly smashed screen, but not important. I ended up getting this phone just by asking a friend what they got hanging around in a drawer. 

Camera Application

Now the normal camera is not going to do. So I am gonna use IP Webcam, basically this will turn the phone into a IP camera for use in security situations. Download and install. 

For my settings I have set:

Resolution: 1280 x 720 (max)
Photo Resolution 2592x1952 (max)
Quality: 50
Orientation: Upside Down (Because of how I have it set up)
Port: 8081
Prevent going to sleep: √

Everything else on default.

Now fire up by pressing Start Server at the bottom. 

Through the crack you can just about see http://192.168.28.69:8081, here is where I am gonna go to access the stream. On the page I several options one being "URL for full-resolution photo capture", that take me to http://192.168.28.69:8081/photo.jpg.







Taking Photos

I am going to build a small python application to take photos in intervals, for a set amount of photos and then stitch them together into a movie or gif. 

First function is to take a URL and save it to location with a filename

import urllib
import os, errno

def getImage(url, filename):
    cwd = os.getcwd()
    default_dir = os.path.join(cwd, 'captured')
    try:
        os.makedirs(default_dir)
    except OSError as e:
        if e.errno != errno.EEXIST:
            raise
    file = os.path.join(default_dir, filename)
    urllib.urlretrieve(url, file)

getImage(url='http://192.168.28.69:8081/photo.jpg', filename='test2.jpg')


Next is to have a function to empty the folder, run a loop of taking images and incrementing the filename. But first some maths. I am gonna have my finished time lapse at 30 frames a seconds, so if I want to create a 10 second clip I will need 300 images. Now if I have 1 image every 30 seconds it will take 2.5 hours to record. So this is my formula.

((clip_length(sec) * 30) * interval_length(sec)) / 3600 = capture_time(hrs)

So I am going to use the clip and interval length for my input variables.

def takeImages(url, clip_length, interval_length):
    images = []
    imageCount = clip_length * 30    for count, image in enumerate(range(imageCount)):
        filename = '%04d.jpg' % count
        imageFile = getImage(url=url, filename=filename)
        images.append(imageFile)
        time.sleep(interval_length)
    return images
takeImages(url='http://192.168.28.69:8081/photo.jpg', clip_length=2, interval_length=10)


Cool, now next I need to collect them all into clip. First I attempted a gif, what I found was at full resolution didn't work. So I added another module to scale the image using PIL.  I then used imageio to stream the images into a gif.

def resizeImage(imageFile):
    maxsize = (600, 600)
    img = Image.open(imageFile)
    img.thumbnail(maxsize, Image.ANTIALIAS)
    img.save(imageFile)
    return True
def makeGif(filelist):
    gifFile = os.path.join(default_dir, 'timelapse.gif')
    with imageio.get_writer(gifFile, mode='I') as writer:
        for filename in filelist:
            file = os.path.join(default_dir, filename)
            resizeImage(file)
            image = imageio.imread(file)
            writer.append_data(image)

Next I wanted to create a video from the images. Here I used ffmpeg to stream the files to a file. I download from http://www.ffmpegmac.net/ and ran it from the script as if I was doing so from the terminal. With this I just get all of the files from looking in the folder and not sending the list to the function.

def makeVideo():
    os.system('./ffmpeg -f image2 -r 30 -i ./captured/%04d.jpg -y ./captured/timelapse.mp4')

Finally I just call the functions as I need them. The Android app url at a clip length of 10 secs at an interval of 5secs ended up as so:



A right hefty file. Sorry for the time to load.

Where from here

If you are wondering, 'why the fuck didn't you just use an app', that's a good question. Well I tend to find myself with some IP camera and thought it would be an interesting way to get timelapse footage. Also there is a site that has IP cameras that haven't been secured, take a peak over at insecam.org. I also wanted to get some timelapse footage from some random cameras from around the world. 






import urllib
import os, errno
import time
import imageio
from PIL import Image

# Get the current working directory and check for/create a folder capture

cwd = os.getcwd()
default_dir = os.path.join(cwd, 'captured')
try:
    os.makedirs(default_dir)
except OSError as e:
    if e.errno != errno.EEXIST:
        raise

# Function to save an image from a URL to file

# Inputs:
#      url (str): Full URL to parse
# filename (str): name the file to be saved
# Outputs:
#  file (string): Return file as a string
def getImage(url, filename):
    # Build file location, request url and save there
    file = os.path.join(default_dir, filename)
    urllib.urlretrieve(url, file)
    return file


# Function to take several images

# Inputs:
#             url (str): Full URL to parse
#     clip_length (int): How long the time lapse clip will be in secs
# interval_length (int): The real time interval between taking images in secs
#
# Outputs:
#         images (list): Return all images as a list of files
def takeImages(url, clip_length, interval_length):
    images = []
    imageCount = clip_length * 30
    for count, image in enumerate(range(imageCount)):
        filename = '%04d.jpg' % count
        imageFile = getImage(url=url, filename=filename)
        images.append(imageFile)
        time.sleep(interval_length)
    return images


# Function to resize an image to a maximum of either 600px high or wide

# Input:
# imagefile (size): Absolute location of image
def resizeImage(imageFile):
    maxsize = (600, 600)
    img = Image.open(imageFile)
    img.thumbnail(maxsize, Image.ANTIALIAS)
    img.save(imageFile)
    return True


# Take a list of images and create a gif

# Inputs:
# filelist (list): list of files from a folder of images
def makeGif(filelist):
    gifFile = os.path.join(default_dir, 'timelapse.gif')
    with imageio.get_writer(gifFile, mode='I') as writer:
        for filename in filelist:
            file = os.path.join(default_dir, filename)
            # Send image to be resized
            resizeImage(file)
            image = imageio.imread(file)
            writer.append_data(image)


# Look in the captured folder and

def makeVideo():
    os.system('./ffmpeg -f image2 -r 30 -i ./captured/%04d.jpg -y ./captured/timelapse.mp4')


images = takeImages(url='http://184.7.223.152/jpg/image.jpg', clip_length=30, interval_length=5)

makeVideo()
makeGif(images)



Comments

Popular posts from this blog

Raspberry Pi Download Machine Part 2

Well SSH is Boring I have got my RPi download machine up and running and having success, unfortunately though SSH is annoying and tedious, so I am gonna do something about it. But a disclaimer; this is my first time working with Aria2 in the most part. RPC  Remote Procedure Call is fancy way of saying 'make this thing make that thing do a thing'. So I ran the command to load the config file (and added to my init file) in the last post and ..... BOLLOCKS ALL. So ran the command again, and need to check the processes (like Task Manager). pi@raspberrypi : ~ $  ps aux | grep aria2c root       524  0.0  0.9  17028  9284 ?        Ss   21:21   0:00 aria2c --conf-path=/home/pi/.aria2/aria2.conf pi        1008  0.0  0.2   4272  1948 pts/0    S+   21:34   0:00 grep --color=auto aria2c There it is, that little scumbag. But still no dice. In the conf file I stated that the rpc-port to be 6800 so need to check that port.  A quick note on ports, every service

Raspberry Pi Download Machine Part 1

Yet Another Raspberry Pi Project Kodi builds, weird fucking robots and classic gaming always seems to be the theme of RPi projects. But a stat I would like to know is how many are just sat in a drawer somewhere. Anyway I am part of that number, until now. I manage to find a 4TB drive and managed to blag a caddy, so with this triangle of 'crap hanging around' I thought I'd build a downloader. Open Directories So I first had the idea from the sub-reddit open directories , here storage devices are opened up to the internet without a morsel of authentication. Google comes along and indexes them and you can go and find them. Decent ones find themselves on this sub of which I assume stays up until the user realises that there broadband is getting absolutely raped. So I wanted to be able to get a URL from a server and just throw it in a WebUI and get it to auto download and ping me when all is finished.  First Steps So to start off I downloaded Raspbian

Adventures in Pillow Part 2

From my last post  where I made a slideshow promo video, I realised how powerful Pillow is. I still have a fair bit of automation to do, so another thing I do a lot of is motivational quotes for Twitter (I am aware they are fucking stupid, but they share well) The breakdown of the components are a background with a filter, the quote, who said it and our logo. Background and Filter To start off I am going to create a folder called quote and add in an image and just name it background.jpg (sourced from Pixabay ). Next I import PIL and open the file. from PIL import Image import os , errno cwd = os.getcwd() image_dir = os.path.join(cwd , 'quote' ) def filterImage (imageFile): im = Image.open(imageFile) im.show() filterImage(os.path.join(image_dir , 'background.jpg' )) Next I need to crop the image. I am going to take the centre portion out of the image to make square. Like so: So I start off with getting the dimensions of the ima