Scrolling a message on a building in a time lapse video

2015-12-23 21:04 | Categories: In English, Nuotraukos, Time-lapse, Užrašai, Video

studentaiThis post is about vision processing and time-lapse video modification. As you probably know I own few stationary long term time-lapse cameras, and sometimes do some tricks with this huge data collection. This time I will walk you through improvised dot matrix display made from building windows.




This can be done spending few days of non stop work on GIMP or Photoshop, but I will be talking about more intelligent way. Let’s hack the time-lapse video.


Source video

2First you need time-lapse movie. I selected pictures captured each minute for period of about 12 hours. Scene illumination should be even (current python script limitation). Prepare dark background by cloning windows with no light from other photos. Also remaining picture should be left transparent. This way video will not be static. Name this layer “dark_background” – it will be used by python script.





3Then select all windows with light. Clone if any is missing. Then create separate layer for each window. Layers should be named “x,y” starting from left bottom corner (for example “1,1” – see notes on the picture). This is time consuming process, but helps avoiding any image processing mistakes. It took me about 30 minutes to complete.

Save this as PSD file. It will be consumed by python script.





4To create overlay layer I used tool called jinx. It allows real-time control of LED’s, but I used just static output functionality.

Setup matrix size (Setup / Matrix Options) Width=12, Height=16

Setup Output (Setup / Output Devices / Add / Bitmap Export / Redirect Output to File…)

Now create scrolling message. In order to start recording press (Setup / Start Output). To stop – navigate to the same menu item.


Easy part goes here

If everything went good, quick and dirty python script will do the magic. Feel free to modify to suit your needs. Things to do and improve: color RGB windows instead of natural ones, automatic window detection, enumeration and mapping and many other things.

# -*- coding: utf-8 -*-
from psd_tools import PSDImage
from PIL import Image
import fnmatch, os

psd_file = 'data.psd'
image_path = 'images1'
overlay_path = 'overlay1'
start_from = 620
pixel_grid_width = 12
pixel_grid_height = 16
psd_layer_dark_background = 'dark_background'

def find_files(directory, pattern):
	file_list = []
	for root, dirs, files in os.walk(directory):
		for basename in files:
			if fnmatch.fnmatch(basename, pattern):
				filename = os.path.join(root, basename)
	return file_list

def get_active_pixels(img):
	(overlay_w, overlay_h) = img.size

	active_overlay_pixels = []
	for x in xrange(overlay_w):
		for y in xrange(overlay_h):
			(r,g,b) = img.getpixel((x, y))
			if r+g+b > 200:
				pixel = str(x+1)+','+str(overlay_h-y)

	return active_overlay_pixels

print 'Loading PSD file...'
psd = PSDImage.load(psd_file)

windows = {}

print 'Loading layers...'
for layer in psd.layers:
		window = {}
		window['name'] =
		window['x1'] = layer.bbox.x1
		window['y1'] = layer.bbox.y1
		window['img'] = layer.as_PIL()
		windows[] = window

# Load source image list
print 'Searching for source images...',
source_image_list = find_files(image_path, '*.jpg')
print 'found:', len(source_image_list)

# Load overlay images
print 'Searching for overlay images...',
overlay_image_list = find_files(overlay_path, '*.bmp')
print 'found:', len(overlay_image_list)

source_index = start_from
for overlay_index in overlay_image_list:
	img_overlay =
	active_overlay_pixels = get_active_pixels(img_overlay)

	img_main =[source_index])
	img_main.paste(windows[psd_layer_dark_background]['img'], (windows[psd_layer_dark_background]['x1'], windows[psd_layer_dark_background]['y1']), windows[psd_layer_dark_background]['img'])	

	for pixel in active_overlay_pixels:
			img_main.paste(windows[pixel]['img'], (windows[pixel]['x1'], windows[pixel]['y1']), windows[pixel]['img'])


	source_index += 1
	print source_index