diff --git a/integration_tests/test_multichannel.py b/integration_tests/test_multichannel.py index cbb7ebf2..12d6d109 100644 --- a/integration_tests/test_multichannel.py +++ b/integration_tests/test_multichannel.py @@ -3,6 +3,7 @@ import pytest import logging import sys +import numpy as np root = logging.getLogger() root.setLevel(logging.DEBUG) @@ -33,8 +34,81 @@ def multichannel_test_stack(render): return stack +@pytest.fixture(scope='module') +def multichannel_test_stack_channelflip(render): + stack = 'multichannel_test_channelflip' + tilespecs = [renderapi.tilespec.TileSpec(json=d) + for d in test_2_channels_d] + for tilespec in tilespecs: + tilespec.channels.reverse() + renderapi.stack.create_stack(stack, render=render) + renderapi.client.import_tilespecs(stack, tilespecs, render=render) + renderapi.stack.set_stack_state(stack, 'COMPLETE', render=render) + return stack + + +@pytest.fixture(scope='module') +def test_pm_collection(render): + collection = 'test_multichan_collection' + renderapi.pointmatch.import_matches( + collection, test_matches, render=render) + return collection + + def test_section_image_channels(render, multichannel_test_stack): section_image = renderapi.image.get_section_image(multichannel_test_stack, 1.0, channel='DAPI', render=render) print(section_image.shape) + + +def test_section_image_same_channel_different_channel_order(render, multichannel_test_stack, multichannel_test_stack_channelflip): + section_image = renderapi.image.get_section_image(multichannel_test_stack, + 1.0, channel='DAPI', + render=render) + section_image2 = renderapi.image.get_section_image(multichannel_test_stack_channelflip, + 1.0, channel='DAPI', + render=render) + assert(np.array_equal(section_image, section_image2)) + + +def test_section_image_different_channel_order(render, multichannel_test_stack, multichannel_test_stack_channelflip): + section_image = renderapi.image.get_section_image(multichannel_test_stack, + 1.0, + render=render) + section_image2 = renderapi.image.get_section_image(multichannel_test_stack_channelflip, + 1.0, + render=render) + assert(not np.array_equal(section_image, section_image2)) + + +def test_multichannel_pointmatches(render, multichannel_test_stack): + collection = 'test_multichannel_pointmatch_same_channel' + sift_options = renderapi.client.SiftPointMatchOptions(renderScale=0.5) + tile_pairs = [['100000001003000', '100000001004000']] + renderapi.client.pointMatchClient(multichannel_test_stack, + collection, + tile_pairs, + filter=True, + excludeAllTransforms=True, + stackChannels='DAPI', + sift_options=sift_options, + render=render) + pms1 = renderapi.pointmatch.get_matches_involving_tile( + collection, collection, '100000001003000', render=render) + assert(len(pms1) > 0) + + collection2 = 'test_multichannel_pointmatch_different_channel' + renderapi.client.pointMatchClient(multichannel_test_stack, + collection2, + tile_pairs, + stack2=multichannel_test_stack, + filter=True, + excludeAllTransforms=True, + stackChannels='DAPI', + stack2Channels='TdTomato', + sift_options=sift_options, + render=render) + with pytest.raises(renderapi.errors.RenderError): + pms2 = renderapi.pointmatch.get_matches_involving_tile( + collection2, collection2, '100000001003000', render=render) diff --git a/renderapi/client/client_calls.py b/renderapi/client/client_calls.py index 3c972a77..68adc2f5 100644 --- a/renderapi/client/client_calls.py +++ b/renderapi/client/client_calls.py @@ -474,6 +474,7 @@ def get_canvas_url_template( stack, filter=False, renderWithoutMask=False, normalizeForMatching=True, excludeTransformsAfterLast=None, excludeFirstTransformAndAllAfter=None, excludeAllTransforms=False, + channels=None, host=None, port=None, owner=None, project=None, client_script=None, render=None, **kwargs): """function for making a render-parameters url template for point matching @@ -507,6 +508,11 @@ def get_canvas_url_template( excludeAllTransforms: bool alternative to normalizeForMatching which simply removes all transforms from the list. default=False + channels: str + list of channels and weights to render in the format [channel name], [channel name]__[weight] or + channel one name]__[weight]__ ... [channel n name]__[weight]. + e.g., "DAPI" or "DAPI__0.9__TdTomato__0.1" + default = None """ # noqa: E501 request_url = format_preamble(host, port, owner, project, stack) tile_base_url = request_url + "/tile" @@ -534,6 +540,8 @@ def get_canvas_url_template( excludeFirstTransformAndAllAfter) if excludeAllTransforms: url_suffix += '&excludeAllTransforms=true' + if channels: + url_suffix += '&channels={}'.format(channels) canvas_url_template = "%s/{}/%s" % (tile_base_url, url_suffix) @@ -551,6 +559,8 @@ def pointMatchClient(stack, collection, tile_pairs, excludeTransformsAfterLast=None, excludeAllTransforms=None, excludeFirstTransformAndAllAfter=None, + stackChannels=None, + stack2Channels=None, subprocess_mode=None, host=None, port=None, owner=None, project=None, client_script=None, @@ -598,7 +608,13 @@ def pointMatchClient(stack, collection, tile_pairs, transforms that you had applied after it. default= None. excludeAllTransforms: bool alternative to normalizeForMatching which simply removes all transforms from the list. - default=False + default = False + stackChannels: str or None + If specified, option to select which channel is used for the stack. + default = None + stack2Channels: str or None + If specified, option to select which channel is used for stack2, if specified. + default = None """ # noqa: E501 sift_options = (SiftPointMatchOptions(**kwargs) if sift_options is None @@ -625,6 +641,7 @@ def pointMatchClient(stack, collection, tile_pairs, excludeTransformsAfterLast, excludeFirstTransformAndAllAfter, excludeAllTransforms, + channels=stackChannels, host=host, port=port, owner=owner, @@ -640,6 +657,7 @@ def pointMatchClient(stack, collection, tile_pairs, excludeTransformsAfterLast, excludeFirstTransformAndAllAfter, excludeAllTransforms, + channels=stack2Channels, host=host, port=port, owner=owner, @@ -647,7 +665,6 @@ def pointMatchClient(stack, collection, tile_pairs, client_script=client_script) else: canvas_url_template2 = canvas_url_template - for tile1, tile2 in tile_pairs: argvs += [canvas_url_template.format(tile1), canvas_url_template2.format(tile2)]