Skip to content

Commit eb2bf51

Browse files
More preprocessing power to the scripts.
1 parent 4e07fa9 commit eb2bf51

File tree

5 files changed

+297
-31
lines changed

5 files changed

+297
-31
lines changed

dome1.lp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
0.129535 0.129535 0.983078
2+
-0.129535 0.129535 0.983078
3+
-0.129535 -0.129535 0.983078
4+
0.129535 -0.129535 0.983078
5+
0.332218 0.332218 0.882758
6+
0.000000 0.469828 0.882758
7+
-0.332218 0.332218 0.882758
8+
-0.469828 0.000000 0.882758
9+
-0.332218 -0.332218 0.882758
10+
-0.000000 -0.469828 0.882758
11+
0.332218 -0.332218 0.882758
12+
0.469828 -0.000000 0.882758
13+
0.502899 0.502899 0.702983
14+
0.272167 0.657069 0.702983
15+
0.000000 0.711207 0.702983
16+
-0.272167 0.657069 0.702983
17+
-0.502899 0.502899 0.702983
18+
-0.657069 0.272167 0.702983
19+
-0.711207 0.000000 0.702983
20+
-0.657069 -0.272167 0.702983
21+
-0.502899 -0.502899 0.702983
22+
-0.272167 -0.657069 0.702983
23+
-0.000000 -0.711207 0.702983
24+
0.272167 -0.657069 0.702983
25+
0.502899 -0.502899 0.702983
26+
0.657069 -0.272167 0.702983
27+
0.711207 -0.000000 0.702983
28+
0.657069 0.272167 0.702983
29+
0.633958 0.633958 0.442939
30+
0.343095 0.828306 0.442939
31+
0.000000 0.896552 0.442939
32+
-0.343095 0.828306 0.442939
33+
-0.633958 0.633958 0.442939
34+
-0.828306 0.343095 0.442939
35+
-0.896552 0.000000 0.442939
36+
-0.828306 -0.343095 0.442939
37+
-0.633958 -0.633958 0.442939
38+
-0.343095 -0.828306 0.442939
39+
-0.000000 -0.896552 0.442939
40+
0.343095 -0.828306 0.442939
41+
0.633958 -0.633958 0.442939
42+
0.828306 -0.343095 0.442939
43+
0.896552 -0.000000 0.442939
44+
0.828306 0.343095 0.442939
45+
0.696439 0.696439 0.173046
46+
0.376910 0.909942 0.173046
47+
0.000000 0.984914 0.173046
48+
-0.376910 0.909942 0.173046
49+
-0.696439 0.696439 0.173046
50+
-0.909942 0.376910 0.173046
51+
-0.984914 0.000000 0.173046
52+
-0.909942 -0.376910 0.173046
53+
-0.696439 -0.696439 0.173046
54+
-0.376910 -0.909942 0.173046
55+
-0.000000 -0.984914 0.173046
56+
0.376910 -0.909942 0.173046
57+
0.696439 -0.696439 0.173046
58+
0.909942 -0.376910 0.173046
59+
0.984914 -0.000000 0.173046
60+
0.909942 0.376910 0.173046

rti-builder/ptm-encoder.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -158,20 +158,19 @@ int main (int argc, char *argv[]) {
158158
fflush (stderr); */
159159

160160
char *path = malloc (strlen (dirname_lp) + strlen (filename) + 2);
161-
162161
sprintf (path, "%s/%s", dirname_lp, filename);
162+
163163
FILE *fp_jpeg;
164164
if ((fp_jpeg = fopen (path, "rb")) == NULL) {
165165
fprintf (stderr, "can't open %s\n", path);
166166
return 1;
167167
}
168-
free (filename);
169168
free (path);
170169

171170
decoder_t *decoder = malloc (sizeof (decoder_t));
172171
struct jpeg_decompress_struct *dinfo = &decoder->dinfo;
173172
decoder->fp = fp_jpeg;
174-
decoder->filename = strdup (filename);
173+
decoder->filename = filename;
175174
decoder->u = u;
176175
decoder->v = v;
177176
decoder->w = w;

scripts/image-converter.py

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
#!/usr/bin/python3
2+
# -*- encoding: utf-8 -*-
3+
4+
"""This script is a wrapper that can pass image files through a converter before
5+
calling the :ref:`ptm-encoder <ptm-encoder>`.
6+
7+
With the help of this script you may crop / resize / rotate your images before
8+
processing them with the ptm-encoder. Temporary files are created for the
9+
encoder, the original files are kept intact.
10+
11+
Write a shell script and :command:`chmod +x` it. The shell script must process
12+
the source image, apply all wanted transformations and save the destination
13+
image. The source image path and filename will be $1 and the destination path
14+
and filename will be $2. The destination will point to a temp directory.
15+
16+
An example of a shell script follows:
17+
18+
.. code-block:: shell
19+
20+
#!/bin/bash
21+
convert "$1" -crop 2800x2800+2236+1064 -resize 2000x2000 "$2"
22+
23+
An example of a command to build one PTM is then:
24+
25+
.. code-block:: console
26+
27+
scripts/image-converter.py -f runs/a/convert.sh \\
28+
bin/ptm-encoder -f PTM_FORMAT_JPEG_LRGB -o a.ptm runs/a/sample.lp
29+
30+
Alternatively you can do without the shell script and put the contents of the
31+
script in the command line. The placeholders "{source}" and "{dest}" will be
32+
replaced by the source and destination filenames.
33+
34+
The command to build one PTM is then:
35+
36+
.. code-block:: console
37+
38+
scripts/image-converter.py -e 'convert "{source}" -crop 2800x2800+2236+1064 -resize 2000x2000 "{dest}"' \\
39+
bin/ptm-encoder -f PTM_FORMAT_JPEG_LRGB -o a.ptm runs/a/sample.lp
40+
41+
"""
42+
43+
import argparse
44+
import datetime
45+
import math
46+
import itertools
47+
import operator
48+
import os
49+
import shlex
50+
import shutil
51+
import subprocess
52+
import sys
53+
import tempfile
54+
import textwrap
55+
56+
57+
58+
def build_parser ():
59+
parser = argparse.ArgumentParser (
60+
formatter_class=argparse.RawDescriptionHelpFormatter,
61+
description=textwrap.dedent (__doc__)
62+
)
63+
64+
parser.add_argument ('-v', '--verbose', dest='verbose', action='count',
65+
help='increase output verbosity', default=0)
66+
67+
group = parser.add_mutually_exclusive_group (required=True)
68+
group.add_argument ('-e', '--exec', metavar='"COMMANDLINE"', type=str,
69+
help='execute COMMANDLINE with every image')
70+
group.add_argument ('-f', '--file', metavar='SCRIPT-FILE', type=str,
71+
help='execute SCRIPT-FILE with every image')
72+
73+
parser.add_argument ('encoder', metavar="ENCODER",
74+
help='the PTM encoder executable')
75+
parser.add_argument ('encoder_args', nargs=argparse.REMAINDER, metavar="...",
76+
help='arguments to the PTM encoder')
77+
78+
return parser
79+
80+
81+
class light (object):
82+
def __init__ (self, s, source_dir, dest_dir):
83+
self.filename, x, y, z = s.split ()
84+
self.basename = os.path.basename (self.filename)
85+
self.source = os.path.join (source_dir, self.basename)
86+
self.dest = os.path.join (dest_dir, self.basename)
87+
self.x = float (x)
88+
self.y = float (y)
89+
self.z = float (z)
90+
91+
def __str__ (self):
92+
return "%s %f %f %f" % (self.basename, self.x, self.y, self.z)
93+
94+
95+
if __name__ == '__main__':
96+
97+
parser = build_parser ()
98+
args = parser.parse_args ()
99+
100+
lights_fn = args.encoder_args[-1]
101+
source_dir = os.path.dirname (lights_fn)
102+
dest_dir = tempfile.mkdtemp ()
103+
104+
if args.file:
105+
args.exec = "%s {source} {dest}" % args.file
106+
107+
lights = []
108+
with open (lights_fn, 'r') as fp_lights:
109+
for line in fp_lights:
110+
try:
111+
lights.append (light (line, source_dir, dest_dir))
112+
except ValueError:
113+
pass
114+
115+
lights_dest_fn = os.path.join (dest_dir, os.path.basename (lights_fn))
116+
117+
with open (lights_dest_fn, 'w') as fp_lights:
118+
fp_lights.write (str (len (lights)) + "\n")
119+
for light in lights:
120+
fp_lights.write (str (light) + "\n")
121+
122+
processes = []
123+
for light in lights:
124+
arg = shlex.split (args.exec.format (source=light.source, dest=light.dest))
125+
print (' '.join (arg))
126+
processes.append (subprocess.Popen (arg))
127+
128+
for process in processes:
129+
process.wait ()
130+
131+
args.encoder_args[-1] = lights_dest_fn
132+
133+
arg = [args.encoder] + shlex.split (' '.join (args.encoder_args))
134+
print (' '.join (arg))
135+
subprocess.call (arg)
136+
137+
shutil.rmtree (dest_dir)

scripts/image-filer.py

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
#!/usr/bin/python3
22
# -*- encoding: utf-8 -*-
33

4-
"""Group image runs and file them into subdirectories.
4+
"""Reads images from a camera's memory card or other flat directory structure,
5+
finds runs of images and files them into subdirectories. A run is found by the
6+
:term:`EXIF` timestamp in the image files.
57
6-
Reads images from a camera's memory card or other flat directory structure, and
7-
groups them into subdirectories. A group is found by the :term:`EXIF` timestamp
8-
in the image files. The script also builds a :file:`sample.lp` file in the
9-
directory that contains a :ref:`light position map <sample.lp>` for the
10-
:ref:`PTM encoder <ptm-encoder>`.
8+
The script also builds a full :ref:`light position map <sample.lp>`
9+
:file:`sample.lp` from a light position skeleton file and files it alongside the
10+
images files.
11+
12+
Some cameras put a maximum of 1000 pictures into a folder. After that they
13+
automatically open a new folder. If this happened during a shooting, include
14+
both directories on the commandline. The script will sort it out for you.
1115
1216
"""
1317

@@ -19,14 +23,11 @@
1923
import os
2024
import shutil
2125
import sys
26+
import textwrap
2227

2328
from PIL import Image
2429
from PIL.ExifTags import TAGS, GPSTAGS
2530

26-
DOME_DIAMETER = 490.0 - (2 * 13.0)
27-
RINGS = [ (4, 85.0), (8, 218.0), (16, 330.0), (16, 416.0), (16, 457.0) ]
28-
29-
twopi = 2.0 * math.pi
3031
thres = datetime.timedelta (seconds = 5)
3132

3233

@@ -50,12 +51,18 @@ def pairwise (iterable):
5051

5152

5253
def build_parser ():
53-
parser = argparse.ArgumentParser (description = __doc__)
54+
parser = argparse.ArgumentParser (
55+
formatter_class=argparse.RawDescriptionHelpFormatter,
56+
description=textwrap.dedent (__doc__)
57+
)
5458

55-
parser.add_argument('files', metavar='FILE', type=str, nargs='+',
56-
help='the image files to file (wildcards supported)')
5759
parser.add_argument ('-v', '--verbose', dest='verbose', action='count',
5860
help='increase output verbosity', default=0)
61+
parser.add_argument ('-l', '--lights', metavar='LP', type=str, default='skeleton.lp',
62+
help='the skeleton light positions file (default: skeleton.lp)')
63+
64+
parser.add_argument ('files', metavar='FILES', type=str, nargs='+',
65+
help='the image files to file (wildcards supported)')
5966
return parser
6067

6168

@@ -64,6 +71,14 @@ def build_parser ():
6471
parser = build_parser ()
6572
args = parser.parse_args ()
6673

74+
# read lights file
75+
lights = []
76+
with open (args.lights, 'r') as fp_lights:
77+
for line in fp_lights:
78+
x, y, z = line.split ()
79+
lights.append ( (float (x), float (y), float (z)) )
80+
81+
# get timestamps from images
6782
files = [ (fn, get_datetime (fn)) for fn in args.files ]
6883
files.sort (key = operator.itemgetter (1)) # sort by time
6984

@@ -78,25 +93,28 @@ def build_parser ():
7893
last_group.append (pair[0])
7994

8095
for files in grouped_files:
81-
i = 0
8296
run = 'runs/' + files[0][1].strftime ('%Y-%m-%d-%H-%M-%S')
8397
os.makedirs (run, exist_ok = True)
8498

99+
if len (files) < len (lights):
100+
print ("error: not enough files in %s\n" % run)
101+
break
102+
if len (files) > len (lights):
103+
print ("error: too many files in %s\n" % run)
104+
break
105+
85106
if args.verbose:
86-
print ("filing into %s\n" % run)
107+
print ("filing into %s" % run)
87108

88109
with open ("%s/sample.lp" % run, 'w') as fp:
89-
fp.write ("# run of %s\n" % files[0][1].isoformat ())
90110
fp.write ("%d\n" % len (files))
91-
for num_leds, diameter in RINGS:
92-
phi = 1.0 / 8.0 * twopi # start each ring at 45°
93-
step_phi = -twopi / num_leds
94-
dia = diameter / DOME_DIAMETER
95-
z = math.sqrt (1 - dia ** 2)
96-
97-
for n in range (0, num_leds):
98-
filename = files[i][0]
99-
shutil.copy2 (filename, run)
100-
fp.write ("%s %f %f %f\n" % (os.path.basename (filename), dia * math.sin (phi), dia * math.cos (phi), z))
101-
phi += step_phi
102-
i += 1
111+
for l, f in zip (lights, files):
112+
filename = f[0]
113+
x, y, z = l
114+
shutil.copy2 (filename, run)
115+
fp.write ("%s %f %f %f\n" % (os.path.basename (filename), x, y, z))
116+
if args.verbose:
117+
print (".", end = '')
118+
119+
if args.verbose:
120+
print ("")

scripts/lp-builder.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#!/usr/bin/python3
2+
# -*- encoding: utf-8 -*-
3+
4+
"""Build the light position file for Dome 1.
5+
6+
Outputs to stdout a skeleton sample.lp file with light positions according to
7+
the Ø 50cm prototype dome at CCeH.
8+
9+
This script is hard-coded to one specific dome but it may serve as example for
10+
writing a more general script for other domes.
11+
12+
"""
13+
14+
import argparse
15+
import math
16+
import sys
17+
18+
DOME_DIAMETER = 490.0 - (2 * 13.0)
19+
RINGS = [ (4, 85.0), (8, 218.0), (16, 330.0), (16, 416.0), (16, 457.0) ]
20+
21+
twopi = 2.0 * math.pi
22+
23+
def build_parser ():
24+
parser = argparse.ArgumentParser (description = __doc__)
25+
26+
parser.add_argument ('-a', '--angle', metavar='ANGLE', type=float, default=0.0,
27+
help='the rotation angle of the camera on the Dome (default 0°)')
28+
parser.add_argument ('-v', '--verbose', dest='verbose', action='count',
29+
help='increase output verbosity', default=0)
30+
return parser
31+
32+
33+
if __name__ == '__main__':
34+
35+
parser = build_parser ()
36+
args = parser.parse_args ()
37+
38+
start_phi = twopi * 45.0 / 360.0 # start each ring at 45°
39+
user_phi = twopi * args.angle / 360.0 # rotated camera
40+
41+
# num_leds = sum ([x[0] for x in RINGS])
42+
# sys.stdout.write ("%d\n" % num_leds)
43+
44+
for num_leds, diameter in RINGS:
45+
phi = start_phi + user_phi
46+
step_phi = -twopi / num_leds
47+
dia = diameter / DOME_DIAMETER
48+
z = math.sqrt (1 - dia ** 2)
49+
50+
for n in range (0, num_leds):
51+
sys.stdout.write ("%f %f %f\n" % (dia * math.sin (phi), dia * math.cos (phi), z))
52+
phi += step_phi

0 commit comments

Comments
 (0)