Skip to content

Commit 721ac88

Browse files
RussTorresfcollman
authored andcommitted
Rendererclient (#134)
* render-parameters: initial renderparameters retrieval * client: add rendererClient calls * renderparams: add renderparameter apis * renderer: add renderer client to render renderparameters * client: python 2 compatibility
1 parent d5ccfaf commit 721ac88

File tree

5 files changed

+262
-5
lines changed

5 files changed

+262
-5
lines changed

integration_tests/test_client_integrated.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,6 +361,29 @@ def test_processpools_parallelfuncs(
361361
mpPool=poolclass)
362362

363363

364+
@pytest.fixture(scope='module')
365+
def example_renderparameters(render, teststack):
366+
zvalues = render.run(renderapi.stack.get_z_values_for_stack, teststack)
367+
z = zvalues[0]
368+
bounds = render.run(renderapi.stack.get_bounds_from_z, teststack, z)
369+
width = (bounds['maxX'] - bounds['minX']) / 2
370+
height = (bounds['maxY'] - bounds['minY']) / 2
371+
x = bounds['minX'] + width / 4
372+
y = bounds['minY'] + width / 4
373+
renderparams = renderapi.image.get_bb_renderparams(
374+
teststack, z, x, y, width, height,
375+
scale=0.25, render=render)
376+
yield renderparams
377+
378+
379+
@pytest.fixture(scope='module')
380+
def renderedimg_renderparams(render, example_renderparameters):
381+
# TODO is there a "render from renderparams" api?
382+
arr = renderapi.image.get_renderparameters_image(
383+
example_renderparameters, render=render)
384+
yield arr, example_renderparameters
385+
386+
364387
@pytest.fixture(scope='module')
365388
def tile_tilespec():
366389
tile_dims = (256, 256)
@@ -393,3 +416,13 @@ def test_ARGBrenderclient(render, tile_tilespec):
393416
tilearr = np.array(tileimg)
394417
assert arr.shape[:-1] == (tspec.width, tspec.height) == tilearr.shape
395418
assert np.all(arr[:, :, 0] == tilearr)
419+
420+
421+
def testRendererClient(render, renderedimg_renderparams):
422+
renderedarr, renderparams = renderedimg_renderparams
423+
arr = renderapi.client.render_renderparameters(renderparams, render=render)
424+
assert arr.shape[:-1] == (
425+
int(renderparams['height'] * renderparams['scale']),
426+
int(renderparams['width'] * renderparams['scale'])
427+
) == renderedarr.shape[:-1]
428+
assert np.all(arr == renderedarr)

integration_tests/test_stack_integrated.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,25 @@ def test_bb_image_options(render, teststack):
323323
maxIntensity=255)
324324

325325

326+
def test_bb_renderparams(render, teststack):
327+
zvalues = render.run(renderapi.stack.get_z_values_for_stack, teststack)
328+
z = zvalues[0]
329+
bounds = render.run(renderapi.stack.get_bounds_from_z, teststack, z)
330+
width = (bounds['maxX'] - bounds['minX']) / 2
331+
height = (bounds['maxY'] - bounds['minY']) / 2
332+
x = bounds['minX'] + width / 4
333+
y = bounds['minY'] + width / 4
334+
scale = 0.25
335+
336+
rp = renderapi.image.get_bb_renderparams(
337+
teststack, z, x, y, width, height, scale=scale, render=render)
338+
assert int(rp['width'] * rp['scale']) == int(width * scale)
339+
assert int(rp['height'] * rp['scale']) == int(height * scale)
340+
assert int(rp['x']) == int(x)
341+
assert int(rp['y']) == int(y)
342+
assert len(rp['tileSpecs'])
343+
344+
326345
def test_tile_image(render, teststack, render_example_tilespec_and_transforms,
327346
**kwargs):
328347
(tilespecs, tforms) = render_example_tilespec_and_transforms
@@ -346,6 +365,23 @@ def test_tile_image_options(render, teststack,
346365
scale=testscale, filter=True, normalizeForMatching=False)
347366

348367

368+
def test_tile_renderparams(render, teststack):
369+
zvalues = render.run(renderapi.stack.get_z_values_for_stack, teststack)
370+
z = zvalues[0]
371+
372+
tspecs = renderapi.tilespec.get_tile_specs_from_z(
373+
teststack, z, render=render)
374+
ts = tspecs[0]
375+
376+
rp = renderapi.image.get_tile_renderparams(
377+
teststack, ts.tileId, render=render)
378+
assert int(rp['x']) == int(ts.minX)
379+
assert int(rp['y']) == int(ts.minY)
380+
assert len(rp['tileSpecs']) == 1
381+
assert rp['height'] - 1 == int(ts.maxY - ts.minY)
382+
assert rp['width'] - 1 == int(ts.maxX - ts.minX)
383+
384+
349385
def test_section_image(render, teststack, **kwargs):
350386
zvalues = render.run(renderapi.stack.get_z_values_for_stack, teststack)
351387
z = zvalues[0]
@@ -367,6 +403,19 @@ def test_section_image_options(render, teststack):
367403
maxTileSpecsToRender=50)
368404

369405

406+
def test_section_renderparams(render, teststack):
407+
zvalues = render.run(renderapi.stack.get_z_values_for_stack, teststack)
408+
z = zvalues[0]
409+
tspecs = renderapi.tilespec.get_tile_specs_from_z(
410+
teststack, z, render=render)
411+
412+
scalefactor = 0.05
413+
rp = renderapi.image.get_section_renderparams(
414+
teststack, z, scale=scalefactor, render=render)
415+
assert len(rp['tileSpecs']) == len(tspecs)
416+
assert rp['scale'] == scalefactor
417+
418+
370419
def fail_image_get(render, teststack, render_example_tilespec_and_transforms):
371420
with pytest.raises(KeyError):
372421
render.run(renderapi.image.get_tile_image_data, teststack,

renderapi/client/client.py

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
from renderapi.external.processpools.stdlib_pool import WithMultiprocessingPool
1818

1919
from .utils import renderclientaccess
20-
from .client_calls import importJsonClient, call_run_ws_client, renderClient
20+
from .client_calls import importJsonClient, call_run_ws_client, renderClient, rendererClient
2121

2222
# setup logger
2323
logger = logging.getLogger(__name__)
@@ -397,11 +397,32 @@ def render_tilespec(*args, **kwargs):
397397
return arr
398398

399399

400+
@renderclientaccess
401+
def materialize_renderparameters_image(
402+
obj, out_fn=None, subprocess_mode=None, client_script=None, memGB=None,
403+
render=None, **kwargs):
404+
tfile = renderdump_temp(obj)
405+
rendererClient(parameters_url=tfile, out_fn=out_fn,
406+
subprocess_mode=subprocess_mode,
407+
client_script=client_script, memGB=memGB, **kwargs)
408+
os.remove(tfile)
409+
410+
411+
def render_renderparameters(*args, **kwargs):
412+
# NOTE this is python2 compatible hack for keyword-only args
413+
image_ext = kwargs.get('image_ext', '.png')
414+
with tempfile.NamedTemporaryFile(suffix=image_ext) as f:
415+
materialize_renderparameters_image(*args, out_fn=f.name, **kwargs)
416+
arr = numpy.array(Image.open(f.name))
417+
return arr
418+
419+
400420
__all__ = [
401421
"import_single_json_file",
402422
"import_jsonfiles_and_transforms_parallel_by_z",
403423
"import_jsonfiles_parallel", "import_jsonfiles",
404424
"import_jsonfiles_validate_client", "import_tilespecs",
405425
"import_tilespecs_parallel", "local_to_world_array",
406426
"world_to_local_array", "WithPool",
407-
"render_tilespec", "materialize_tilespec_image"]
427+
"render_tilespec", "materialize_tilespec_image",
428+
"materialize_renderparameters_image", "render_renderparameters"]

renderapi/client/client_calls.py

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -682,9 +682,53 @@ def renderClient(tile_spec_url=None, height=None, width=None, in_fn=None,
682682
**kwargs)
683683

684684

685+
@renderclientaccess
686+
def rendererClient(tile_spec_url=None, meshCellSize=None, minMeshCellSize=None,
687+
in_fn=None, out_fn=None, x=None, y=None, width=None,
688+
height=None, scale=None, area_offset=None,
689+
minIntensity=None, maxIntensity=None, gray=None,
690+
quality=None, threads=None, skip_interpolation=None,
691+
binary_mask=None, exclude_mask=None, parameters_url=None,
692+
do_filter=None, background_color=None, fill_with_noise=None,
693+
channels=None, subprocess_mode=None, client_script=None,
694+
memGB=None, render=None, **kwargs):
695+
get_cmd_opt = ArgumentParameters.get_cmd_opt
696+
697+
argvs = (get_cmd_opt(tile_spec_url, '--tile_spec_url') +
698+
get_cmd_opt(height, '--height') +
699+
get_cmd_opt(width, '--width') +
700+
get_cmd_opt(in_fn, '--in') +
701+
get_cmd_opt(out_fn, '--out') +
702+
get_cmd_opt(x, '--x') +
703+
get_cmd_opt(y, '--y') +
704+
get_cmd_opt(meshCellSize, '--meshCellSize') +
705+
get_cmd_opt(minMeshCellSize, '--minMeshCellSize') +
706+
get_cmd_opt(scale, '--scale') +
707+
get_cmd_opt(area_offset, '--area_offset') +
708+
get_cmd_opt(minIntensity, '--minIntensity') +
709+
get_cmd_opt(maxIntensity, '--maxIntensity') +
710+
get_cmd_opt(gray, '--gray') +
711+
get_cmd_opt(quality, '--quality') +
712+
get_cmd_opt(threads, '--threads') +
713+
get_cmd_opt(skip_interpolation, '--skip_interpolation') +
714+
get_cmd_opt(binary_mask, '--binary_mask') +
715+
get_cmd_opt(exclude_mask, '--exclude_mask') +
716+
get_cmd_opt(parameters_url, '--parameters_url') +
717+
get_cmd_opt(do_filter, '--do_filter') +
718+
get_cmd_opt(background_color, '--background_color') +
719+
get_cmd_opt(fill_with_noise, '--fill_with_noise') +
720+
get_cmd_opt(channels, '--channels'))
721+
722+
call_run_ws_client('org.janelia.alignment.Render',
723+
memGB=memGB, client_script=client_script,
724+
subprocess_mode=subprocess_mode, add_args=argvs,
725+
**kwargs)
726+
727+
685728
__all__ = [
686729
"call_run_ws_client", "run_subprocess_mode",
687730
"importJsonClient", "tilePairClient",
688731
"importTransformChangesClient", "coordinateClient",
689732
"renderSectionClient", "transformSectionClient",
690-
"get_canvas_url_template", "pointMatchClient"]
733+
"get_canvas_url_template", "pointMatchClient", "renderClient",
734+
"rendererClient"]

renderapi/image.py

Lines changed: 112 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
from PIL import Image
66
import numpy as np
77
import logging
8-
from .render import format_preamble, renderaccess
8+
from .render import format_preamble, format_baseurl, renderaccess
99
from .errors import RenderError
10-
from .utils import NullHandler, jbool
10+
from .utils import NullHandler, jbool, get_json, put_json
1111

1212
logger = logging.getLogger(__name__)
1313
logger.addHandler(NullHandler())
@@ -25,6 +25,38 @@
2525
None: 'png-image'} # Default to png
2626

2727

28+
def _strip_None_value_dictitems(d, exclude_keys=[]):
29+
return {k: v for k, v in d.items()
30+
if v is not None and k not in exclude_keys}
31+
32+
33+
@renderaccess
34+
def get_bb_renderparams(stack, z, x, y, width, height, scale=1.0,
35+
channel=None, minIntensity=None, maxIntensity=None,
36+
binaryMask=None, filter=None, filterListName=None,
37+
convertToGray=None, excludeMask=None,
38+
host=None, port=None, owner=None,
39+
project=None, session=requests.session(),
40+
render=None, **kwargs):
41+
42+
request_url = format_preamble(
43+
host, port, owner, project, stack) + \
44+
"/z/%d/box/%d,%d,%d,%d,%f/render-parameters" % (
45+
z, x, y, width, height, scale)
46+
47+
qparams = _strip_None_value_dictitems({
48+
"minIntensity": minIntensity,
49+
"maxIntensity": maxIntensity,
50+
"binaryMask": binaryMask,
51+
"filter": filter,
52+
"filterListName": filterListName,
53+
"convertToGray": convertToGray,
54+
"excludeMask": excludeMask,
55+
"channels": channel})
56+
57+
return get_json(session, request_url, params=qparams)
58+
59+
2860
@renderaccess
2961
def get_bb_image(stack, z, x, y, width, height, scale=1.0,
3062
channel=None,
@@ -109,6 +141,41 @@ def get_bb_image(stack, z, x, y, width, height, scale=1.0,
109141
return RenderError(r.text)
110142

111143

144+
@renderaccess
145+
def get_tile_renderparams(
146+
stack, tileId, channel=None, normalizeForMatching=None,
147+
excludeAllTransforms=None, excludeTransformsAfterLast=None,
148+
excludeFirstTransformAndAllAfter=None, scale=None,
149+
width=None, height=None, minIntensity=None, maxIntensity=None,
150+
filter=None, filterListName=None, excludeMask=None, convertToGray=None,
151+
binaryMask=None, host=None, port=None, owner=None,
152+
project=None, img_format=None,
153+
session=requests.session(), render=None, **kwargs):
154+
request_url = format_preamble(
155+
host, port, owner, project, stack) + \
156+
"/tile/%s/render-parameters" % (
157+
tileId)
158+
159+
qparams = _strip_None_value_dictitems({
160+
"normalizeForMatching": normalizeForMatching,
161+
"excludeAllTransforms": excludeAllTransforms,
162+
"excludeTransformsAfterLast": excludeTransformsAfterLast,
163+
"excludeFirstTransformAndAllAfter": excludeFirstTransformAndAllAfter,
164+
"scale": scale,
165+
"width": width,
166+
"height": height,
167+
"minIntensity": minIntensity,
168+
"maxIntensity": maxIntensity,
169+
"binaryMask": binaryMask,
170+
"filter": filter,
171+
"filterListName": filterListName,
172+
"convertToGray": convertToGray,
173+
"excludeMask": excludeMask,
174+
"channels": channel})
175+
176+
return get_json(session, request_url, params=qparams)
177+
178+
112179
@renderaccess
113180
def get_tile_image_data(stack, tileId, channel=None, normalizeForMatching=True,
114181
excludeAllTransforms=False, scale=None,
@@ -191,6 +258,32 @@ def get_tile_image_data(stack, tileId, channel=None, normalizeForMatching=True,
191258
return RenderError(r.text)
192259

193260

261+
@renderaccess
262+
def get_section_renderparams(stack, z, binaryMask=None, channel=None,
263+
convertToGray=None, excludeMask=None, filter=None,
264+
filterListName=None, minIntensity=None,
265+
maxIntensity=None, scale=None,
266+
host=None, port=None, owner=None, project=None,
267+
session=requests.session(),
268+
render=None, **kwargs):
269+
request_url = format_preamble(
270+
host, port, owner, project, stack) + "/z/{}/render-parameters".format(
271+
z)
272+
273+
qparams = _strip_None_value_dictitems({
274+
"scale": scale,
275+
"minIntensity": minIntensity,
276+
"maxIntensity": maxIntensity,
277+
"binaryMask": binaryMask,
278+
"filter": filter,
279+
"filterListName": filterListName,
280+
"convertToGray": convertToGray,
281+
"excludeMask": excludeMask,
282+
"channels": channel})
283+
284+
return get_json(session, request_url, params=qparams)
285+
286+
194287
@renderaccess
195288
def get_section_image(stack, z, scale=1.0, channel=None,
196289
filter=False,
@@ -255,3 +348,20 @@ def get_section_image(stack, z, scale=1.0, channel=None,
255348

256349
r = session.get(request_url, params=qparams)
257350
return np.asarray(Image.open(io.BytesIO(r.content)))
351+
352+
353+
@renderaccess
354+
def get_renderparameters_image(renderparams, img_format=None,
355+
host=None, port=None, owner=None,
356+
session=requests.session(),
357+
render=None, **kwargs):
358+
try:
359+
image_ext = IMAGE_FORMATS[img_format]
360+
except KeyError as e: # pragma: no cover
361+
raise ValueError('{} is not a valid render image format!'.format(e))
362+
363+
request_url = format_baseurl(host, port) + '/owner/{owner}/{ext}'.format(
364+
owner=owner, ext=image_ext)
365+
366+
r = put_json(session, request_url, renderparams)
367+
return np.array(Image.open(io.BytesIO(r.content)))

0 commit comments

Comments
 (0)