{"id":8410,"date":"2015-12-23T21:04:03","date_gmt":"2015-12-23T19:04:03","guid":{"rendered":"http:\/\/lukse.lt\/uzrasai\/?p=8410"},"modified":"2016-01-28T10:22:34","modified_gmt":"2016-01-28T08:22:34","slug":"overlaying-seamless-messages-on-time-lapsed-city","status":"publish","type":"post","link":"https:\/\/lukse.lt\/uzrasai\/2015-12-overlaying-seamless-messages-on-time-lapsed-city\/","title":{"rendered":"Scrolling a message on a building in a time lapse video"},"content":{"rendered":"<p style=\"text-align: justify;\"><a rel=\"attachment wp-att-8475\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-8475 alignleft\" src=\"http:\/\/lukse.lt\/uzrasai\/wp-content\/uploads\/2015\/12\/studentai.gif\" alt=\"studentai\" width=\"200\" height=\"135\" \/><\/a>This 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.<\/p>\n<div align=\"center\"><!--more--><\/div>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<div align=\"center\"><iframe loading=\"lazy\" src=\"https:\/\/www.youtube.com\/embed\/KczYUK2eIXY?rel=0\" width=\"640\" height=\"420\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><\/iframe><\/div>\n<p>&nbsp;<\/p>\n<div style=\"text-align: justify;\" align=\"center\">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&#8217;s hack the time-lapse video.<\/div>\n<p>&nbsp;<\/p>\n<h3 style=\"text-align: justify;\" align=\"center\">Source video<\/h3>\n<div style=\"text-align: justify;\" align=\"center\">\n<p><a onclick=\"javascript:pageTracker._trackPageview('\/downloads\/uzrasai\/wp-content\/uploads\/2015\/12\/2.png');\"  href=\"http:\/\/lukse.lt\/uzrasai\/wp-content\/uploads\/2015\/12\/2.png\" rel=\"attachment wp-att-8432\" rel=\"lightbox[8410]\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-8432 alignleft\" src=\"http:\/\/lukse.lt\/uzrasai\/wp-content\/uploads\/2015\/12\/2-400x300.png\" alt=\"2\" width=\"400\" height=\"300\" srcset=\"https:\/\/lukse.lt\/uzrasai\/wp-content\/uploads\/2015\/12\/2-400x300.png 400w, https:\/\/lukse.lt\/uzrasai\/wp-content\/uploads\/2015\/12\/2.png 682w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/a>First 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 &#8220;dark_background&#8221; &#8211; it will be used by python script.<\/p>\n<\/div>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p style=\"text-align: justify;\"><a onclick=\"javascript:pageTracker._trackPageview('\/downloads\/uzrasai\/wp-content\/uploads\/2015\/12\/3.png');\"  href=\"http:\/\/lukse.lt\/uzrasai\/wp-content\/uploads\/2015\/12\/3.png\" rel=\"attachment wp-att-8435\" rel=\"lightbox[8410]\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-8435 alignleft\" src=\"http:\/\/lukse.lt\/uzrasai\/wp-content\/uploads\/2015\/12\/3-400x297.png\" alt=\"3\" width=\"400\" height=\"297\" srcset=\"https:\/\/lukse.lt\/uzrasai\/wp-content\/uploads\/2015\/12\/3-400x297.png 400w, https:\/\/lukse.lt\/uzrasai\/wp-content\/uploads\/2015\/12\/3.png 691w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/a>Then select all windows with light. Clone if any is missing. Then create separate layer for each window. Layers should be named &#8220;x,y&#8221; starting from left bottom corner (for example &#8220;1,1&#8221; &#8211; 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.<\/p>\n<p style=\"text-align: justify;\">Save this as PSD file. It will be consumed by python script.<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<h3>Overlay<\/h3>\n<p style=\"text-align: justify;\"><a onclick=\"javascript:pageTracker._trackPageview('\/downloads\/uzrasai\/wp-content\/uploads\/2015\/12\/4.png');\"  href=\"http:\/\/lukse.lt\/uzrasai\/wp-content\/uploads\/2015\/12\/4.png\" rel=\"attachment wp-att-8438\" rel=\"lightbox[8410]\"><img loading=\"lazy\" decoding=\"async\" class=\"size-medium wp-image-8438 alignleft\" src=\"http:\/\/lukse.lt\/uzrasai\/wp-content\/uploads\/2015\/12\/4-400x265.png\" alt=\"4\" width=\"400\" height=\"265\" srcset=\"https:\/\/lukse.lt\/uzrasai\/wp-content\/uploads\/2015\/12\/4-400x265.png 400w, https:\/\/lukse.lt\/uzrasai\/wp-content\/uploads\/2015\/12\/4-768x509.png 768w, https:\/\/lukse.lt\/uzrasai\/wp-content\/uploads\/2015\/12\/4-1024x678.png 1024w, https:\/\/lukse.lt\/uzrasai\/wp-content\/uploads\/2015\/12\/4.png 1060w\" sizes=\"auto, (max-width: 400px) 100vw, 400px\" \/><\/a>To create overlay layer I used tool called <a onclick=\"javascript:pageTracker._trackPageview('\/outgoing\/www.live-leds.de\/');\"  href=\"http:\/\/www.live-leds.de\/\">jinx<\/a>. It allows real-time control of LED&#8217;s, but I used just static output functionality.<\/p>\n<p style=\"text-align: justify;\">Setup matrix size (Setup \/ Matrix Options)  Width=12, Height=16<\/p>\n<p style=\"text-align: justify;\">Setup Output (Setup \/ Output Devices \/ Add \/ Bitmap Export \/ Redirect Output to File&#8230;)<\/p>\n<p style=\"text-align: justify;\">Now create scrolling message. In order to start recording press (Setup \/ Start Output). To stop &#8211; navigate to the same menu item.<\/p>\n<p>&nbsp;<\/p>\n<h3>Easy part goes here<\/h3>\n<p>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. <code><\/code><\/p>\n<pre>\r\n# -*- coding: utf-8 -*-\r\nfrom psd_tools import PSDImage\r\nfrom PIL import Image\r\nimport fnmatch, os\r\n\r\npsd_file = 'data.psd'\r\nimage_path = 'images1'\r\noverlay_path = 'overlay1'\r\nstart_from = 620\r\npixel_grid_width = 12\r\npixel_grid_height = 16\r\npsd_layer_dark_background = 'dark_background'\r\n\r\n\r\ndef find_files(directory, pattern):\r\n\tfile_list = []\r\n\tfor root, dirs, files in os.walk(directory):\r\n\t\tfor basename in files:\r\n\t\t\tif fnmatch.fnmatch(basename, pattern):\r\n\t\t\t\tfilename = os.path.join(root, basename)\r\n\t\t\t\tfile_list.append(filename)\r\n\treturn file_list\r\n\r\ndef get_active_pixels(img):\r\n\t(overlay_w, overlay_h) = img.size\r\n\r\n\tactive_overlay_pixels = []\r\n\tfor x in xrange(overlay_w):\r\n\t\tfor y in xrange(overlay_h):\r\n\t\t\t(r,g,b) = img.getpixel((x, y))\r\n\t\t\tif r+g+b > 200:\r\n\t\t\t\tpixel = str(x+1)+','+str(overlay_h-y)\r\n\t\t\t\tactive_overlay_pixels.append(pixel)\r\n\r\n\treturn active_overlay_pixels\r\n\r\n\r\nprint 'Loading PSD file...'\r\npsd = PSDImage.load(psd_file)\r\n\r\nwindows = {}\r\n\r\nprint 'Loading layers...'\r\nfor layer in psd.layers:\r\n\ttry:\r\n\t\twindow = {}\r\n\t\twindow['name'] = layer.name\r\n\t\twindow['x1'] = layer.bbox.x1\r\n\t\twindow['y1'] = layer.bbox.y1\r\n\t\twindow['img'] = layer.as_PIL()\r\n\t\twindows[layer.name] = window\r\n\texcept:\r\n\t\tpass\r\n\r\n# Load source image list\r\nprint 'Searching for source images...',\r\nsource_image_list = find_files(image_path, '*.jpg')\r\nprint 'found:', len(source_image_list)\r\n\r\n# Load overlay images\r\nprint 'Searching for overlay images...',\r\noverlay_image_list = find_files(overlay_path, '*.bmp')\r\nprint 'found:', len(overlay_image_list)\r\n\r\nsource_index = start_from\r\nfor overlay_index in overlay_image_list:\r\n\timg_overlay = Image.open(overlay_index)\r\n\tactive_overlay_pixels = get_active_pixels(img_overlay)\r\n\r\n\timg_main = Image.open(source_image_list[source_index])\r\n\timg_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'])\t\r\n\r\n\tfor pixel in active_overlay_pixels:\r\n\t\ttry:\r\n\t\t\timg_main.paste(windows[pixel]['img'], (windows[pixel]['x1'], windows[pixel]['y1']), windows[pixel]['img'])\r\n\t\texcept:\r\n\t\t\tpass\r\n\r\n\tos.remove(source_image_list[source_index])\r\n\timg_main.save(source_image_list[source_index])\r\n\r\n\tsource_index += 1\r\n\tprint source_index\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>This 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.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[38,4,19,5,15],"tags":[],"class_list":["post-8410","post","type-post","status-publish","format-standard","hentry","category-in-english","category-nuotraukos","category-time-lapse","category-uzrasai","category-video"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p2rU5c-2bE","jetpack_sharing_enabled":true,"jetpack_likes_enabled":true,"_links":{"self":[{"href":"https:\/\/lukse.lt\/uzrasai\/wp-json\/wp\/v2\/posts\/8410","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/lukse.lt\/uzrasai\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/lukse.lt\/uzrasai\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/lukse.lt\/uzrasai\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/lukse.lt\/uzrasai\/wp-json\/wp\/v2\/comments?post=8410"}],"version-history":[{"count":64,"href":"https:\/\/lukse.lt\/uzrasai\/wp-json\/wp\/v2\/posts\/8410\/revisions"}],"predecessor-version":[{"id":8502,"href":"https:\/\/lukse.lt\/uzrasai\/wp-json\/wp\/v2\/posts\/8410\/revisions\/8502"}],"wp:attachment":[{"href":"https:\/\/lukse.lt\/uzrasai\/wp-json\/wp\/v2\/media?parent=8410"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/lukse.lt\/uzrasai\/wp-json\/wp\/v2\/categories?post=8410"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/lukse.lt\/uzrasai\/wp-json\/wp\/v2\/tags?post=8410"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}