Category Archives: Photography

Tiny animator for stop-motion

I was working on a RP2040 HID project, but I needed some components I didn’t have … right now .. again ..

So I made something else ..

A tiny animator for stop motion animations using my webcam, python and OpenCV.

For claymotion or lego or whatever.

The program displays your webcam with the previous snapshot overlayed, so you can position everything relative to your previous snapshot.

Difference between two shots.

Press B to take a frame.

Just a proof of concept using a (BAD) webcam. (Don’t look at my hand )

CODE (short but you need OpenCV)

import  cv2
from datetime import datetime
# black is just a start empty image .. 
img=cv2.imread("black.png");
cap = cv2.VideoCapture(0)

while True: 

    ret,vid=cap.read()
    dim = (800,600)
    img1 = cv2.resize(img, dim, interpolation = cv2.INTER_AREA)
    vid1 = cv2.resize(vid, dim, interpolation = cv2.INTER_AREA)

    result=cv2.addWeighted(img1,0.5,vid1,0.5,0)
    cv2.imshow('overlay', result)
    if(cv2.waitKey(10) & 0xFF == ord('b')):
            now = datetime.now()
            current_time = now.strftime("%d_%m_%Y_%H_%M_%S")
            filename = '%s.png' % current_time
            if not cv2.imwrite(filename, vid1):
                raise Exception("Could not write image")
            img=cv2.imread(filename);

Pressing B fills your directory with PNG’s
like 24_10_2023_00_01_01.png (date formatted)

convert to GIF

convert -delay 10 -loop 0 24*.png animation.gif

Triple screen panorama viewer

Got a question, could I make the video viewer also for images.

Well, that is a great idea, i’ve got some panoramic photos myself.

A little modification, some added code, but here is a working example.

Some vacation pictures widescreen …

CODE
imageview.py filename
Use esc to stop, and enter for next image.
(Has better full screen experience than my movie player. (no padding) have to revisit that one )

Nice to have?

  • Back button?
  • Comments, renaming thumb
from pathlib import Path
from sys import platform as PLATFORM
import os
import re
import PySimpleGUI as sg
from PIL import Image, ImageEnhance, ImageTk, ImageOps, ImageFilter
from xml.etree import ElementTree as ET
import sys
from sys import platform as PLATFORM

abspath = os.path.abspath(__file__)
dname = os.path.dirname(abspath)
os.chdir(dname)

try:
    image=sys.argv[1]
except:
    print(sys.argv[0] +  " filename")
    exit()


def nextFile(currentfile,dir):
        newfile=""
        dirpath = os.path.dirname(dir)
        fileList = []
        for f in os.listdir(dirpath):
            #fpath = os.path.join(dirpath, f)
            fpath = f
            if os.path.isfile(fpath) and f.endswith(('.jpg','.JPG')):
                fileList.append(fpath)
        fileList.sort()
        for i in range(len(fileList)):
            try:
                if (fileList[i]) == currentfile:
                    newfile=fileList[i+1]
                    break
            except:
                newfile=fileList[0]
        return newfile
# yeah i know .. no thumb but full image, change it yourself!
def loadthumb(thumbfile):
    # IF exists
    path_to_file = thumbfile
    path = Path(path_to_file)

    if path.is_file():
        im = Image.open(thumbfile)
        im=ImageOps.contain(im, (5760,5760)) 
        thumbimage = ImageTk.PhotoImage(image=im)

        window['image'].update(data=thumbimage)
    else:
        window['image'].update("")

sg.theme('SystemDefaultForReal')
#------- Layout image only --------#
layout = [
        [[sg.Image('', size=(5760, 1080), key='image',background_color='black',pad=(0, 0))],
          ]]

#------- Set window --------#
window = sg.Window('Triple image player', layout, no_titlebar=True, margins=(0,0),location=(0,0), size=(5760,1080), keep_on_top=True, finalize=True,resizable=False)

window.bring_to_front()
window.Maximize()
window.bind("<Escape>", "-ESCAPE-")
window.bind("<Return>", "-ENTER-")

window['image'].expand(True, True)               

loadthumb(image)
nextfile = image
#------------ The Event Loop ------------#
while True:
    event, values = window.read(timeout=1000)       # run with a timeout so that current location can be updated
    if event == sg.WIN_CLOSED:
        break

    if event == '-ENTER-':
        nextfile = nextFile(nextfile,'./')
        loadthumb(nextfile)

    if event == '-ESCAPE-':
        window.close()
window.close()

Converting images for right resolution from a temp directory filled with large panorama photos

ls temp  | while read; do
	convert -resize 5760x -gravity center  -crop 5760x1080 -auto-orient  "temp/$REPLY" "$REPLY" 
done

Movie stabilisation and music suggestions

Some suggestions/answers for some friends.

Movie stabilisation from action cams:

Mostly I use kdenlive, but if you have an actioncam which also records movement (pan, tilt, zoom, and rotation) use a tool like Gyroflow!
This will use the motion data to correct the movement!

https://userbase.kde.org/Kdenlive/Manual/Clip_Menu/Stabilize

I’ve tried Davinci Resolve also. But I’m not sure which i’ve used for below movies.

Using blender : https://www.youtube.com/watch?v=oCHjdEODrpM
OR https://www.youtube.com/watch?v=982RL4a899g

Me flying a Cessna 172
Arja on the Death Road in Bolivia (8x speed and stabilzed)

If you want even an easier way, upload to YT, stabilise and download you movie. 🙂

Something else, what music to listen to? Any suggestions?

I had to name some (most by heart), I will edit/alter this list.
The folk/pipes artists will be in a next post.

Heavier stuff:
The prodigy, nightwish, in extremo, tanzwut, after forever, faun, gathering, therion, withintemptation

Folky
Trolska polska, dervish, gaelic storm, lunasa, michael mcgoldrick, peatbog faeries, beoga

Jazzy folk
Borne and mcleod, Bees Knees (Hamish moore and dick lee)

Film music
Akira, Vangelis (bladerunner), Kill Bill music (all kinds of sources)

Electro
Junky-xl, Trentemoller, Alt-j, Avcii

Classical
Einaudi, ennio morricone, Paganini,Rondò Veneziano

Easy listening
Aereda, Andreas Vollenweider,Anuna, Clannad, Dead can danve, enya, Era, Lais, kitaro, Moya Brennan,omnia

Blues
BB King

Divers
Alva Noto and Ryuichi Sakamoto, Buddha bar, Buena Vista Social Club, Cafe del mar, Mark Knopfler, Easy Alohas

Indie
Kensington, Imagine Dragons, 77 bombay street, Mumford and Sons, Lumineers, Of monsters and men,

Scottish Rock
Runrig

Find other music/genre’s

Background switcher Ubuntu

I was playing around with Phantomjs a headless browser.
Using this as a scraper for a ajax enabled site.

After scraping a wallpaper site, I wanted to take the big pictures and display these as background.

First sort and resize to a better size.

Below does the following:

  • Image width larger than 1800 AND
  • Image height larger than 900
  • Resize to 1920×1080 ( enlarge or reduce size )
  • Not screen filling (portrait mode) ? Than add black bars on the side.
  • Place the image in wallpaper directory

Convert script, if you resize huge images beforehand, you safe cpu resources later.
You also can place other colors or even another background instead of black.

mkdir -p wallpaper
ls * | while read ; do
info=$(identify "$REPLY" | awk '{ print $3 }' 2>/dev/null)
height=$( echo $info | cut -f2 -dx)
width=$( echo $info | cut -f1 -dx)
if [ $width -gt 1800 ] && [ $height -gt 900 ] ; then
	convert -resize 1920x1080  -gravity center  -background black -extent 1920x1080 "$REPLY" "wallpaper/$REPLY"
fi
done

Set a random wallpaper as background using cron.

#!/bin/bash
DISPLAY=":0.0"
XAUTHORITY="/home/henri/.Xauthority"
XDG_RUNTIME_DIR="/run/user/1000"

cd /home/henri/Pictures/
getranpic=$(ls  wallpaper/ |sort -R |tail -1)
#gsettings set org.gnome.desktop.background picture-options 'wallpaper'
#Set different modes ( enum 'none' 'wallpaper' 'centered' 'scaled' 'stretched' 'zoom' 'spanned' )
gsettings set org.gnome.desktop.background picture-uri-dark  "$(realpath wallpaper/$getranpic)"
logger "$(realpath $getranpic)" 

Cron example

* * * * * DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus /home/henri/bin/setrandom

Camera bags

I saw this article on Flipboard.

So true, we own several.

Am I happy with those? .. Well depends.

They all have their benefits. But I want the impossible.
One with all the benefits.
We choose the bag depending on the occasion, but for example a large bag is perfect for a far away vacation, sometimes we do daytrips which can be done with a smaller bag.
And I want an even smaller bag when going to the city to get something to eat when on holiday. Or the day trips to family or other cities in our country.

Also the means of transport matters.

Bike: Small one
Own car: Big bag and a small one
Plane: We have been all over the world, it depends on travel and transport in those countries.

I LOVE the ones with easy access. (Slingshot and mindshift)
Some of them have a way to take your tripod with you.

Sometimes we have to take two camera’s with us, so we don’t fight. (Vertex and Mindshift take two)

Lowepro Vertex 200 AW

Comes with a tripod holder, lots of pockets and easy adjustable. Plus it has a rain cover hidden in the bottom.

Hama

A real small bag. This one we use for day trips.
Holds camera plus a lens or our small binoculars.

Lowepro Slingshot Edge

This is another day trip bag. For when we need a little more room or take some food with us.
Love the sling concept, but not much used anymore.

Mindshift Gear Rotation 180 Horizon

I love this bag! We took this one with us to Peru and Bolivia.
Easy on the shoulders and back. I carried this one the whole day for several weeks.
The camera sling rests on your hips.

What we take with us in the big bags?

  • Filters: Polarisation/8x Stop filters + ring adaptors
  • My little screen magnifier
  • Many Sdcards
  • WD Passport for backup (see the New Zealand hack)
  • Multiple lenses
  • Cleaning material
  • Lens sunshades
  • Mini tripod
  • GPS tracker (To embed locations in photos)
  • Raincoat
  • Technochanter 🙂

A vacation in numbers and about taking pictures

Italy 2023

Pictures : 2633 mobile + 2425 dslr
Movies : 52

Highest point: 1214m (Vesuvius)
Lowest: -40m

Pizza’s eaten:
Too many ( sometimes 2 times a day), it was hard to get something else to eat besides Pizza and Pasta.


Oldest building : 500BC

Km walked: 220Km
Km driven: ? (calculating) Will update when i post something about unwritten traffic rules in Italy.

Types of transport: Plane, train, metro/subway, bus, scooter, bike, car, walking

Temperature high: 32
Temperature low: 16

About the photos .. it finally happened.
More mobile photos where taken than with our trusty Nikon!
(Read our New Zealand post, why trusty .. rain damage on both Mobile and Nikon D750)

Some data about longer trips since 2010

This has multiple reasons:

  • Coline took loads of mobile phone pictures.
    (I was mostly in charge of the Nikon)
    She is trigger happy ..
  • We didn’t take the big camera always with us at night, going for dinner.
  • Sometimes it was too hot for me to focus on taking good pictures.
  • I didn’t make panoramic and time-lapse photos.

Why still use dlsr?

  • Better sensors (larger image chip) Small image ICs give more cross noise due to the image pixelsensors being to close to each other)
    So more pixels does NOT equal better images!
  • More control over your settings.
  • Better lenses and faster. Better aperture equals better DOF!!
    (Depth of field)

Transform photos using gimp

Just back from my 3 week trip to Italy.
Made 5000-odd photos.
Using my posted scripts they are easily sorted.

But some are crooked, lets fix them.

Not a straight horizon:

Lets open this photo in Gimp

Easy to fix:

  • Open in Gimp
  • Go to measure tool
  • Orientation – auto and transform layer
  • Select the horizon on the left (do not release the mouse button) and draw to the right
  • Press straighten

Easy ..

Another fix below : Perspective

Sometimes you want to look straight at a picture, but when taking a picture there is something preventing this.

  • Other tourists won’t move away from a information sign, so you have to take the picture from an angle.
  • The image is far up a wall.
  • Or as in example below, the Roman mosaic is on the floor, no way to take a picture from above.

  • Open in gimp
  • Select from tools > Transform Tools
  • Handle transform or press SHIFT-L
  • Select a corner and drag, repeat until satisfied

Kodi push pictures/directory from website

For a new project i’m using parts of my Photo Manager.

UPDATE: Random photo push from directory in one script.

I will post the Minimal code for the following:

  • Caching thumbnail generation
  • Drag and drop image for displaying on a kodi instance
  • Button to start slideshow of a directory
  • Open image in browser with obfuscated image url (not shown in movie)
  • Stop image playing

Json RPC used:

# Playing a single file
curl -H "content-type:application/json" -i -X POST -d '{"jsonrpc":"2.0","id":1,"method":"Player.Open","params":{"item":{"file":"'.$dir2.'"}}}' http://KODI-IP:8080/jsonrpc &';

# Playing a directory
curl -H "content-type:application/json" -i -X POST -d '{"jsonrpc":"2.0","id":1,"method":"Player.Open","params":{"item":{"directory":"/path/'.$dir.'"}}}' http://KODI-IP:8080/jsonrpc &';

# Stop playing (i'm stopping player 1 and 2) You can query which player is active, this works also 
curl -H "content-type:application/json" -i -X POST -d '{"jsonrpc": "2.0", "method": "Player.Stop", "params": { "playerid": 1 }, "id": 1}' http://10.1.0.73:8080/jsonrpc';
Kodi enable http control and disable authentication (if you want to use authentication, change the curl commands accordingly)

Below the multiple PHP files, i’ve removed a lot of code specific for my manager.

By the way, I love this trick:

header("HTTP/1.1 204 NO CONTENT");

I’ve you put this in the top of your php script which is linked from the first page, you won’t open this link in your browser, but it gets executed nevertheless!

::::::::::::::
push.php
::::::::::::::
<!DOCTYPE html>
<html>
<head>
</head>
<body>

<div id="dropbox">Drop Image</div><br>
<a href="playpush.php?dir=TEMP/Sake">playdir</a> 
<a href="stoppush.php">stop</a> 

# Here i have a generated part to list my photoalbum photos in this format

<a href='getimg.php?imagepath=/mnt/fileserver/TEMP/1.jpg'><img src='getimg2.php?imagepath=/mnt/fileserver/TEMP/1.jpg' width=300 title='1.jpg'></a>
<a href='getimg.php?imagepath=/mnt/fileserver/TEMP/2.jpg'><img src='getimg2.php?imagepath=/mnt/fileserver/TEMP/2.jpg' width=300 title='2.jpg'></a>

<script
    type="text/javascript"
    src="javascript2.js"
    
  ></script>
</body></html>
::::::::::::::
getimg.php - Displays photo in browser (forgotten in movie)
::::::::::::::
<?php
Header("Content-Type: image/jpeg"); 
$file = $_GET['imagepath'];
$file = str_replace("%20", "\ ", $file);
$file = str_replace("(", "\(", $file);
$file = str_replace(")", "\)", $file);
$log =  'imggetlog';
file_put_contents($log, $file, FILE_APPEND);
file_put_contents($log, "\n\r", FILE_APPEND);
header('Content-Length: ' . filesize($file));
readfile($file);
?>

::::::::::::::
getimg2.php - makes a caching thumbnail 
/long/image/path/to/photo.jpg -> cachedir/longimagepathtophoto.jpg
::::::::::::::
<?php
Header("Content-Type: image/jpeg"); 
$file = $_GET['imagepath'];
$file = str_replace("%28", "\(", $file);
$file = str_replace("%29", "\)", $file);
$file = str_replace("%20", "\ ", $file);

$cachename = str_replace("/", "", $file);
$cachename = str_replace(" ", "", $cachename);
$cachename = "cachedir/$cachename";
$log =  'imggetlog';
file_put_contents($log, $file, FILE_APPEND);
file_put_contents($log, "\n\r", FILE_APPEND);
if (!file_exists("$cachename")) {

exec("convert -resize 300x300 \"$file\" \"$cachename\"");
}
header('Content-Length: ' . filesize("$cachename"));
readfile("$cachename");
?>

::::::::::::::
playpush.php - Pushes DIRECTORY play to Kodi
::::::::::::::
<?PHP
header("HTTP/1.1 204 NO CONTENT");

header("Cache-Control: no-cache, no-store, must-revalidate"); // HTTP 1.1.
header("Pragma: no-cache"); // HTTP 1.0.
header("Expires: 0"); // Proxies.

$dir=$_GET['dir'];

$command='nohup curl -H "content-type:application/json" -i -X POST -d \'{"jsonrpc":"2.0","id":1,"method":"Player.Open","params":{"item":{"directory":"/mnt/fileserver/'.$dir.'"}}}\' http://IPKODI:8080/jso
nrpc &';
exec($command, $output, $retval);
?>

::::::::::::::
stoppush.php - stops displaying
::::::::::::::
<?PHP
header("HTTP/1.1 204 NO CONTENT");

header("Cache-Control: no-cache, no-store, must-revalidate"); // HTTP 1.1.
header("Pragma: no-cache"); // HTTP 1.0.
header("Expires: 0"); // Proxies.

$command='curl -H "content-type:application/json" -i -X POST -d \'{"jsonrpc": "2.0", "method": "Player.Stop", "params": { "playerid": 1 }, "id": 1}\' http://IPKODI:8080/jsonrpc';
exec($command, $output, $retval);
$command='curl -H "content-type:application/json" -i -X POST -d \'{"jsonrpc": "2.0", "method": "Player.Stop", "params": { "playerid": 2 }, "id": 1}\' http://IPKODI:8080/jsonrpc';
exec($command, $output, $retval);
?>
::::::::::::::
javascript2.js
::::::::::::::
function getAllElementsWith(tag, attribute, value)
{
  var matchingElements = [];
  var allElements = document.getElementsByTagName(tag);
  for (var i = 0; i < allElements.length; i++)
  {
    if (value.indexOf(allElements[i].getAttribute(attribute)) != -1)
    {
      // Element exists with attribute. Add to array.
      matchingElements.push(allElements[i]);
    }
  }
  return matchingElements;
}

// onDrop
function onDrop(evt) {
    evt.stopPropagation();
    evt.preventDefault();
    var imageUrl = evt.dataTransfer.getData("URL");
    var links = getAllElementsWith("a", "href", imageUrl);
    var image;
     console.log(links, evt);
    
    if(links.length){
        image = links[0].getElementsByTagName("img");
        if(image.length)
            imageUrl = image[0].getAttribute("src");
        else
            imageUrl = "#no-image";
    }
    
///    alert(imageUrl);
var res = imageUrl.replace(/getimg/, "pushplay2");

location.href = (res);

};

// onDragOver
function onDragOver(evt){
    evt.preventDefault();
}

var dropbox = document.getElementById('dropbox');
dropbox.addEventListener('drop', onDrop);
dropbox.addEventListener("dragover", onDragOver, false);

Random picture push

file=$(find /mnt/fileserver/examples -type f  | shuf | head -1)
post_data="{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"Player.Open\",\"params\":{\"item\":{\"file\":\"$file\"}}}"
curl --user user:pass  -H "content-type:application/json" -i -X POST --data "${post_data}" http://KODI-IP:8080/jsonrpc

Below a example of what your can do with the code above

Quick previewing negatives using OBS

I’m using a camlink to connect a Nikon camera to my PC, but you could use your webcam also for this trick.

Now i can activate the full screen projector in OBS to preview and sort the negatives on a big screen. (right click on you preview screen)

When connecting a camera to OBS you initially have a “negative” image.

Below trick inverts your image, after that you can use your camera controls or OBS colour correction filter to adjust.

I’m using gimp to invert the LUT png image, but most image editors can invert an image.

A LUTs is a LookUp Table. Color presets/filters for adjusting the image.

Hardcore method .. command line

convert input.png -channel RGB -negate invert.png

DLSR Camera versus Mobile Phone

Not talking about the quality but how much we are using the camera’s.

Reason for taking pictures:

  • Capture memorable events – DLSR
  • Simple snapshots to remember stuff – Mobile
  • HQ photos – shoots etcetera – you want to use DOF, a mobile can´t do this
  • Images for web/mattermost/whatsapp – mobile phone is sufficient

But we always take our phone with us … sometimes we forget to bring the Nikon to memorable events.

A simple count of pictures on my fileserver.

# Below creates a CSV file
for f in $(seq 2000 2022) ; do echo -n $f, ; find  */$f -type f 2>/dev/null | wc -l  ;done 

Notes:

2010 – We bought a new nikon
2019 – Busy planning buying a new house
2020,2021 – Covid
< 2010 – Mobile pictures are potato quality

I had my first android phone in 2009.
Phones before 2010 didn´t have good exif information, so the picture count is a little off in the graph above.