Skip to content

Commit 93f22f2

Browse files
committed
improved tiling
1 parent 9094303 commit 93f22f2

File tree

4 files changed

+119
-75
lines changed

4 files changed

+119
-75
lines changed

__init__.py

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ class DeepBumpProperties(PropertyGroup):
7979
description='More overlap might help reducing some artifacts but takes longer to compute.',
8080
items=[('SMALL', 'Small', 'Small overlap between tiles.'),
8181
('MEDIUM', 'Medium', 'Medium overlap between tiles.'),
82-
('BIG', 'Big', 'Big overlap between tiles.')]
82+
('LARGE', 'Large', 'Large overlap between tiles.')],
83+
default='LARGE'
8384
)
8485

8586

@@ -136,13 +137,13 @@ def execute(self, context):
136137
img = np.mean(img[0:3], axis=0, keepdims=True)
137138

138139
# Split image in tiles
139-
tile_size = (256, 256)
140-
OVERLAP = context.scene.deep_bump_tool.tiles_overlap_enum
141-
overlaps = {'SMALL': 20, 'MEDIUM': 50, 'BIG': 124}
142-
stride_size = (tile_size[0]-overlaps[OVERLAP],
143-
tile_size[1]-overlaps[OVERLAP])
144140
print('DeepBump : tilling')
145-
tiles, paddings = infer.tiles_split(img, tile_size, stride_size)
141+
tile_size = 256
142+
OVERLAP = context.scene.deep_bump_tool.tiles_overlap_enum
143+
overlaps = {'SMALL': tile_size//6, 'MEDIUM': tile_size//4, 'LARGE': tile_size//2}
144+
stride_size = tile_size-overlaps[OVERLAP]
145+
tiles, paddings = infer.tiles_split(img, (tile_size, tile_size),
146+
(stride_size, stride_size))
146147

147148
# Load model (if not already loaded)
148149
if self.ort_session is None:
@@ -160,8 +161,8 @@ def execute(self, context):
160161

161162
# Merge tiles
162163
print('DeepBump : merging')
163-
pred_img = infer.tiles_merge(
164-
pred_tiles, stride_size, (3, img.shape[1], img.shape[2]), paddings)
164+
pred_img = infer.tiles_merge(pred_tiles, (stride_size, stride_size),
165+
(3, img.shape[1], img.shape[2]), paddings)
165166

166167
# Normalize each pixel to unit vector
167168
pred_img = infer.normalize(pred_img)

cli.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ Go to the DeepBump folder, then use with :
2121

2222
python deepbump_cli.py -i <path_input_image> -n <path_generated_normal> -o <overlap>
2323

24-
where `<overlap>` can be `small`, `medium` or `big`.
24+
where `<overlap>` can be `small`, `medium` or `large`.

deepbump_cli.py

100644100755
Lines changed: 57 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,57 @@
1-
from PIL import Image
2-
import numpy as np
3-
import infer
4-
import onnxruntime as ort
5-
from argparse import ArgumentParser
6-
7-
# Disable MS telemetry
8-
ort.disable_telemetry_events()
9-
10-
# Parse cli arguments
11-
parser = ArgumentParser()
12-
parser.add_argument('-i', '--img_path', dest='img_path', required=True,
13-
help='path to the input image')
14-
parser.add_argument('-n', '--normal_path', dest='normal_path', required=True,
15-
help='path where the generated normal map is saved')
16-
parser.add_argument('-o', '--overlap', dest='overlap', required=True,
17-
help='tiles overlap size, must be "small", "medium" or "big"',
18-
choices=['small', 'medium', 'big'])
19-
args = parser.parse_args()
20-
21-
# Load image
22-
img = np.array(Image.open(args.img_path)) / 255.0
23-
# Reshape to C,H,W
24-
img = np.transpose(img, (2, 0, 1))
25-
# Grayscale
26-
img = np.mean(img[0:3], axis=0, keepdims=True)
27-
28-
# Split image in tiles
29-
print('tilling')
30-
tile_size = (256, 256)
31-
overlaps = {'small': 20, 'medium': 50, 'big': 124}
32-
stride_size = (tile_size[0]-overlaps[args.overlap], tile_size[1]-overlaps[args.overlap])
33-
tiles, paddings = infer.tiles_split(img, tile_size, stride_size)
34-
35-
# Predict tiles normal map
36-
print('generating')
37-
38-
def progress_print(current, total):
39-
print('{}/{}'.format(current, total))
40-
41-
ort_session = ort.InferenceSession('./deepbump256.onnx')
42-
pred_tiles = infer.tiles_infer(tiles, ort_session, progress_callback=progress_print)
43-
44-
# Merge tiles
45-
print('merging')
46-
pred_img = infer.tiles_merge(pred_tiles, stride_size, (3, img.shape[1], img.shape[2]), paddings)
47-
48-
# Save image
49-
pred_img = pred_img.transpose((1,2,0))
50-
pred_img = Image.fromarray((pred_img*255.0).astype(np.uint8))
51-
pred_img.save(args.normal_path)
1+
from PIL import Image
2+
import numpy as np
3+
import infer
4+
import onnxruntime as ort
5+
from argparse import ArgumentParser
6+
7+
8+
def progress_print(current, total):
9+
print('{}/{}'.format(current, total))
10+
11+
12+
# Disable MS telemetry
13+
ort.disable_telemetry_events()
14+
15+
# Parse cli arguments
16+
parser = ArgumentParser()
17+
parser.add_argument('-i', '--img_path', dest='img_path', required=True,
18+
help='path to the input image')
19+
parser.add_argument('-n', '--normal_path', dest='normal_path', required=True,
20+
help='path where the generated normal map is saved')
21+
parser.add_argument('-o', '--overlap', dest='overlap', required=True,
22+
help='tiles overlap size, must be "small", "medium" or "large"',
23+
choices=['small', 'medium', 'large'])
24+
args = parser.parse_args()
25+
26+
# Load image
27+
img = np.array(Image.open(args.img_path)) / 255.0
28+
# Reshape to C,H,W
29+
img = np.transpose(img, (2, 0, 1))
30+
# Grayscale
31+
img = np.mean(img[0:3], axis=0, keepdims=True)
32+
33+
# Split image in tiles
34+
print('tilling')
35+
tile_size = 256
36+
overlaps = {'small': tile_size//6, 'medium': tile_size//4,
37+
'large': tile_size//2}
38+
stride_size = tile_size-overlaps[args.overlap]
39+
tiles, paddings = infer.tiles_split(img, (tile_size, tile_size),
40+
(stride_size, stride_size))
41+
42+
# Predict tiles normal map
43+
print('generating')
44+
ort_session = ort.InferenceSession('./deepbump256.onnx')
45+
pred_tiles = infer.tiles_infer(tiles, ort_session,
46+
progress_callback=progress_print)
47+
48+
# Merge tiles
49+
print('merging')
50+
pred_img = infer.tiles_merge(pred_tiles, (stride_size, stride_size),
51+
(3, img.shape[1], img.shape[2]),
52+
paddings)
53+
54+
# Save image
55+
pred_img = pred_img.transpose((1, 2, 0))
56+
pred_img = Image.fromarray((pred_img*255.0).astype(np.uint8))
57+
pred_img.save(args.normal_path)

infer.py

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,11 @@ def tiles_split(img, tile_size, stride_size):
1414
img_h, img_w = img.shape[1], img.shape[2]
1515

1616
# stride must be even
17-
assert((stride_h % 2 == 0) and (stride_w % 2 == 0))
18-
# stride must greater than half tile
19-
assert((stride_h > tile_h/2) and (stride_w > tile_w/2))
20-
# stride must be smaller than tile size
21-
assert((stride_h < tile_h) and (stride_w < tile_w))
17+
assert (stride_h % 2 == 0) and (stride_w % 2 == 0)
18+
# stride must be greater or equal than half tile
19+
assert (stride_h >= tile_h/2) and (stride_w >= tile_w/2)
20+
# stride must be smaller or equal tile size
21+
assert (stride_h <= tile_h) and (stride_w <= tile_w)
2222

2323
# find total height & width padding sizes
2424
pad_h, pad_w = 0, 0
@@ -97,11 +97,10 @@ def generate_mask(tile_size, stride_size):
9797
mask[-ramp_h:, ramp_w:-ramp_w] = np.transpose(np.linspace(1, 0, num=ramp_h)[None],
9898
(1, 0))
9999

100+
# Assume tiles are squared
101+
assert ramp_h == ramp_w
100102
# top left corner
101-
plane_h = np.repeat(np.transpose(np.linspace(0, 0.25, num=ramp_h)[None], (1, 0)),
102-
ramp_w, axis=1)
103-
plane_w = np.repeat(np.linspace(0, 0.25, num=ramp_w)[None], ramp_h, axis=0)
104-
corner = plane_h + plane_w
103+
corner = np.rot90(corner_mask(ramp_h), 2)
105104
mask[:ramp_h, :ramp_w] = corner
106105
# top right corner
107106
corner = np.flip(corner, 1)
@@ -116,6 +115,44 @@ def generate_mask(tile_size, stride_size):
116115
return mask
117116

118117

118+
def corner_mask(side_length):
119+
'''Generates the corner part of the pyramidal-like mask.
120+
Currently, only for square shapes.'''
121+
122+
corner = np.zeros([side_length, side_length])
123+
124+
for h in range(0, side_length):
125+
for w in range(0, side_length):
126+
if h >= w:
127+
sh = h / (side_length-1)
128+
corner[h, w] = 1-sh
129+
if h <= w:
130+
sw = w / (side_length-1)
131+
corner[h, w] = 1-sw
132+
133+
return corner-0.25*scaling_mask(side_length)
134+
135+
136+
def scaling_mask(side_length):
137+
138+
scaling = np.zeros([side_length, side_length])
139+
140+
for h in range(0, side_length):
141+
for w in range(0, side_length):
142+
sh = h / (side_length-1)
143+
sw = w / (side_length-1)
144+
if h >= w and h <= side_length-w:
145+
scaling[h, w] = sw
146+
if h <= w and h <= side_length-w:
147+
scaling[h, w] = sh
148+
if h >= w and h >= side_length-w:
149+
scaling[h, w] = 1-sh
150+
if h <= w and h >= side_length-w:
151+
scaling[h, w] = 1-sw
152+
153+
return 2*scaling
154+
155+
119156
def tiles_merge(tiles, stride_size, img_size, paddings):
120157
'''Merges the list of tiles into one image. img_size is the original size, before
121158
padding.'''
@@ -127,11 +164,11 @@ def tiles_merge(tiles, stride_size, img_size, paddings):
127164
stride_h, stride_w = stride_size
128165

129166
# stride must be even
130-
assert((stride_h % 2 == 0) and (stride_w % 2 == 0))
131-
# stride must greater than half tile
132-
assert((stride_h > tile_h/2) and (stride_w > tile_w/2))
133-
# stride must be smaller than tile size
134-
assert((stride_h < tile_h) and (stride_w < tile_w))
167+
assert (stride_h % 2 == 0) and (stride_w % 2 == 0)
168+
# stride must be greater or equal than half tile
169+
assert (stride_h >= tile_h/2) and (stride_w >= tile_w/2)
170+
# stride must be smaller or equal tile size
171+
assert (stride_h <= tile_h) and (stride_w <= tile_w)
135172

136173
merged = np.zeros((img_size[0], height, width))
137174
mask = generate_mask((tile_h, tile_w), stride_size)

0 commit comments

Comments
 (0)