record shape in place of height and width separately

This commit is contained in:
Grant Sanderson
2016-02-27 13:33:46 -08:00
parent 74517d798d
commit 0667e13427
5 changed files with 66 additions and 57 deletions

View File

@ -11,39 +11,45 @@ from helpers import *
class Camera(object): class Camera(object):
DEFAULT_CONFIG = { DEFAULT_CONFIG = {
#background of a different shape will overwrite these #background of a different shape will overwrite this
"pixel_width" : DEFAULT_WIDTH, "pixel_shape" : (DEFAULT_HEIGHT, DEFAULT_WIDTH),
"pixel_height" : DEFAULT_HEIGHT, #this will be resized to match pixel_shape
"space_shape" : (SPACE_HEIGHT, SPACE_WIDTH),
"space_center" : ORIGIN,
"background_color" : BLACK, "background_color" : BLACK,
#
"space_height" : SPACE_HEIGHT,
"space_center" : ORIGIN,
} }
def __init__(self, background = None, **kwargs): def __init__(self, background = None, **kwargs):
digest_config(self, kwargs, locals()) digest_config(self, kwargs, locals())
self.init_background() self.init_background()
self.resize_space_shape()
self.reset() self.reset()
width_to_height = float(self.pixel_width) / self.pixel_height def resize_space_shape(self, fixed_dimension = 0):
self.space_width = self.space_height * width_to_height """
Changes space_shape to match the aspect ratio
of pixel_shape, where fixed_dimension determines
whether space_shape[0] (height) or space_shape[1] (width)
remains fixed while the other changes accordingly.
"""
aspect_ratio = float(self.pixel_shape[1])/self.pixel_shape[0]
space_height, space_width = self.space_shape
if fixed_dimension == 0:
space_width = aspect_ratio*space_height
else:
space_height = space_width/aspect_ratio
self.space_shape = (space_height, space_width)
def init_background(self): def init_background(self):
if self.background: if self.background:
shape = self.background.shape[:2] self.pixel_shape = self.background.shape[:2]
self.pixel_height, self.pixel_width = shape
else: else:
background_color = Color(self.background_color) background_rgb = color_to_int_rgb(self.background_color)
background_rgb = (255*np.array( self.background = np.zeros(
background_color.get_rgb() list(self.pixel_shape)+[3],
)).astype('uint8')
ones = np.ones(
(self.pixel_height, self.pixel_width, 1),
dtype = 'uint8' dtype = 'uint8'
) )
self.background = np.dot( self.background[:,:] = background_rgb
ones, background_rgb.reshape((1, 3))
)
def get_image(self): def get_image(self):
return np.array(self.pixel_array) return np.array(self.pixel_array)
@ -77,8 +83,8 @@ class Camera(object):
raise Exception("Invalid display mode") raise Exception("Invalid display mode")
def display_region(self, region): def display_region(self, region):
(h, w) = self.pixel_height, self.pixel_width (h, w) = self.pixel_shape
scalar = 2*self.space_height / h scalar = 2*self.space_shape[0] / h
xs = scalar*np.arange(-w/2, w/2) xs = scalar*np.arange(-w/2, w/2)
ys = -scalar*np.arange(-h/2, h/2) ys = -scalar*np.arange(-h/2, h/2)
x_array = np.dot(np.ones((h, 1)), xs.reshape((1, w))) x_array = np.dot(np.ones((h, 1)), xs.reshape((1, w)))
@ -106,29 +112,31 @@ class Camera(object):
pixel_coords = pixel_coords[on_screen_indices] pixel_coords = pixel_coords[on_screen_indices]
rgbs = rgbs[on_screen_indices] rgbs = rgbs[on_screen_indices]
flattener = np.array([1, self.pixel_width], dtype = 'int') ph, pw = self.pixel_shape
flattener = np.array([1, pw], dtype = 'int')
flattener = flattener.reshape((2, 1)) flattener = flattener.reshape((2, 1))
indices = np.dot(pixel_coords, flattener)[:,0] indices = np.dot(pixel_coords, flattener)[:,0]
indices = indices.astype('int') indices = indices.astype('int')
pw, ph = self.pixel_width, self.pixel_height
# new_array = np.zeros((pw*ph, 3), dtype = 'uint8') # new_array = np.zeros((pw*ph, 3), dtype = 'uint8')
# new_array[indices, :] = rgbs # new_array[indices, :] = rgbs
new_pa = self.pixel_array.reshape((ph*pw, 3)) new_pa = self.pixel_array.reshape((ph*pw, 3))
new_pa[indices] = rgbs new_pa[indices] = rgbs
self.pixel_array = new_pa.reshape((ph, pw, 3)) self.pixel_array = new_pa.reshape((ph, pw, 3))
def align_points_to_camera(self, points): def align_points_to_camera(self, points):
## This is where projection should live ## This is where projection should live
return points - self.space_center return points - self.space_center
def points_to_pixel_coords(self, points): def points_to_pixel_coords(self, points):
result = np.zeros((len(points), 2)) result = np.zeros((len(points), 2))
width_mult = self.pixel_width/self.space_width/2 ph, pw = self.pixel_shape
width_add = self.pixel_width/2 sh, sw = self.space_shape
height_mult = self.pixel_height/self.space_height/2 width_mult = pw/sw/2
height_add = self.pixel_height/2 width_add = pw/2
height_mult = ph/sh/2
height_add = ph/2
#Flip on y-axis as you go #Flip on y-axis as you go
height_mult *= -1 height_mult *= -1
@ -139,16 +147,14 @@ class Camera(object):
def on_screen_pixels(self, pixel_coords): def on_screen_pixels(self, pixel_coords):
return reduce(op.and_, [ return reduce(op.and_, [
pixel_coords[:,0] >= 0, pixel_coords[:,0] >= 0,
pixel_coords[:,0] < self.pixel_width, pixel_coords[:,0] < self.pixel_shape[1],
pixel_coords[:,1] >= 0, pixel_coords[:,1] >= 0,
pixel_coords[:,1] < self.pixel_height, pixel_coords[:,1] < self.pixel_shape[0],
]) ])
def adjusted_thickness(self, thickness): def adjusted_thickness(self, thickness):
big_width = PRODUCTION_QUALITY_DISPLAY_CONFIG["width"] big_shape = PRODUCTION_QUALITY_DISPLAY_CONFIG["shape"]
big_height = PRODUCTION_QUALITY_DISPLAY_CONFIG["height"] factor = sum(big_shape)/sum(self.pixel_shape)
factor = (big_width + big_height) / \
(self.pixel_width + self.pixel_height)
return 1 + (thickness-1)/factor return 1 + (thickness-1)/factor
def get_thickening_nudges(self, thickness): def get_thickening_nudges(self, thickness):
@ -171,13 +177,17 @@ class MovingCamera(Camera):
Stays in line with the height, width and position Stays in line with the height, width and position
of a given mobject of a given mobject
""" """
DEFAULT_CONFIG = {
"aligned_dimension" : "height" #or "width"
}
def __init__(self, mobject, **kwargs): def __init__(self, mobject, **kwargs):
digest_locals(self) digest_locals(self)
Camera.__init__(self, **kwargs) Camera.__init__(self, **kwargs)
def capture_mobjects(self, *args, **kwargs): def capture_mobjects(self, *args, **kwargs):
self.space_height = self.mobject.get_height()
self.space_center = self.mobject.get_center() self.space_center = self.mobject.get_center()
#TODO

View File

@ -7,20 +7,17 @@ DEFAULT_WIDTH = 2560
DEFAULT_FRAME_DURATION = 0.04 DEFAULT_FRAME_DURATION = 0.04
PRODUCTION_QUALITY_DISPLAY_CONFIG = { PRODUCTION_QUALITY_DISPLAY_CONFIG = {
"height" : DEFAULT_HEIGHT, "shape" : (DEFAULT_HEIGHT, DEFAULT_WIDTH),
"width" : DEFAULT_WIDTH ,
"frame_duration" : DEFAULT_FRAME_DURATION, "frame_duration" : DEFAULT_FRAME_DURATION,
} }
MEDIUM_QUALITY_DISPLAY_CONFIG = { MEDIUM_QUALITY_DISPLAY_CONFIG = {
"height" : 720, "shape" : (720, 1280),
"width" : 1280,
"frame_duration" : 0.04, "frame_duration" : 0.04,
} }
LOW_QUALITY_DISPLAY_CONFIG = { LOW_QUALITY_DISPLAY_CONFIG = {
"height" : 600,#480, "shape" : (480, 640),
"width" : 1000,#840,
"frame_duration" : 0.04, "frame_duration" : 0.04,
} }

View File

@ -12,6 +12,9 @@ import re
from constants import * from constants import *
def color_to_int_rgb(color):
return (255*np.array(Color(color).get_rgb())).astype('uint8')
def compass_directions(n = 4, start_vect = UP): def compass_directions(n = 4, start_vect = UP):
angle = 2*np.pi/n angle = 2*np.pi/n
return [ return [

View File

@ -18,18 +18,15 @@ from mobject import Mobject
class Scene(object): class Scene(object):
DEFAULT_CONFIG = { DEFAULT_CONFIG = {
"height" : DEFAULT_HEIGHT, "shape" : (DEFAULT_HEIGHT, DEFAULT_WIDTH),
"width" : DEFAULT_WIDTH , "frame_duration" : DEFAULT_FRAME_DURATION,
"frame_duration" : DEFAULT_FRAME_DURATION, "construct_args" : [],
"construct_args" : [], "background" : None,
"background" : None,
"start_dither_time" : DEFAULT_DITHER_TIME,
} }
def __init__(self, **kwargs): def __init__(self, **kwargs):
digest_config(self, kwargs) digest_config(self, kwargs)
self.camera = Camera( self.camera = Camera(
pixel_width = self.width, pixel_shape = self.shape,
pixel_height = self.height,
background = self.background background = self.background
) )
self.frames = [] self.frames = []
@ -154,11 +151,10 @@ class Scene(object):
for t in self.get_time_progression(animations): for t in self.get_time_progression(animations):
for animation in animations: for animation in animations:
animation.update(t / animation.run_time) animation.update(t / animation.run_time)
self.camera.capture_mobjects([ self.camera.capture_mobjects(moving_mobjects)
anim.mobject frame = self.camera.get_image()
for anim in animations
]) self.frames.append(frame)
self.frames.append(self.camera.get_image())
self.camera.set_image(static_image) self.camera.set_image(static_image)
for animation in animations: for animation in animations:
animation.clean_up() animation.clean_up()
@ -247,7 +243,7 @@ class Scene(object):
print "Writing to %s"%file_path print "Writing to %s"%file_path
fps = int(1/self.frame_duration) fps = int(1/self.frame_duration)
dim = (self.width, self.height) dim = tuple(reversed(self.shape))
command = [ command = [
FFMPEG_BIN, FFMPEG_BIN,

View File

@ -10,7 +10,10 @@ class TkSceneRoot(Tkinter.Tk):
raise Exception(str(scene) + " has no frames!") raise Exception(str(scene) + " has no frames!")
Tkinter.Tk.__init__(self) Tkinter.Tk.__init__(self)
kwargs = {"height" : scene.height, "width" : scene.width} kwargs = {
"height" : scene.shape[0],
"width" : scene.shape[1],
}
self.frame = Tkinter.Frame(self, **kwargs) self.frame = Tkinter.Frame(self, **kwargs)
self.frame.pack() self.frame.pack()
self.canvas = Tkinter.Canvas(self.frame, **kwargs) self.canvas = Tkinter.Canvas(self.frame, **kwargs)