Usage in Python#
You can interact with Imaging Server Kit algorithms in Python to access all of the main functionalities:
Interact with remote (served) as well as local algorithms.
Run algorithms in a regular or tile-by-tile fashion.
Collect intermediate (streamed) outputs.
Load samples and access algorithm documentation.
Running algorithms#
Let’s consider our usual thresholding algorithm:
import imaging_server_kit as sk
import skimage.data
@sk.algorithm(
name="Intensity threshold",
parameters={"threshold": sk.Integer(name="Threshold", min=0, max=255, default=128)},
samples=[{"image" : skimage.data.coins()}],
)
def threshold_algo(image, threshold):
mask = image > threshold
return sk.Mask(mask, name="Binary mask")
Our function turned algorithm still “behaves” similarly to the original Python function. If you try this:
image = skimage.data.coins()
mask = threshold_algo(image, threshold=100)
print(mask)
You will get a standard Numpy array for mask.
However, one notable difference is that parameters are validated at runtime according to the annotations you provided.
Because of that, and your annotation of min=0 for the threshold parameter, you won’t be able to run the algorithm with negative threshold values:
mask_invalid = threshold_algo(image, threshold=-1) # Will raise a `ValidationError`
In this case, a ValidationError is raised with the message indicating that the threshold input should be greater than or equal to zero.
Moreover, the algorithm object has gained a few extra methods. You can execute computations via .run():
results = threshold_algo.run(image, threshold=100)
print(results)
In this case, the returned results is an instance of a Results object from imaging-server-kit. Results encapsulate a stack of data layers. In this case, the results include one layer containing the segmentation mask.
Data layers in a Results object can be accessed either by name via .read() or by indexing (results[0]).
mask_result = results.read("Binary mask") # <- Equivalent to accessing `results[0]`
print(mask_result)
Here, mask_result is a Mask object, which is an instance of sk.DataLayer. You can retreive the segmentation mask as its data attribute.
mask = mask_result.data # Numpy array
print(mask.shape)
All data layers have a data attribute, as well as other attributes that you can explore:
.name: A unique name identifying the layer in the stack..data: The returned data, such as a Numpy array..meta: A dictionary of metadata about the layer.
Using sk.Client#
Note
You need to run the “server-side” code from this section in a Python script (not a Jupyter notebook) as explained in Serving algorithms via:
...
if __name__ == "__main__":
sk.serve(threshold_algo)
One of the main advantages of using .run() is that it will work in the same way when applied to a local algorithm and when applied to a client instance connected to an algorithm server.
To demonstrate this, let’s serve our threshold algorithm so that it becomes available on http://localhost:8000. Once the server is available, you can connect to it from Python via a sk.Client() instance:
import imaging_server_kit as sk
# Connect to the server
client = sk.Client("http://localhost:8000")
# Send the image and parameters, computation runs on the server, results are retrieved:
results = client.run(image, threshold=0.5)
print(results)
# Mask data layer
mask_result = results[0]
print(mask_result)
# Segmentation mask
mask = results[0].data
print(mask.shape)
Moreover, you can retreive samples using the .get_sample() method on an algorithm, or client, and passing the index of the sample:
n_samples = client.get_n_samples() # <- Returns the number of samples available
sample = client.get_sample(idx=0) # <- Retreive the first sample.
# Results from running the algo with the given sample
results = client.run(**sample.to_params_dict())
Finally, using .info() on an algorithm, or a connected client, will open the algo docs page in a web browser:
client.info()
Working with algorithm collections#
Algorithm collections expose the same methods as standalone algorithms, except that you need to provide a value for the algorithm parameter, which corresponds to the name of the algorithm.
On the server side, combine two algorithms and serve them:
import imaging_server_kit as sk
import skimage.data
from skimage.filters import threshold_otsu, threshold_li
@sk.algorithm(
name="intensity-threshold",
parameters={"threshold": sk.Integer(name="Threshold", min=0, max=255, default=128)},
samples=[{"image" : skimage.data.coins()}],
)
def threshold_algo(image, threshold):
mask = image > threshold
return sk.Mask(mask, name="Binary mask")
@sk.algorithm(
name="automatic-threshold",
parameters={"method": sk.Choice(name="Method", items=["otsu", "li"], default="otsu")},
samples=[{"image" : skimage.data.coins()}],
)
def auto_threshold(image, method):
if method == "otsu":
mask = image > threshold_otsu(image)
elif method == "li":
mask = image > threshold_li(image)
return sk.Mask(mask, name="Binary mask")
# Combine the algorithms
threshold_algos = sk.combine([threshold_algo, auto_threshold], name="threshold-algos")
if __name__ == "__main__":
sk.serve(threshold_algos)
Then, on the client side:
client = sk.Client("http://localhost:8000")
# List the available algorithms
print(client.algorithms) # ["intensity-threshold", "automatic-threshold"]
thresh_results = client.run(algorithm="intensity-threshold", image=image, threshold=0.3)
print(thresh_results)
auto_results = client.run(algorithm="automatic-threshold", image=image, method="otsu")
print(auto_results)
Tiled inference#
To run an algorithm tile-by-tile, you can set tiled=True and specify the tile_size_px, overlap_percent, randomize and delay_sec parameters:
results = client.run(
image=image,
tiled=True, # <- Enable tiled inference
tile_size_px=64, # (64, 64) sized tiles
overlap_percent=0.1, # 10% overlap
randomize=True, # Process the tiles in a random order
delay_sec=0.0, # (Optional) Add a little time delay betwen each tile
)
Summary#
Use
sk.Client()to connect to algorithm servers from Python.Use
.run()on a client, or the original algorithm, to retreive aResultsobject.Resultscontain a stack of data layers.You can access the
data,nameandmetaattributes of data layers.Parameters are validated (invalid parameters raise a
ValidationError).Use
.get_sample()to retreive samplesUse
.info()to access documentation.Use
tiled=Truefor tiled inference.
Next steps#
Next, we’ll take a look at how you can serve Server Kit algorithms in Docker containers.