|
from PIL import Image |
|
import numpy as np |
|
|
|
import torch |
|
import torchvision.transforms.functional as TF |
|
|
|
from .permutations import make_inner_circle_perm |
|
from .view_permute import PermuteView |
|
|
|
class InnerCircleView(PermuteView): |
|
''' |
|
Implements an "inner circle" view, where a circle inside the image spins |
|
but the border stays still. Inherits from `PermuteView`, which implements |
|
the `view` and `inverse_view` functions as permutations. We just make |
|
the correct permutation here, and implement the `make_frame` method |
|
for animation |
|
''' |
|
def __init__(self): |
|
''' |
|
Make the correct "inner circle" permutations and pass it to the |
|
parent class constructor. |
|
''' |
|
self.perm_64 = make_inner_circle_perm(im_size=64, r=24) |
|
self.perm_256 = make_inner_circle_perm(im_size=256, r=96) |
|
|
|
super().__init__(self.perm_64, self.perm_256) |
|
|
|
def make_frame(self, im, t): |
|
im_size = im.size[0] |
|
frame_size = int(im_size * 1.5) |
|
theta = -t * 180 |
|
|
|
|
|
im = torch.tensor(np.array(im) / 255.).permute(2,0,1) |
|
|
|
|
|
coords = torch.arange(0, 256) - 127.5 |
|
xx, yy = torch.meshgrid(coords, coords) |
|
mask = xx**2 + yy**2 < (24*4)**2 |
|
mask = torch.stack([mask]*3).float() |
|
|
|
|
|
im_rotated = TF.rotate(im, theta) |
|
|
|
|
|
im = im * (1 - mask) + im_rotated * mask |
|
|
|
|
|
im = Image.fromarray((np.array(im.permute(1,2,0)) * 255.).astype(np.uint8)) |
|
|
|
|
|
frame = Image.new('RGB', (frame_size, frame_size), (255, 255, 255)) |
|
frame.paste(im, ((frame_size - im_size) // 2, (frame_size - im_size) // 2)) |
|
|
|
return frame |
|
|
|
|