Files
manim/displayer.py
2016-02-27 16:32:53 -08:00

186 lines
6.0 KiB
Python

import numpy as np
import itertools as it
import os
import sys
from PIL import Image
import cv2
from colour import Color
import progressbar
from helpers import *
class Camera(object):
CONFIG = {
"pixel_width" : DEFAULT_WIDTH,
"pixel_height" : DEFAULT_HEIGHT,
"space_height" : SPACE_HEIGHT,
"space_center" : ORIGIN,
"background_color" : BLACK,
}
def __init__(self, background = None, **kwargs):
digest_config(self, kwargs, locals())
self.init_background()
self.reset()
width_to_height = float(self.pixel_width) / self.pixel_height
self.space_width = self.space_height * width_to_height
def init_background(self):
if self.background:
shape = self.background.shape[:2]
self.pixel_height, self.pixel_width = shape
else:
background_color = Color(self.background_color)
background_rgb = np.array(background_color.get_rgb())
ones = np.ones(
(self.pixel_height, self.pixel_width, 1),
dtype = 'uint8'
)
self.background = np.dot(
ones, background_rgb.reshape((1, 3))
)
def get_image(self):
return self.pixel_array
def reset(self):
self.pixel_array = np.array(self.background)
# def get_pixels(image_array): #TODO, FIX WIDTH/HEIGHT PROBLEM HERE
# if image_array is None:
# return np.zeros(
# (DEFAULT_HEIGHT, DEFAULT_WIDTH, 3),
# dtype = 'uint8'
# )
# else:
# pixels = np.array(image_array).astype('uint8')
# assert len(pixels.shape) == 3 and pixels.shape[2] == 3
# return pixels
# def paint_region(region, image_array = None, color = None):
# pixels = get_pixels(image_array)
# assert region.shape == pixels.shape[:2]
# if color is None:
# #Random dark color
# rgb = 0.5 * np.random.random(3)
# else:
# rgb = np.array(Color(color).get_rgb())
# pixels[region.bool_grid] = (255*rgb).astype('uint8')
# return pixels
def capture_mobject(self, mobject):
return self.capture_mobjects([mobject])
def capture_mobjects(self, mobjects, include_sub_mobjects = True):
# pixels = get_pixels(image_array)
# height = pixels.shape[0]
# width = pixels.shape[1]
# space_height = SPACE_HEIGHT
# space_width = SPACE_HEIGHT * width / height
# pixels = pixels.reshape((pixels.size/3, 3)).astype('uint8')
if include_sub_mobjects:
all_families = [
mob.submobject_family()
for mob in mobjects
]
mobjects = reduce(op.add, all_families, [])
for mobject in mobjects:
self.display_points(
mobject.points, mobject.rgbs,
mobject.point_thickness
)
def display_points(self, points, rgbs, thickness):
points = self.project_onto_screen(points)
pixel_coordinates = self.pixel_coordinates_of_points(points)
rgbs = (255*rgbs).astype('uint8')
on_screen_indices = self.on_screen_pixels(pixel_coordinates)
pixel_coordinates = pixel_coordinates[on_screen_indices]
rgbs = rgbs[on_screen_indices]
flattener = np.array([1, self.width], dtype = 'int')
flattener = flattener.reshape((2, 1))
indices = np.dot(pixel_coordinates, flattener)[:,0]
pw, ph = self.pixel_width, self.pixel_height
self.pixel_array.reshape((pw*ph, 3))
self.pixel_array[indices] = rgbs.astype('uint8')
self.pixel_array.reshape((ph, pw, 3))
def project_onto_screen(points):
## TODO
points[:,2] = 0
def pixel_coordinates_of_points(self, points):
result = np.zeros((len(points), 2))
width_mult = self.pixel_width/self.space_width/2
width_add = self.pixel_width/2
height_mult = self.pixel_height/self.space_height/2
height_add = self.pixel_height/2
#Flip on y-axis as you go
height_mult *= -1
result[:,0] = points[:,0]*width_mult + width_add
result[:,1] = points[:,1]*height_mult + height_add
return result
def on_screen_pixels(self, pixel_coordinates):
return (pixel_coordinates[:,0] < 0) | \
(pixel_coordinates[:,0] >= width) | \
(pixel_coordinates[:,1] < 0) | \
(pixel_coordinates[:,1] >= height)
# def add_thickness(pixel_indices_and_rgbs, thickness, width, height):
# """
# Imagine dragging each pixel around like a paintbrush in
# a plus-sign-shaped pixel arrangement surrounding it.
# Pass rgb = None to do nothing to them
# """
# thickness = adjusted_thickness(thickness, width, height)
# original = np.array(pixel_indices_and_rgbs)
# n_extra_columns = pixel_indices_and_rgbs.shape[1] - 2
# for nudge in range(-thickness/2+1, thickness/2+1):
# if nudge == 0:
# continue
# for x, y in [[nudge, 0], [0, nudge]]:
# pixel_indices_and_rgbs = np.append(
# pixel_indices_and_rgbs,
# original+([x, y] + [0]*n_extra_columns),
# axis = 0
# )
# admissibles = (pixel_indices_and_rgbs[:,0] >= 0) & \
# (pixel_indices_and_rgbs[:,0] < width) & \
# (pixel_indices_and_rgbs[:,1] >= 0) & \
# (pixel_indices_and_rgbs[:,1] < height)
# return pixel_indices_and_rgbs[admissibles]
def adjusted_thickness(thickness, width, height):
big_width = PRODUCTION_QUALITY_DISPLAY_CONFIG["width"]
big_height = PRODUCTION_QUALITY_DISPLAY_CONFIG["height"]
factor = (big_width + big_height) / (width + height)
return 1 + (thickness-1)/facto