Camera Geometry

Warning

TODO doc

To inspect the results of a pinhole camera calibration, viren2d provides the following utilities:

Pinhole camera visualizations

Corresponding Python example code:

 1def _calibrated_example():
 2    """Example image (`ninja`) and its calibration (estimated via PnP)."""
 3    img = viren2d.load_image_uint8(VIREN2D_DATA_PATH / 'ninja.jpg')
 4    K = np.array(
 5        [[523.17808219,   0.0,        341.0],
 6         [  0.0,        523.17808219, 256.0],
 7         [  0.0,          0.0,          1.0]], dtype=np.float64)
 8    R = np.array(
 9        [[ 0.99013141,  0.14006482, -0.00465153],
10         [ 0.05439048, -0.41465762, -0.90835056],
11         [-0.12915675,  0.89913342, -0.41818372]], dtype=np.float64)
12    t = np.array([-51.84341161, 17.32680283, 82.51435241], dtype=np.float64)
13    return img, K, R, t
14
15
16def _overlay_axes(painter, K, R, t):
17    """Draws the coordinate system axes."""
18    arrow_style = viren2d.ArrowStyle(
19        width=7, tip_length=35, tip_angle=25)
20    # Instead of (0, 0, 0), we draw the axis origin at (12, 12, 0) to avoid
21    # clipping the z-axis.
22    # The size of a checkerboard grid cell is 24x24 millimeters - the length
23    # of each axis will be 2 grid cells.
24    painter.draw_xyz_axes(
25        K=K, R=R, t=t, origin=(12, 12, 0),
26        lengths=(48, 48, 48), arrow_style=arrow_style)
27
28
29def _overlay_horizon(painter, K, R, t):
30    """Draws the approximated line of horizon."""
31    line_style = viren2d.LineStyle(
32        width=7, color=viren2d.axis_color('z'), dash_pattern=[40, 50],
33        cap='round')
34    horizon = painter.draw_horizon_line(K=K, R=R, t=t, line_style=line_style)
35    if horizon.is_valid():
36        # Add a label
37        text_style = viren2d.TextStyle(family='xkcd', size=29, color='#1a1c1d')
38        line_style.width = 3
39        line_style.dash_pattern = []
40        painter.draw_text_box(
41            ['Line of Horizon'],
42            position=horizon.point_at_offset(0.8) + (0, 10),
43            anchor='top', text_style=text_style, padding=(10, 6),
44            line_style=line_style, fill_color='#c0bab1c0')
45
46
47def demo_pinhole():
48    """Visualizations for calibrated pinhole cameras"""
49    img, K, R, t = _calibrated_example()
50    painter1 = viren2d.Painter(img)
51
52    # Visualize origin/world reference frame:  #TODO WIP - needs 3d line clipping
53    _overlay_axes(painter1, K, R, t)
54
55    # Visualize line of horizon
56    _overlay_horizon(painter1, K, R, t)
57
58    # TODO Visualize ground plane
59
60    # Create the collage:
61    canvas_width = 600
62    canvas_height = 255
63    padding = 5
64    scale = (canvas_width / 2 - 2 * padding) / img.shape[1]
65    painter_comb = viren2d.Painter(
66        canvas_height, canvas_width, 'white!0')
67    
68    text_style = viren2d.TextStyle(family='xkcd', size=21, color='#c0bab1')
69    line_style = viren2d.LineStyle(width=2, color=text_style.color)
70    bg_color = '#1a1c1dc8'
71    
72    painter_comb.draw_image(
73        painter1.canvas,  position=(padding, padding), anchor='top-left',
74        scale_x=scale, scale_y=scale, clip_factor=0.1)
75    painter_comb.draw_text_box(
76        ['Axes & Horizon (TBD)'],  # TODO update text once finished
77        position=(canvas_width / 4, canvas_height - 2 * padding),
78        anchor='bottom', fill_color=bg_color, text_style=text_style,
79        line_style=line_style, padding=(10, 6))
80
81    # TODO Replace by ground plane visualization
82    dimmed = (0.2 * np.array(img)).astype(np.uint8)
83    painter_comb.draw_image(
84        dimmed,  position=(canvas_width - padding, padding),
85        anchor='top-right', scale_x=scale, scale_y=scale, clip_factor=0.1)
86    painter_comb.draw_text_box(
87        ['Ground plane (TBD)'],  # TODO update text once finished
88        position=(3 * canvas_width / 4, canvas_height - 2 * padding),
89        anchor='bottom', fill_color=bg_color, text_style=text_style,
90        line_style=line_style, padding=(10, 6))
91
92    return np.array(painter_comb.canvas, copy=True)