# Copyright (c) 2017, System Engineering Software Society
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the System Engineering Software Society nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED.
# IN NO EVENT SHALL SYSTEM ENGINEERING SOFTWARE SOCIETY BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
from __future__ import (print_function, division, unicode_literals,
absolute_import)
from sympathy.api import node
from sympathy.api.nodeconfig import Port, Ports, Tag, Tags
from skimage import io
from sylib.imageprocessing.image import Image
import numpy as np
[docs]class SaveImage(node.Node):
"""
Saves an image to a datasource in the given file format.
"""
name = 'Save Image'
author = 'Mathias Broxvall'
copyright = "(C) 2017 System Engineering Software Society"
version = '0.1'
icon = 'image_save.svg'
description = 'Saves an image to a datasource in the given file format'
nodeid = 'syip.saveimage'
tags = Tags(Tag.ImageProcessing.IO)
file_formats = ['png', 'gif']
parameters = node.parameters()
parameters.set_string(
'File format', value='png',
description=('Desired file format of saved file '
'(.png or .gif currently available)'),
editor=node.Util.combo_editor(options=file_formats).value())
inputs = Ports([
Image('Input image', name='image'),
Port.Datasource(
'File name before appending file type extension (eg: .png)',
name='dest')])
outputs = Ports([
Port.Datasource(
'File name after appending file type extension (eg: .png)',
name='out')])
def execute(self, node_context):
image = node_context.input['image'].get_image()
dest = node_context.input['dest']
if dest.decode_type() != 'FILE':
raise NotImplementedError(
'Image saving must be done to file names.')
if len(image.shape) > 2 and image.shape[2] not in [1, 3, 4]:
raise NotImplementedError(
'Only images with 1, 3, or 4 channels can be exported.')
if not isinstance(image.dtype, np.uint8):
image = (image*255.0).astype(np.uint8)
if len(image.shape) > 2 and image.shape[2] == 1:
image = image.reshape(image.shape[:2])
file_format = node_context.parameters['File format'].value
dest_path = dest.decode_path()
extensions = {'png': '.png', 'gif': '.gif'}
extension = extensions[file_format]
if dest_path.endswith(extension):
full_path = dest_path
else:
full_path = dest_path + extension
node_context.output['out'].encode_path(full_path)
io.imsave(full_path, image)
[docs]class ImageToTable(node.Node):
"""
Converts an image into a table with a single column.
"""
name = 'Convert Image to Table'
author = 'Mathias Broxvall'
copyright = '(C) 2017 System Engineering Software Society'
version = '0.1'
icon = 'image_to_table.svg'
description = 'Converts an image into a table with a single column'
nodeid = 'syip.convert_image_to_table'
tags = Tags(Tag.ImageProcessing.IO)
parameters = node.parameters()
parameters.set_string(
'Column name', value='image',
description='Name of column which image is converted into')
inputs = Ports([
Image('Input image', name='image'),
])
outputs = Ports([
Port.Table('Table containing image data', name='data'),
Port.Table('Table containing image meta data', name='meta'),
])
def execute(self, node_context):
image = node_context.input['image'].get_image()
column_name = node_context.parameters['Column name'].value
data_out = node_context.output['data']
meta_out = node_context.output['meta']
width = image.shape[0]
height = image.shape[1]
channels = 1 if len(image.shape) < 3 else image.shape[2]
data_out.set_column_from_array(
column_name, image.reshape(width * height * channels))
meta_out.set_column_from_array('width', np.array([width]))
meta_out.set_column_from_array('height', np.array([height]))
meta_out.set_column_from_array('channels', np.array([channels]))
[docs]class ImageToTable2D(node.Node):
"""
Converts first channel of image into a 2D table with X along columns and
Y along rows.
"""
name = 'Convert Image to 2D Table'
author = 'Mathias Broxvall'
copyright = '(C) 2017 System Engineering Software Society'
version = '0.1'
icon = 'image_to_table.svg'
description = (
'Converts first channel of image into a 2D table with X along columns and '
'Y along rows.')
nodeid = 'syip.convert_image_to_table_2d'
tags = Tags(Tag.ImageProcessing.IO)
parameters = node.parameters()
inputs = Ports([
Image('Input image', name='image'),
])
outputs = Ports([
Port.Table('Table containing image data', name='data'),
])
def execute(self, node_context):
image = node_context.input['image'].get_image()
data_out = node_context.output['data']
width = image.shape[0]
height = image.shape[1]
if len(image.shape) >= 3:
image = image[:,:,0]
for col in range(height):
data_out.set_column_from_array(
'Y{}'.format(col), image[:,col])
[docs]class TableToImage(node.Node):
"""
Converts a table into an image using a column each for: data, image width,
image height and image channels.
"""
name = 'Convert Table to Image'
author = 'Mathias Broxvall'
copyright = '(C) 2017 System Engineering Software Society'
version = '0.1'
icon = 'image_from_table.svg'
description = ('Converts a table into an image, using columns for data, '
'image width, image height and image channels.')
nodeid = 'syip.convert_table_to_image'
tags = Tags(Tag.ImageProcessing.IO)
parameters = node.parameters()
parameters.set_string(
'Data column', label='Data column name', value='image',
description='Name of image data column in input table')
parameters.set_string(
'Width column', label='Width column name', value='width',
description='Name of image width column in input table')
parameters.set_string(
'Height column', label='Height column name', value='height',
description='Name of image height column in input table')
parameters.set_string(
'Channels column', label='Channels column name',
value='channels',
description='Name of image channels column in input table')
inputs = Ports([
Port.Table('Table containing image data', name='data'),
Port.Table('Table containing image meta data', name='meta'),
])
outputs = Ports([
Image('Input image', name='image'),
])
def execute(self, node_context):
data = node_context.input['data'].get_column_to_array(
node_context.parameters['Data column'].value)
width = node_context.input['meta'].get_column_to_array(
node_context.parameters['Width column'].value)[0]
height = node_context.input['meta'].get_column_to_array(
node_context.parameters['Height column'].value)[0]
channels = node_context.input['meta'].get_column_to_array(
node_context.parameters['Channels column'].value)[0]
im = data.reshape((width, height, channels))
node_context.output['image'].set_image(im)
[docs]class Table2DToImage(node.Node):
"""
Converts a 2D table into a grayscale image, using columns as X and rows as Y positions.
"""
name = 'Convert 2D Table to Image'
author = 'Mathias Broxvall'
copyright = '(C) 2017 System Engineering Software Society'
version = '0.1'
icon = 'image_from_table.svg'
description = (
'Converts a 2D table into a grayscale image, using columns as X and '
'rows as Y positions.')
nodeid = 'syip.convert_table2d_to_image'
tags = Tags(Tag.ImageProcessing.IO)
parameters = node.parameters()
inputs = Ports([
Port.Table('Table containing image data', name='data'),
])
outputs = Ports([
Image('Input image', name='image'),
])
def execute(self, node_context):
tbl = node_context.input['data']
data = np.array(
[tbl.get_column_to_array(colname) for colname in tbl.column_names()]).T
node_context.output['image'].set_image(data)