├── LICENSE
├── README.md
├── python
├── spin-zoom
│ ├── README.md
│ ├── requirements.txt
│ ├── spin-zoom.gif
│ └── spin-zoom.py
└── vid2vid
│ ├── README.md
│ ├── example.gif
│ ├── requirements.txt
│ └── vid2vid.py
└── web
└── plain-js
├── PlainJS.html
├── README.md
└── screenshot.png
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 compute(r)ender
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Tutorials
2 | Examples using the [computerender](https://computerender.com) API
3 |
4 | ## Python
5 |
6 | - [vid2vid](python/vid2vid/)
7 |
8 |
9 | - [spin-zoom](python/spin-zoom/)
10 |
11 |
12 | ## Web
13 |
14 | - [plain-js](web/plain-js/)
15 |
16 |
--------------------------------------------------------------------------------
/python/spin-zoom/README.md:
--------------------------------------------------------------------------------
1 | # vid2vid
2 |
3 | Spinning zoom effect using stable diffusion via [computerender](https://computerender.com).
4 |
5 |
6 |
7 | ## 1. Setup
8 | You can install the python dependencies by running:
9 |
10 | ```bash
11 | pip install -r requirements.txt
12 | ```
13 |
14 | To install install ffmpeg:
15 | Linux
16 | ```bash
17 | apt install ffmpeg
18 | ```
19 | Macos:
20 | ```bash
21 | brew install ffmpeg
22 | ```
23 | Windows:
24 | https://ffmpeg.org/download.html
25 |
26 | ## 2. API Key
27 | You can get an API key by making an account at https://computerender.com/account.html
28 | To make your key visible to the python client, you can add it as an environment variable:
29 | ```bash
30 | export CR_KEY=sk_your_key_here
31 | ```
32 | Or alternatively provide it when initializing the client in the python script:
33 | ```python
34 | cr = Computerender("sk_your_key_here")
35 | ```
36 |
37 | ## 3. Running the script
38 | It is a good idea to first create a short, trimmed version of your video that's just a few frames.
39 | This will be helpful for tuning parameters to get the right amount of modification to your video.
40 | Most importantly, the "strength" parameter will determine how much influence the effect has.
41 | The angle and zoom parameters control the speed of the zooming effect.
42 |
43 | Run the script:
44 | ```bash
45 | python spin-zoom.py
46 | ```
47 |
48 | ## 4. Post processing
49 | To produce the final output, the video was imported into adobe premiere and slowed using "optical flow" as the frame interpolation. It may be possible to achieve the same effect using opencv, but that is not covered in this tutorial.
50 |
--------------------------------------------------------------------------------
/python/spin-zoom/requirements.txt:
--------------------------------------------------------------------------------
1 | numpy
2 | Pillow
3 | tqdm
4 | mediapy
5 | computerender
--------------------------------------------------------------------------------
/python/spin-zoom/spin-zoom.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/computerender/tutorials/d65208541f9ac59ea3ff321d10928b0b72ad849a/python/spin-zoom/spin-zoom.gif
--------------------------------------------------------------------------------
/python/spin-zoom/spin-zoom.py:
--------------------------------------------------------------------------------
1 | import math
2 | from io import BytesIO
3 | import asyncio
4 | from computerender import Computerender
5 | from tqdm import tqdm
6 | from PIL import Image
7 | import numpy as np
8 | from mediapy import VideoWriter
9 |
10 | input_file = "IMG_4839.jpeg" # <-- Starting image
11 | output_file = "sd-zoom-output.mp4"
12 | prompt = "beautiful lush forest, national geographic"
13 | frames = 100 # Length of video
14 | strength = 0.4 # How strong the styling effect should be (range 0.1-1.0)
15 | scale_speed = 0.98 # How fast to zoom
16 | angle_speed = 0.9 * 2 * math.pi / 360 # How fast to rotate
17 | iterations = 60
18 | guidance = 11.0
19 | output_res = (512, 512)
20 | out_r = (output_res[1], output_res[0])
21 | parallel_jobs = 4
22 |
23 | # using the cropping method from here:
24 | # https://note.nkmk.me/en/python-pillow-square-circle-thumbnail/
25 | def crop_center(pil_img, crop_width, crop_height):
26 | img_width, img_height = pil_img.size
27 | return pil_img.crop(((img_width - crop_width) // 2,
28 | (img_height - crop_height) // 2,
29 | (img_width + crop_width) // 2,
30 | (img_height + crop_height) // 2))
31 |
32 | def crop_max_square(pil_img):
33 | return crop_center(pil_img, min(pil_img.size), min(pil_img.size))
34 |
35 | # PIL doesn't have a great way for building
36 | # affine transformations so we're doing it manually
37 | def create_transform(angle, scale, dimensions):
38 | # center of image
39 | x = dimensions[0] // 2
40 | y = dimensions[1] // 2
41 |
42 | # translation matrix to center of image
43 | trans_a = np.array([[1, 0, x],
44 | [0, 1, y],
45 | [0, 0, 1]])
46 | # rotation matrix
47 | rot = np.array([[math.cos(angle), math.sin(angle), 0],
48 | [-math.sin(angle), math.cos(angle), 0],
49 | [0, 0, 1]])
50 | # scale matrix
51 | scale = np.array([[scale_speed, 0, 0],
52 | [0, scale_speed, 0],
53 | [0, 0, 1]])
54 | # translate back to original position
55 | trans_b = np.array([[1, 0, -x],
56 | [0, 1, -y],
57 | [0, 0, 1]])
58 | # compose transformations into a single matrix
59 | return trans_a @ rot @ scale @ trans_b
60 |
61 | cr = Computerender()
62 |
63 | async def img2img(img, strength_mul, seed):
64 | img_bytes = BytesIO()
65 | img.save(img_bytes, format="jpeg")
66 | img_out = await cr.generate(
67 | prompt, iterations=iterations, seed=seed, strength=strength*strength_mul,
68 | guidance=guidance, img=img_bytes.getvalue()
69 | )
70 | return Image.open(BytesIO(img_out))
71 |
72 | async def main():
73 |
74 | # load base image
75 | cur_img = crop_max_square(
76 | Image.open(input_file)
77 | ).resize(output_res, Image.Resampling.NEAREST)
78 |
79 | with VideoWriter(output_file, shape=output_res, fps=30) as w:
80 |
81 | w.add_image(np.array(cur_img))
82 |
83 | # for each frame
84 | for idx in tqdm(range(frames)):
85 |
86 | # run img2img
87 | cur_img = await img2img(cur_img, 1.0, idx)
88 |
89 | w.add_image(np.array(cur_img))
90 |
91 | t = create_transform(angle_speed, scale_speed, out_r)
92 | # transform image
93 | cur_img = cur_img.transform(
94 | out_r,
95 | Image.Transform.AFFINE,
96 | (t[0][0], t[0][1], t[0][2], t[1][0], t[1][1], t[1][2]),
97 | resample=Image.Resampling.BILINEAR)
98 |
99 | asyncio.run(main())
--------------------------------------------------------------------------------
/python/vid2vid/README.md:
--------------------------------------------------------------------------------
1 | # vid2vid
2 |
3 | Style video using stable diffusion with [computerender](https://computerender.com).
4 |
5 |
6 |
7 | ## 1. Setup
8 | You can install the python dependencies by running:
9 |
10 | ```bash
11 | pip install -r requirements.txt
12 | ```
13 |
14 | Install ffmpeg for:
15 |
16 | Linux
17 | ```bash
18 | apt install ffmpeg
19 | ```
20 | Macos:
21 | ```bash
22 | brew install ffmpeg
23 | ```
24 | Windows:
25 | https://ffmpeg.org/download.html
26 |
27 | ## 2. API Key
28 | You can get an API key by making an account at https://computerender.com/account.html
29 | To make your key visible to the python client, you can add it as an environment variable:
30 | ```bash
31 | export CR_KEY=sk_your_key_here
32 | ```
33 | Or alternatively provide it when initializing the client in the python script:
34 | ```python
35 | cr = Computerender("sk_your_key_here")
36 | ```
37 |
38 | ## 3. Running the script
39 | It is a good idea to first create a short, trimmed version of your video that's just a few frames.
40 | This will be helpful for tuning parameters to get the right amount of modification to your video.
41 | Most importantly, the "strength" parameter will determine how much influence the effect has.
42 |
43 | Run the script:
44 | ```bash
45 | python vid2vid.py
46 | ```
47 |
48 | ## 4. Post processing
49 | To produce the final output, the video was imported into adobe premiere and slowed using "optical flow" as the frame interpolation. It is also possible to do this optical flow interpolation using ffmpeg.
50 | Following the method used in this article:
51 | https://blog.programster.org/ffmpeg-create-smooth-videos-with-frame-interpolation
52 | One can do:
53 | ```bash
54 | ffmpeg \
55 | -i sd-output.mp4 \
56 | -crf 10 \
57 | -vf "minterpolate=fps=60:mi_mode=mci:mc_mode=aobmc:me_mode=bidir:vsbmc=1" \
58 | sd-output-smooth.mp4
59 | ```
60 | You may need to first edit the speed or framerate of the video to get good results this way.
61 |
62 |
--------------------------------------------------------------------------------
/python/vid2vid/example.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/computerender/tutorials/d65208541f9ac59ea3ff321d10928b0b72ad849a/python/vid2vid/example.gif
--------------------------------------------------------------------------------
/python/vid2vid/requirements.txt:
--------------------------------------------------------------------------------
1 | numpy
2 | Pillow
3 | tqdm
4 | mediapy
5 | computerender
--------------------------------------------------------------------------------
/python/vid2vid/vid2vid.py:
--------------------------------------------------------------------------------
1 | from io import BytesIO
2 | import asyncio
3 | from computerender import Computerender
4 | from tqdm import tqdm
5 | from PIL import Image
6 | import numpy as np
7 | from mediapy import VideoReader, VideoWriter
8 |
9 | input_file = "IMG_0068.MOV" # <-- put your video here
10 | output_file = "sd-output.mp4"
11 | prompt = "a royal prince playing the guitar in magnificent room, victorian painting, highly detailed"
12 | strength = 0.5 # How strong the styling effect should be (range 0.1-1.0)
13 | seed = 200 # Change this to get a different generation using the same parameters
14 | guidance = 13.0 # How much the model should try to stick to the prompt (range 0-20)
15 | iterations = 50
16 | output_res = (512,512)
17 | out_r = (output_res[1], output_res[0])
18 | parallel_jobs = 4
19 |
20 | # using the cropping method from here:
21 | # https://note.nkmk.me/en/python-pillow-square-circle-thumbnail/
22 | def crop_center(pil_img, crop_width, crop_height):
23 | img_width, img_height = pil_img.size
24 | return pil_img.crop(((img_width - crop_width) // 2,
25 | (img_height - crop_height) // 2,
26 | (img_width + crop_width) // 2,
27 | (img_height + crop_height) // 2))
28 |
29 | def crop_max_square(pil_img):
30 | return crop_center(pil_img, min(pil_img.size), min(pil_img.size))
31 |
32 | cr = Computerender()
33 |
34 | async def img2img(arr, out_r):
35 | pil_image = crop_max_square(Image.fromarray(arr)).resize(out_r)
36 | img_bytes = BytesIO()
37 | pil_image.save(img_bytes, format="jpeg")
38 | img_out = await cr.generate(
39 | prompt, iterations=iterations, strength=strength,
40 | seed=seed, guidance=guidance, img=img_bytes.getvalue()
41 | )
42 | return Image.open(BytesIO(img_out))
43 |
44 | async def main():
45 | with VideoReader(input_file) as r:
46 | with VideoWriter(output_file, shape=output_res, fps=r.fps, bps=r.bps) as w:
47 | cur_frames = []
48 | for image in tqdm(r, total=r.num_images):
49 | cur_frames.append(image)
50 | if len(cur_frames) == parallel_jobs:
51 | imgs = await asyncio.gather(*[img2img(frame, out_r) for frame in cur_frames])
52 | for sd_image in imgs:
53 | w.add_image(np.array(sd_image))
54 | cur_frames = []
55 |
56 | asyncio.run(main())
--------------------------------------------------------------------------------
/web/plain-js/PlainJS.html:
--------------------------------------------------------------------------------
1 |
2 |
18 |
19 |