# This file is part of Sympathy for Data.
# Copyright (c) 2017, Combine Control Systems AB
#
# SYMPATHY FOR DATA COMMERCIAL LICENSE
# You should have received a link to the License with Sympathy for Data.
from sympathy.api import node
from sympathy.api.nodeconfig import Port, Ports, Tag, Tags
import numpy as np
from sylib.imageprocessing.image import ImagePort
from sylib.imageprocessing.image import File as ImageFile
from sylib.imageprocessing.algorithm_selector import (
ImageFiltering_abstract)
[docs]
class ImageToList(ImageFiltering_abstract, node.Node):
name = 'Image to List'
author = 'Mathias Broxvall'
icon = 'image_list.svg'
description = ('Generates a list of images based on algorithms operating '
'on one image')
nodeid = 'syip.image2list'
tags = Tags(Tag.ImageProcessing.Layers)
def alg_from_labels(im, results, par):
if not np.issubdtype(im.dtype, np.integer):
# Early return, input is not a labeled image
return
if len(im.shape) == 3:
im = im[:, :, 0]
for value in range(np.min(im), np.max(im)+1):
mask = im == value
if value == 0 and not par['do background'].value:
pass
elif np.sum(mask) > 0:
new_image = ImageFile()
new_image.set_image(mask)
results.append(new_image)
def alg_from_channels(im, results, par):
if len(im.shape) < 3:
im = im.reshape(im.shape + (1,))
channels = im.shape[2]
for channel in range(channels):
new_image = ImageFile()
new_image.set_image(im[:, :, channel])
results.append(new_image)
algorithms = {
'from labels': {
'description': ('Generates an image mask selecting each label in '
'an image once'),
'do background': 'If true include the background object (ID=0)',
'multi_chromatic': False,
'algorithm': alg_from_labels},
'from channels': {
'description': ('Generates a list of grayscale images from each '
'channel in input image'),
'multi_chromatic': True,
'algorithm': alg_from_channels}}
options_list = ['do background']
options_types = {'do background': bool}
options_default = {'do background': True}
parameters = node.parameters()
parameters.set_string('algorithm', value=next(iter(algorithms)),
description='', label='Algorithm')
ImageFiltering_abstract.generate_parameters(parameters, options_types,
options_default)
inputs = Ports([
ImagePort('source image', name='source')])
outputs = Ports([
Port.Custom('[image]', 'Resulting list of images', name='results')])
__doc__ = ImageFiltering_abstract.generate_docstring(
description, algorithms, options_list, inputs, outputs)
def execute(self, node_context):
image = node_context.input['source'].get_image()
params = node_context.parameters
alg_name = params['algorithm'].value
results = node_context.output['results']
alg = self.algorithms[alg_name]['algorithm']
alg(image, results, params)
[docs]
class ListToImage(ImageFiltering_abstract, node.Node):
name = 'List to Image'
author = 'Mathias Broxvall'
icon = 'image_list2image.svg'
description = 'Generates an image based on a list of images'
nodeid = 'syip.list2image'
tags = Tags(Tag.ImageProcessing.Layers)
def alg_concatenate(images, par):
max_x, max_y = 0, 0
channels = 0
if len(images) == 0:
return np.zeros((1, 1, 1))
dtype = images[0].get_image().dtype
for im_obj in images:
im = im_obj.get_image()
max_x = max(max_x, im.shape[1])
max_y = max(max_y, im.shape[0])
if len(im.shape) > 2:
channels += im.shape[2]
else:
channels += 1
result = np.zeros((max_y, max_x, channels), dtype=dtype)
ch = 0
for im_obj in images:
im = im_obj.get_image()
if len(im.shape) < 3:
im = im.reshape(im.shape + (1,))
result[:im.shape[0], :im.shape[1], ch:ch+im.shape[2]] = im
ch += im.shape[2]
return result
algorithms = {
'concatenate channels': {
'description': ('Generates an image by concatenating all channels '
'in the input images. Resulting datatype given by '
'first image in the list'),
'multi_chromatic': True,
'algorithm': alg_concatenate}}
options_list = ['do background']
options_types = {'do background': bool}
options_default = {'do background': True}
parameters = node.parameters()
parameters.set_string('algorithm', value=next(iter(algorithms)),
description='', label='Algorithm')
ImageFiltering_abstract.generate_parameters(parameters, options_types,
options_default)
inputs = Ports([
Port.Custom('[image]', 'Input list of images', name='inputs')
])
outputs = Ports([
ImagePort('result image', name='result'),
])
__doc__ = ImageFiltering_abstract.generate_docstring(
description,
algorithms, options_list, inputs, outputs)
def execute(self, node_context):
params = node_context.parameters
output = node_context.output['result']
inputs = node_context.input['inputs']
alg_name = params['algorithm'].value
alg = self.algorithms[alg_name]['algorithm']
im = alg(inputs, params)
output.set_image(im)