forked from BachiLi/redner
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest_single_triangle_background.py
162 lines (146 loc) · 6.3 KB
/
test_single_triangle_background.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
import pyredner
import redner
import numpy as np
import torch
import skimage.transform
# Optimize three vertices of a single triangle, with a SIGGRAPH logo background
# Use GPU if available
pyredner.set_use_gpu(torch.cuda.is_available())
# Set up the pyredner scene for rendering:
# Setup camera
cam = pyredner.Camera(position = torch.tensor([0.0, 0.0, -5.0]),
look_at = torch.tensor([0.0, 0.0, 0.0]),
up = torch.tensor([0.0, 1.0, 0.0]),
fov = torch.tensor([45.0]), # in degree
clip_near = 1e-2, # needs to > 0
resolution = (256, 256),
fisheye = False)
# Setup materials
mat_grey = pyredner.Material(\
diffuse_reflectance = \
torch.tensor([0.5, 0.5, 0.5], device = pyredner.get_device()))
# The material list of the scene
materials = [mat_grey]
# Setup geometries
shape_triangle = pyredner.Shape(\
vertices = torch.tensor([[-1.7, 1.0, 0.0], [1.0, 1.0, 0.0], [-0.5, -1.0, 0.0]],
device = pyredner.get_device()),
indices = torch.tensor([[0, 1, 2]], dtype = torch.int32,
device = pyredner.get_device()),
uvs = None,
normals = None,
material_id = 0)
# Setup light source shape
shape_light = pyredner.Shape(\
vertices = torch.tensor([[-1.0, -1.0, -7.0],
[ 1.0, -1.0, -7.0],
[-1.0, 1.0, -7.0],
[ 1.0, 1.0, -7.0]], device = pyredner.get_device()),
indices = torch.tensor([[0, 1, 2],[1, 3, 2]],
dtype = torch.int32, device = pyredner.get_device()),
uvs = None,
normals = None,
material_id = 0)
# The shape list of the scene
shapes = [shape_triangle, shape_light]
# Setup light source
light = pyredner.AreaLight(shape_id = 1,
intensity = torch.tensor([20.0,20.0,20.0]))
area_lights = [light]
# Construct the scene
scene = pyredner.Scene(cam, shapes, materials, area_lights)
# Serialize the scene
# Here we specify the output channels as "radiance" and "alpha"
scene_args = pyredner.RenderFunction.serialize_scene(\
scene = scene,
num_samples = 16,
max_bounces = 1,
channels = [redner.channels.radiance, redner.channels.alpha])
# Render the scene as our target image.
render = pyredner.RenderFunction.apply
# Render. The first argument is the seed for RNG in the renderer.
img = render(0, *scene_args)
# Since we specified alpha as output channel, img has 4 channels now
# We blend the image with a background image
background = pyredner.imread('scenes/textures/siggraph.jpg')
background = torch.from_numpy(skimage.transform.resize(background.numpy(), (256, 256, 3)))
if pyredner.get_use_gpu():
background = background.cuda(device = pyredner.get_device())
background = background.type_as(img)
img = img[:, :, :3] * img[:, :, 3:4] + background * (1 - img[:, :, 3:4])
# Save the images.
# The output image is in the GPU memory if you are using GPU.
pyredner.imwrite(img.cpu(), 'results/test_single_triangle_background/target.exr')
pyredner.imwrite(img.cpu(), 'results/test_single_triangle_background/target.png')
# Read the target image we just saved.
target = pyredner.imread('results/test_single_triangle_background/target.exr')
if pyredner.get_use_gpu():
target = target.cuda(device = pyredner.get_device())
# Perturb the scene, this is our initial guess.
shape_triangle.vertices = torch.tensor(\
[[-2.0,1.5,0.3], [0.9,1.2,-0.3], [-0.4,-1.4,0.2]],
device = pyredner.get_device(),
requires_grad = True)
# We need to serialize the scene again to get the new arguments.
scene_args = pyredner.RenderFunction.serialize_scene(\
scene = scene,
num_samples = 16,
max_bounces = 1,
channels = [redner.channels.radiance, redner.channels.alpha])
# Render the initial guess.
img = render(1, *scene_args)
# Blend the image with a background image
img = img[:, :, :3] * img[:, :, 3:4] + background * (1 - img[:, :, 3:4])
# Save the images.
pyredner.imwrite(img.cpu(), 'results/test_single_triangle_background/init.png')
# Compute the difference and save the images.
diff = torch.abs(target - img)
pyredner.imwrite(diff.cpu(), 'results/test_single_triangle_background/init_diff.png')
# Optimize for triangle vertices.
optimizer = torch.optim.Adam([shape_triangle.vertices], lr=5e-2)
# Run 300 Adam iterations.
for t in range(300):
print('iteration:', t)
optimizer.zero_grad()
# Forward pass: render the image.
scene_args = pyredner.RenderFunction.serialize_scene(\
scene = scene,
num_samples = 4, # We use less samples in the Adam loop.
max_bounces = 1,
channels = [redner.channels.radiance, redner.channels.alpha])
# Important to use a different seed every iteration, otherwise the result
# would be biased.
img = render(t+1, *scene_args)
# Blend the image with a background image
img = img[:, :, :3] * img[:, :, 3:4] + background * (1 - img[:, :, 3:4])
# Save the intermediate render.
pyredner.imwrite(img.cpu(), 'results/test_single_triangle_background/iter_{}.png'.format(t))
# Compute the loss function. Here it is L2.
loss = (img - target).pow(2).sum()
print('loss:', loss.item())
# Backpropagate the gradients.
loss.backward()
# Print the gradients of the three vertices.
print('grad:', shape_triangle.vertices.grad)
# Take a gradient descent step.
optimizer.step()
# Print the current three vertices.
print('vertices:', shape_triangle.vertices)
# Render the final result.
scene_args = pyredner.RenderFunction.serialize_scene(\
scene = scene,
num_samples = 16,
max_bounces = 1,
channels = [redner.channels.radiance, redner.channels.alpha])
img = render(302, *scene_args)
# Blend the image with a background image
img = img[:, :, :3] * img[:, :, 3:4] + background * (1 - img[:, :, 3:4])
# Save the images and differences.
pyredner.imwrite(img.cpu(), 'results/test_single_triangle_background/final.exr')
pyredner.imwrite(img.cpu(), 'results/test_single_triangle_background/final.png')
pyredner.imwrite(torch.abs(target - img).cpu(), 'results/test_single_triangle_background/final_diff.png')
# Convert the intermediate renderings to a video.
from subprocess import call
call(["ffmpeg", "-framerate", "24", "-i",
"results/test_single_triangle_background/iter_%d.png", "-vb", "20M",
"results/test_single_triangle_background/out.mp4"])