示例#1
0
def demo_overlay():
    """How to overlay images and highlight regions."""
    # Overlay
    rgb = imutils.imread('../data/flamingo.jpg', mode='L')
    # Generate some data to overlay
    im_height, im_width = rgb.shape[0], rgb.shape[1]
    peak_pos = (im_width * 0.75, im_height * 0.15)
    xv, yv = np.meshgrid(np.arange(0, im_width), np.arange(0, im_height))
    overlay = np.exp(
        -(np.power(xv - peak_pos[0], 2) + np.power(yv - peak_pos[1], 2)) /
        (3e4))
    overlay_vis = imvis.overlay(imvis.pseudocolor(overlay), rgb, 0.7)

    # Highlight regions
    rgb = imutils.imread('../data/flamingo.jpg', mode='RGB')
    rgb_mask = np.zeros((rgb.shape[0], rgb.shape[1]), dtype=np.uint8)
    rgb_mask[160:334, 120:290] = 1
    highlight = imvis.highlight(rgb, rgb_mask)
    # highlight another region, this time in blue
    rgb_mask[:] = 0
    rgb_mask[200:374, 250:420] = 1
    highlight = imvis.highlight(highlight, rgb_mask, color=(0, 0, 255))

    # Combine all "colored" images:
    collage = imvis.make_collage([overlay_vis, highlight],
                                 padding=5,
                                 bg_color=(255, 255, 255))
    imvis.imshow(collage, title="Overlay & Highlights", wait_ms=-1)
示例#2
0
def demo_primitives():
    """How to draw basic shapes, text boxes, etc."""
    # * rotated rect around dot, maybe
    img = imutils.imread('../data/ninja.jpg',
                         mode='RGB')  # Load grayscale as 3-channel image
    # Draw rounded box(es)
    vis_img = imvis.draw_rounded_rects(img, [(9, 23, 149, 106)],
                                       corner_percentage=0.2,
                                       fill_opacity=0.75,
                                       line_width=0,
                                       color=(0, 200, 200),
                                       non_overlapping=True)
    # Draw filled & dashed rect
    # vis_img = imvis.draw_rects(vis_img, [(178, 164, 43, 29)], fill_opacity=0.4, line_width=2, dash_length=10, color=(220, 0, 255))

    # Draw rotated rectangle
    vis_img = imvis.draw_rotated_rects(vis_img, [(60, 220, 70, 45, -55)],
                                       fill_opacity=0.5,
                                       line_width=2,
                                       dash_length=15,
                                       color=(0, 200, 0))

    # Draw lines - a line is a list or tuple: ((start-point), (end-point), is_dashed, color)
    lines = [
        [(7, 184), (329, 211), True, (255, 0, 255)],  # Dashed
        [(42, 147), (337, 168), False, (255, 0, 255)]
    ]  # Solid
    vis_img = imvis.draw_lines(vis_img,
                               lines,
                               line_width=3,
                               default_color=(200, 255, 0),
                               dash_length=15)

    # Draw arrows - same format as lines (see above)
    arrows = [[(314, 20), (175, 38), False, (0, 255, 255)],
              ((314 + 20, 20 + 30), (175 + 20, 38 + 30), True, (255, 0, 255))]
    #[(320, 33), (316, 87), True, (0, 255, 255)]]
    vis_img = imvis.draw_arrows(vis_img,
                                arrows,
                                line_width=2,
                                default_color=(0, 200, 255),
                                dash_length=15,
                                arrow_head_factor=0.1)

    # Draw text box
    vis_img = imvis.draw_text_box(vis_img,
                                  'Angry', (283, 68),
                                  text_anchor='west',
                                  bg_color=(255, 0, 255),
                                  font_color=(-1, -1, -1),
                                  font_scale=1.0,
                                  font_thickness=1,
                                  padding=5,
                                  fill_opacity=0.8)

    imvis.imshow(vis_img, title='Drawing Primitives', wait_ms=10)
示例#3
0
def demo_pseudocolor():
    """Pseudocoloring."""
    peaks = imutils.imread('../data/peaks.png', mode='L')
    # For visualization purposes only, reduce input to a few
    # distinct categories/labels:
    data = ((peaks / 25) - 5).astype(np.int16)
    names = ['Bone', 'Magma', 'Viridis']
    images = list()
    for name in names:
        pc = imvis.pseudocolor(
            data,
            limits=None,  # Compute min/max from data
            color_map=colormaps.by_name(name, return_rgb=True))
        images.append(pc)

    # Display as a single collage
    padding = 10
    # Add alpha channel to render the collage nicely for the repo's README
    images[0] = np.dstack(
        (images[0], 255 * np.ones(images[0].shape[:2], dtype=np.uint8)))
    collage = imvis.make_collage(images,
                                 padding=padding,
                                 fixed_size_per_image=(200, 200),
                                 bg_color=(0, 0, 0, 0),
                                 num_images_per_row=len(images))

    # Add labels
    height, width = collage.shape[:2]
    mask_width = (width - (len(names) - 1) * padding) / len(names)
    for i in range(len(names)):
        pos = (i * (mask_width + padding) + mask_width / 2, height - 10)
        collage = imvis.draw_text_box(collage,
                                      names[i],
                                      pos,
                                      text_anchor='south',
                                      bg_color=(0, 0, 0),
                                      font_color=(-1, -1, -1),
                                      font_scale=1.0,
                                      font_thickness=1,
                                      padding=5,
                                      fill_opacity=0.8)

    imvis.imshow(collage, title='Pseudocoloring', wait_ms=-1)
    imutils.imsave('../../doc/example-pseudocolor.png', collage)
示例#4
0
    def _process_next_frameset(self, capture, frameset):
        # assert len(frameset) == 1  # Currently, we assume there's only one mobotix camera connected!
        if frameset[0] is None:
            self._streamer.stop()
            return

        if self._args.verbose:
            # Measure time between received framesets
            if self._mean_ms_between_framesets is None:
                ms_between_framesets = 0
            else:
                ms_between_framesets = pyutils.ttoc('[frameset received]')
            self._mean_ms_between_framesets = ms_between_framesets if self._mean_ms_between_framesets is None else 0.9 * self._mean_ms_between_framesets + 0.1 * ms_between_framesets
            if ms_between_framesets > 0:
                print(
                    'Frameset received after {:.2f} ms, avg. framerate {:.1f}'.
                    format(ms_between_framesets,
                           1000.0 / self._mean_ms_between_framesets))
            pyutils.tic('[frameset received]')

        vis_frames = list()
        vis_labels = list()
        for idx, frame in enumerate(frameset):
            frame_lbl = capture.frame_label(idx)
            vis_frame = imvis.pseudocolor(frame, [0, 5000], color_map=colormaps.colormap_turbo_rgb)\
                if capture.is_depth(idx) or capture.is_infrared(idx) else frame
            vis_frames.append(vis_frame)
            vis_labels.append(frame_lbl)

        # Overlay labels
        vis_frames = [
            imvis.draw_text_box(vis_frames[idx],
                                vis_labels[idx],
                                (vis_frames[idx].shape[1] // 2, 40),
                                text_anchor='north',
                                bg_color=(220, 0, 0),
                                font_color=(0, 0, 0))
            for idx in range(len(vis_frames))
        ]

        # Forward to storage processes
        self._store(capture, frameset)

        # Display the live stream
        collage = imvis.make_collage(vis_frames,
                                     num_images_per_row=2,
                                     padding=0,
                                     fixed_size_per_image=(640, 480))
        k = imvis.imshow(collage, "Live view", wait_ms=10)
        if k == ord('q') or k == 27:
            self._streamer.stop()
示例#5
0
def show_off_boxes3d():
    # 3D bounding box animations (to show clipping, visibility tests, etc.)
    box3da = ([(-3, 5, 2.5), (-1.5, 5, 2.5), (-1.5, 3, 2.5),
               np.array((-3, 3, 2.5)), (-3, 5, 0), (-1.5, 5, 0), (-1.5, 3, 0),
               (-3, 3, 0)], (255, 0, 0), "A box")  # Must be a tuple!!!

    box3db = ([(-2, -2, -0.5), (-2, 2, -0.5), (0.1, 2, -0.5), (0.1, -2, -0.5),
               (-2, -2, -1.5), (-2, 2, -1.5), (0.1, 2, -1.5), (0.1, -2, -1.5)],
              (0, 255, 0), "A better box")  # Must be a tuple!!!

    box3dc = ([[-0.5, -0.5, 1], [-0.5, 0.5, 1], [0.5, 0.5, 1], [0.5, -0.5, 1],
               [-0.5, -0.5, 0], [-0.5, 0.5, 0],
               np.array([0.5, 0.5, 0]),
               np.array([0.5, -0.5, 0])], (0, 255, 255), "Tilted occluder")
    box3dc = shift_bbox3d(rotate_bbox3d_center(box3dc, 45, 0, 10), 0, 0.5, 0)

    # Dummy camera parameters:
    R = np.array([[1.0, 0.0, 0.0], [0.0, 0.0, -1.0], [0.0, 1.0, 0.0]],
                 dtype=np.float64)
    C = np.array([0, -1, 1], dtype=np.float64).reshape((3, 1))
    t = -np.dot(R, C)
    K = np.array([[300, 0, 512], [0, 300, 384], [0, 0, 1]], dtype=np.float64)

    # Show off (1)
    for angle in range(0, 90, 2):
        vis_img = np.zeros((768, 1024, 3), dtype=np.uint8)
        vis_img = imvis.draw_bboxes3d(
            vis_img,
            [box3da, rotate_bbox3d(box3db, 0, 0, angle), box3dc],
            K,
            R,
            t,
            line_width=3,
            text_anchor='center',
            non_overlapping=True)
        vis_img = imvis.draw_text_box(vis_img,
                                      'Press ESC to cancel', (512, 5),
                                      text_anchor='north')
        k = imvis.imshow(
            vis_img, title="3d bbox (non-overlapping)", wait_ms=100) & 0xFF
        if k == 27:
            return

    # Show off (2)
    for angle in range(0, 360, 2):
        vis_img = np.zeros((768, 1024, 3), dtype=np.uint8)
        vis_img = imvis.draw_bboxes3d(
            vis_img, [rotate_bbox3d_center(box3da, angle, 0, 0)],
            K,
            R,
            t,
            line_width=3,
            dash_length=-1,
            text_anchor='southeast')
        vis_img = imvis.draw_text_box(vis_img,
                                      'Press ESC to cancel', (512, 5),
                                      text_anchor='north')
        k = imvis.imshow(vis_img, title="3d bbox", wait_ms=10) & 0xFF
        if k == 27:
            return

    # Show off (3)
    for angle in range(0, 360, 2):
        vis_img = np.zeros((768, 1024, 3), dtype=np.uint8)
        vis_img = imvis.draw_bboxes3d(
            vis_img, [rotate_bbox3d_center(box3da, 0, angle, 0)],
            K,
            R,
            t,
            line_width=3)
        vis_img = imvis.draw_text_box(vis_img,
                                      'Press ESC to cancel', (512, 5),
                                      text_anchor='north')
        k = imvis.imshow(vis_img, title="3d bbox", wait_ms=10) & 0xFF
        if k == 27:
            return

    # Show off (4)
    for angle in range(0, 360, 2):
        vis_img = np.zeros((768, 1024, 3), dtype=np.uint8)
        vis_img = imvis.draw_bboxes3d(
            vis_img, [rotate_bbox3d_center(box3da, 0, 0, angle)],
            K,
            R,
            t,
            line_width=3)
        vis_img = imvis.draw_text_box(vis_img,
                                      'Press ESC to cancel', (512, 5),
                                      text_anchor='north')
        k = imvis.imshow(vis_img, title="3d bbox", wait_ms=10) & 0xFF
        if k == 27:
            return

    # Show off (5)
    for shift in range(0, -48, -1):
        vis_img = np.zeros((768, 1024, 3), dtype=np.uint8)
        vis_img = imvis.draw_bboxes3d(vis_img, [
            shift_bbox3d(rotate_bbox3d(box3da, 0, 0, 10), 1.9, shift / 10.0, 0)
        ],
                                      K,
                                      R,
                                      t,
                                      line_width=3)
        vis_img = imvis.draw_text_box(vis_img,
                                      'Press ESC to cancel', (512, 5),
                                      text_anchor='north')
        k = imvis.imshow(vis_img, title="3d bbox", wait_ms=50) & 0xFF
        if k == 27:
            return

    # Show off (6)
    box = rotate_bbox3d_center(box3da, 90, 0, 0)
    for shift in range(0, -54, -1):
        vis_img = np.zeros((768, 1024, 3), dtype=np.uint8)
        vis_img = imvis.draw_bboxes3d(
            vis_img, [shift_bbox3d(box, 1.5, shift / 10.0, 0)],
            K,
            R,
            t,
            line_width=3)
        vis_img = imvis.draw_text_box(vis_img,
                                      'Press ESC to cancel', (512, 5),
                                      text_anchor='north')
        k = imvis.imshow(vis_img, title="3d bbox", wait_ms=50) & 0xFF
        if k == 27:
            return

    # Show off (7)
    box = rotate_bbox3d_center(box3da, 40, 0, 20)
    for shift in range(0, -60, -1):
        vis_img = np.zeros((768, 1024, 3), dtype=np.uint8)
        vis_img = imvis.draw_bboxes3d(
            vis_img, [shift_bbox3d(box, 1.5, shift / 10.0, 0)],
            K,
            R,
            t,
            line_width=3)
        vis_img = imvis.draw_text_box(vis_img,
                                      'Press ESC to cancel', (512, 5),
                                      text_anchor='north')
        k = imvis.imshow(vis_img, title="3d bbox", wait_ms=50) & 0xFF
        if k == 27:
            return

    # Show off (8)
    for shift in range(0, -63, -1):
        vis_img = np.zeros((768, 1024, 3), dtype=np.uint8)
        vis_img = imvis.draw_bboxes3d(vis_img, [
            shift_bbox3d(rotate_bbox3d_center(box3db, 10, 10, -20), 1,
                         4 + shift / 10.0, 1.5)
        ],
                                      K,
                                      R,
                                      t,
                                      line_width=3)
        vis_img = imvis.draw_text_box(vis_img,
                                      'Press ESC to cancel', (512, 5),
                                      text_anchor='north')
        k = imvis.imshow(vis_img, title="3d bbox", wait_ms=50) & 0xFF
        if k == 27:
            return
示例#6
0
    mask_width = (width - padding) / 2
    for i in range(len(names)):
        pos = ((i % 2) * (mask_width + padding) + mask_width / 2,
               (i // 2) * (225 + padding) + (225 - 10))
        collage = imvis.draw_text_box(collage,
                                      names[i],
                                      pos,
                                      text_anchor='south',
                                      bg_color=(0, 0, 0),
                                      font_color=(-1, -1, -1),
                                      font_scale=1.0,
                                      font_thickness=1,
                                      padding=5,
                                      fill_opacity=0.8)

    imvis.imshow(collage, title='Basic Drawing', wait_ms=-1)
    imutils.imsave('../../doc/example-imvis.png', collage)

    # ############################################################################
    # Drawing basic shapes/primitives
    demo_primitives()

    # ############################################################################
    # Pseudocolorization
    demo_pseudocolor()

    # ############################################################################
    # Overlay images and highlight regions
    demo_overlay()

    # ############################################################################
示例#7
0
    center = (im_width / 2.0, im_height / 2.0)
    rect = (im_width * 3 / 4, im_height / 2, 50, 80)
    vis_img = imvis.draw_rects(rgb, [rect],
                               fill_opacity=0.4,
                               line_width=2,
                               dash_length=10,
                               color=(220, 0, 255))

    rotrect = imutils.rotate_rect(rect, center, np.deg2rad(5))
    vis_img = imvis.draw_rotated_rects(vis_img, [rotrect],
                                       fill_opacity=0.4,
                                       line_width=2,
                                       dash_length=10,
                                       color=(220, 0, 0))

    imvis.imshow(vis_img, title="rotated rect", wait_ms=200)

    #TODO make testable
    ## Find the convex hull of this polyline
    # First, scale it to the target image size
    target_sz = (1024, 768)
    xmin, xmax = np.min(x), np.max(x)
    ymin, ymax = np.min(y), np.max(y)
    padding = 20
    scale_x = (target_sz[0] - 2 * padding) / (xmax - xmin)
    scale_y = (target_sz[1] - 2 * padding) / (ymax - ymin)
    # Subsample the polyline to get some points for convex hull computation
    polygon = [((p[0] - xmin) * scale_x + padding,
                target_sz[1] - ((p[1] - ymin) * scale_y + padding))
               for p in [polyline[sub] for sub in range(0, len(polyline), 5)]]
示例#8
0
def demo_align():
    cfg_base_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),
                                 '..', 'data', 'data-best')
    cfg_file = os.path.join(cfg_base_path, 'k4a-manual-alignment.cfg')

    streamer = best.MulticamStepper(cfg_file,
                                    True,
                                    cfg_file_rel_path_base_dir=cfg_base_path,
                                    verbose=True)
    capture = streamer.start()

    _, frameset = streamer.next_frameset()

    K_color = capture.intrinsics(0)
    K_depth = capture.intrinsics(1)
    Rt_stereo = capture.stereo_transformation(1)
    D_color = capture.distortion_coefficients(0)
    D_depth = capture.distortion_coefficients(1)

    alignment = None
    num_frames_processed = 1
    while streamer.is_available():
        capture, frameset = streamer.next_frameset()
        if frameset is None:
            print('Invalid frameset received, terminating now!')
            break
        color, depth, infrared = frameset

        if alignment is None:
            alignment = best.RgbdAlignment(K_color, K_depth, Rt_stereo[0],
                                           Rt_stereo[1], img_resolution(color),
                                           img_resolution(depth), D_color,
                                           D_depth)
        # pyutils.tic('cpp-align')
        # aligned_depth_cpp = alignment.align_d2c(depth)
        # pyutils.toc('cpp-align')

        pyutils.tic('cpp-align-di')
        aligned_depth_cpp, aligned_ir_cpp = alignment.align_di2c(
            depth, infrared)
        pyutils.toc('cpp-align-di')

        vis_frames = [color, vis_depth(depth), vis_infrared(infrared)]
        vis_labels = ['RGB', 'Depth (original)', 'IR (original)']

        ## The cpp version takes care of properly interpolating depth values during alignment
        # takes about 3-5ms per 640x480 depth
        # Additionally aligning the intensity image adds another 0.8-1ms to the cpp processing time
        ## The python version is a naive reprojection + binning (without depth ordering, filtering, interpolation, etc.)
        # takes about 20-30 ms (~4-5 times slower than cpp)
        # pyutils.tic('py-align')
        # aligned_depth_py = align_depth_to_color(depth, K_color, K_depth, Rt_stereo, color.shape[1], color.shape[0])
        # pyutils.toc('py-align')

        aligned_depth = aligned_depth_cpp
        vis_aligned_depth = vis_depth(aligned_depth)
        vis_frames.append(vis_aligned_depth)
        vis_labels.append('Aligned Depth')

        aligned_ir = aligned_ir_cpp
        vis_aligned_ir = vis_infrared(aligned_ir)
        # vis_frames.append(vis_aligned_ir)
        # vis_labels.append('Aligned IR')

        # color_resized = cv2.resize(color, (aligned_depth.shape[1], aligned_depth.shape[0]))
        # vis_frames.append(color_resized)
        # vis_labels.append('color resized')

        # vis_frames.append(imvis.overlay(vis_aligned_depth, color_resized, 0.7))#, aligned_depth > 0))
        vis_frames.append(imvis.overlay(vis_aligned_depth, color, 0.7))
        vis_labels.append('RGB+D')

        vis_frames.append(imvis.overlay(vis_aligned_ir, color, 0.7))
        vis_labels.append('RGB+IR')

        # Visualization (rescale, overlay a label, show a single collage)
        bg_color = (180, 180, 180)
        vis_frames = [
            imutils.aspect_aware_resize(f, (640, 480),
                                        padding_value=bg_color)[0]
            for f in vis_frames
        ]
        vis_frames = overlay_labels(vis_frames, vis_labels)

        img_per_row = len(vis_frames) // 2
        img_per_row = img_per_row if len(
            vis_frames) % 2 == 0 else img_per_row + 1
        collage = imvis.make_collage(vis_frames,
                                     bg_color=bg_color,
                                     num_images_per_row=img_per_row)
        k = imvis.imshow(collage, title='Stream', wait_ms=20)
        if k == ord('q') or k == 27:
            break

        num_frames_processed += 1
示例#9
0
    def _cb_next_frameset(self, capture, frameset):
        if any([f is None for f in frameset]):
            mp.get_logger().warning('[Demo] Skipping invalid frameset')
            return

        # Colorize depth/infrared images for visualization
        def _col_rgb(f):
            return f  #imutils.transform(f, 'histeq')

        def _col_depth(f):
            # return imutils.transform(f, 'depth2surfnorm', 'surfnorm2rgb')
            return imvis.pseudocolor(f,
                                     limits=[0, self._args.max_depth],
                                     color_map=colormaps.colormap_turbo_rgb)

        def _col_ir(f):
            #TODO
            # Normalize/stretch, etc. using: self._args.max_ir
            if f.dtype == np.uint8:
                return f
            return imvis.pseudocolor(f,
                                     limits=None,
                                     color_map=colormaps.colormap_turbo_rgb)

        vis_frames = [
            _col_depth(frameset[idx]) if capture.is_depth(idx) else
            (_col_ir(frameset[idx])
             if capture.is_infrared(idx) else _col_rgb(frameset[idx]))
            for idx in range(len(frameset))
        ]
        # Resize
        vis_frames = [
            imutils.fuzzy_resize(f, self._args.scale) for f in vis_frames
        ]
        # Overlay frame labels
        if self._args.label_overlay:
            vis_frames = [
                imvis.draw_text_box(vis_frames[idx],
                                    capture.frame_label(idx) +
                                    (' [Undist. & Rect.]'
                                     if capture.is_rectified(idx) else ''),
                                    (vis_frames[idx].shape[1] // 2, 10),
                                    'north',
                                    bg_color=(0, 0, 0),
                                    font_color=(-1, -1, -1),
                                    font_scale=1.0,
                                    font_thickness=1,
                                    padding=5,
                                    fill_opacity=0.5)
                for idx in range(len(vis_frames))
            ]
        # Show collage
        collage = imvis.make_collage(
            vis_frames, num_images_per_row=self._args.images_per_row)
        k = imvis.imshow(collage, title='Live Stream', wait_ms=10)
        # Handle user input (if any)
        if k == 27 or k == ord('q'):
            self._streamer.stop()
        elif k == ord('s') or k == 85 or k == 86 or k == 10:
            # 85, 86, 10: PgUp, PgDown, Enter
            if self._storage is not None:
                for idx in range(len(frameset)):
                    self._storage[capture.frame_label(
                        idx)].put_storage_request(frameset[idx])
            mp.get_logger().info('[Demo] Current frameset has been saved.')
示例#10
0
            (530, img.shape[0]-10),
            text_anchor='south', bg_color=(0, 0, 0),
            font_color=(-1, -1, -1), font_scale=1.0,
            font_thickness=1, padding=5, fill_opacity=0.8)


if __name__ == "__main__":
    # RGBA, transparent image
    vis_img = np.zeros((256, 600, 4))
    vis_img = demo_intersect(vis_img)

    vis_img = demo_tangents(vis_img)

    vis_img = demo_convhull(vis_img)

    imvis.imshow(vis_img, title='Geometry Utilities', wait_ms=-1)
    imutils.imsave('../../doc/example-geometry.png', vis_img)
    # # #TODO remove this
    # # print(math2d.circle_from_three_points((0,0), (0,0), (10, 20)))

    # # # Plane from 3 points
    # # plane = cmath.plane_from_three_points((10,234,0), (13,-23,-16), (234.2,37,999))
    # # print(plane)

    # # # Collinear - should be all 0, and a warning issued
    # # plane = cmath.plane_from_three_points((-7,3,0), (3,3,10), (5,3,12))
    # # print(plane)

    # # # Compute distances:
    # # plane = cmath.plane_from_three_points((-1,-2,2), (-1,2,2), (1,0,1))
    # # print(plane)
示例#11
0
def demo(pseudocolor=True, inspect=False):
    imgs = [imutils.imread('../data/ninja-01.jpg'), imutils.imread('../data/ninja-02.jpg')]

    bgmodels = list()
    bgmodel = bgm.BackgroundModel()
    bgmodel.approximate_median_bgm(
        adaptation_step=5,
        fg_report_threshold=50,
        median_on_grayscale=True)
    bgmodels.append(bgmodel)

    bgmodel = bgm.BackgroundModel()
    bgmodel.block_mean_bgm(
        block_size=(16, 16),
        block_overlap=0.5,
        update_rate=0.01,
        fg_report_threshold=50,
        channel='grayscale')
    bgmodels.append(bgmodel)

    bgmodel = bgm.BackgroundModel()
    bgmodel.gaussian_mixture_bgm(
        history=500,
        detect_shadows=True,
        var_thresh=100,
        comp_thresh=0.05)
    bgmodels.append(bgmodel)

    bgmodel = bgm.BackgroundModel()
    bgmodel.normalized_rgb_bgm(
        report_as_binary=False,
        # binary_reporting_threshold=20,
        update_rate=0.1,
        alpha=0.1,
        beta=1.0)
    bgmodels.append(bgmodel)

    print("""
! Note that the reported initialization time for the first BGM includes
  library initialization - maybe OpenCV (haven't tracked that down yet).
    """)
    fg_masks = list()
    for bgmodel in bgmodels:
        pyutils.tic('init')
        bgmodel.init(imgs[0])
        t_init = pyutils.ttoc('init')
        pyutils.tic('apply')
        mask = bgmodel.report_changes(imgs[1])
        t_apply = pyutils.ttoc('apply')

        if pseudocolor:
            fg_masks.append(imvis.pseudocolor(mask, limits=None, color_map=colormaps.colormap_viridis_rgb))
        else:
            fg_masks.append(mask)
        print('init/apply: {:17s} {:7.2f} ms, {:7.2f} ms'.format(bgmodel.name(), t_init, t_apply))

        if inspect:
            import iminspect
            iminspect.show(mask)

    padding = 10
    # Add alpha channel to render the README visualization nicely for web display
    fg_masks[0] = np.dstack((fg_masks[0], 255 * np.ones(fg_masks[0].shape[:2], dtype=np.uint8)))
    collage = imvis.make_collage(fg_masks,
        padding=padding,
        fixed_size_per_image=(200, 266),
        bg_color=(0, 0, 0, 0),
        num_images_per_row=2)
    input_seq = cv2.resize(imutils.imread('../data/ninja-seq.png'), (200, 266))
    collage = imvis.make_collage([input_seq, collage],
        padding=padding, bg_color=(0, 0, 0, 0))

    # Overlay names
    height, width = collage.shape[:2]
    collage = imvis.draw_text_box(collage, 'Input',
            (input_seq.shape[1]/2, height/3+20), text_anchor='center', bg_color=(255, 255, 255),
            font_color=(-1, -1, -1), font_scale=1.0,
            font_thickness=1, padding=5, fill_opacity=0.8)

    names = [bg.name() for bg in bgmodels]
    mask_width = (width-input_seq.shape[1] - padding) / 2
    for i in range(len(names)):
        pos = (input_seq.shape[1] + padding + (i % 2) * (mask_width + padding) + mask_width/2,
            (i // 2) * (266 + padding) + 266 - 10)
        collage = imvis.draw_text_box(collage, names[i],
            pos, text_anchor='south', bg_color=(255, 255, 255),
            font_color=(-1, -1, -1), font_scale=1.0,
            font_thickness=1, padding=5, fill_opacity=0.8)

    imvis.imshow(collage, title="Background Subtraction", wait_ms=-1)
    imutils.imsave('../../doc/example-bgm.png', collage)