def encode_linemoire(fname_root, stop, start=0, width=1, phase=0, delay=200): """Create a line moiré animation and save the resulting images to disk. fname_root is the common filename used for the frames (without numbers and file extension). It may include a subdirectory path. When specifying the numbers used to distinguish the frames' filenames, start and stop behave the same way as the start and stop arguments in the range() function. width is the width (in pixels) of each transparent column in the decoding mask (1 pixel wide, by default). phase is the starting position (in pixels) of the first transparent column in the decoding mask (by default, 0, which indicates that the first transparent column appears at the very beginning of the mask). delay is the number of milliseconds with which to separate each frame in the animated GIF. """ # Hint: the following lines do not have to be part of a correct solution, # but this would be one way of obtaining the correct shape for the # animation image: animation = zeros(imread_sc(fname_root + '0' + '.png').shape) print('animation shape is ', animation.shape) for j in range(stop): img = imread_sc(fname_root+str(j)+'.png') num_frames = stop for i in range(width): animation[:,phase+j+i::num_frames*width] = img[:,phase+j+i::num_frames*width] #img = imread_sc(fname_root+str(1)+'.png') #num_frames = stop #for i in range(width): # animation[:,phase+1+i::num_frames*width] = img[:,phase+i::num_frames*width] #for j in range(stop): # img = imread_sc(fname_root + str(j) + '.png') #raise NotImplementedError('The missing code at this point in ' + # 'encode_linemoire() must be implemented as ' + # 'part of the assignment.') # Encode the number of frames in pixel [0, 0]. Include a checksum. _embed_watermark(animation, num_frames, width, phase) # Write animation image to disk imsave_sc(fname_root + '_linemoire.png', animation) # Write animated GIF to disk that combines original versions of frames create_animated_gif(fname_root, start, stop, delay=delay, out_fname=(fname_root + '_orig'))
def _get_mask(dir_name, im_shape, num_frames, width, phase): """Load from disk, or create, a mask for the line moiré animation at hand. An appropriate mask is specified by knowing the shape of the animation image, the number of frames in the animation, and the width and phase of the transparent elements. If the mask does not exist already, create it. """ # Generate the full path for an appropriate mask on disk. Include the # sub-directory for temporary files in the path. fname = _generate_mask_fname(os.path.join(dir_name, TEMP_DIR), im_shape, num_frames, width, phase) # Attempt to read the file from disk try: mask = imread_sc(fname) except FileNotFoundError: # If the file does not exist, create it mask = _create_mask(dir_name, im_shape, num_frames, width, phase) return mask
def decode_linemoire(fpath, num_frames=None, width=1, phase=0, reverse=False, delay=200): """Decode a line moiré animation and save the results to disk. This function can decode line moiré animations created with this module and created independently. fpath is the full path of the animation image (if it does not have a file extension it is assumed to be '.png). num_frames is the number of frames in the animation. width is the width (in pixels) of each transparent column in the decoding mask (1 pixel wide, by default). phase is the starting position (in pixels) of the first transparent column in the decoding mask (by default, 0, which indicates that the first transparent column appears at the very beginning of the mask). reverse is a bool flag to determine the direction of motion of the mask. delay is the number of milliseconds with which to separate each frame in the animated GIF. If the animation image was created with this software (verified by a simple watermark) its animation properties can be extracted from the animation image itself. """ # Give the filename a default file extension if it does not have one fpath_root, ext = os.path.splitext(fpath) if not ext: ext = '.png' # Read the animation image from disk animation = imread_sc(fpath_root + ext) # If the number of frames in the animation image is not passed as an # argument, raise an exception if the animation image was not created by # this module. if not num_frames: # A watermark in the animation image can be used to verify that this # animation image was created by this module before trusting the # properties extracted from it. verified, num_frames, width, phase = _verify_watermark(animation) # If verified == True, this means that the animation image was created # with this software, and its animation properties extracted from the # image can be trusted. Otherwise, raise an exception. if not verified: raise ValueError('"' + fpath_root + ext + '" does not seem to be a line moiré animation ' + 'created with this software. Please specify ' + 'a value for argument "num_frames".') # Create a generator for the decoded frames. (Extract the subdirectory # name if there is one, in order to appropriately save the mask to disk.) dir_name, fname_root = os.path.split(fpath_root) frames = _decode_animation_images(dir_name, animation, num_frames, width, phase, reverse) # Create a list of temporary filenames to store each decoded frame (has to # be a list rather than a generator because it will be accessed twice). fname_root += '_decoded' temp_fpath_root = os.path.join(dir_name, TEMP_DIR, fname_root) fnames = [temp_fpath_root + str(a) + '.png' for a in range(num_frames)] # Write each decoded frame to a temporary file for fname, frame in zip(fnames, frames): imsave_sc(fname, frame) # Create an animated GIF from these decoded frames create_animated_gif(fnames, delay=delay, out_fname=(fpath_root + '_decoded'))