Source code for node_perspective
# This file is part of Sympathy for Data.
# Copyright (c) 2018, Combine Control Systems AB
#
# SYMPATHY FOR DATA COMMERCIAL LICENSE
# You should have received a link to the License with Sympathy for Data.
import numpy as np
from sympathy.api import node
from sympathy.api.exceptions import SyDataError, SyConfigurationError
from sympathy.api.nodeconfig import Port, Ports, Tag, Tags, adjust
from sylib.imageprocessing.image import ImagePort
from sympathy.utils.pip_util import import_optional
def _cv2():
return import_optional("cv2", group="opencv")
[docs]
class PerspectiveTransform(node.Node):
"""
Performs a perspective transform in an image by mapping four points
(atleast 3 non-colinear) in the input image to specific corresponding
points in the output image.
The input table should have exactly four rows and four columns. Two of
the columns give the XY coordinates of an input point and the other two
columns the corresponding point in the output image.
The result is an image after applying the perspective transform implied by
the given points.
"""
name = 'Perspective Transform'
author = 'Mathias Broxvall'
nodeid = 'com.sympathyfordata.imageanalysis.perspective_transform'
icon = 'image_perspective_transform.svg'
description = (
'Performs a perspective transform in an image by mapping four points '
'(atleast 3 non-colinear) in the input image to specific corresponding'
' points in the output image'
)
tags = Tags(Tag.ImageProcessing.ImageManipulation)
inputs = Ports([
ImagePort('image to transform', name='image'),
Port.Table('Table mapping four coordinates', name='coords')
])
outputs = Ports([
ImagePort('Result', name='result'),
])
parameters = node.parameters()
parameters.set_string(
'xbefore', label='X column before',
description='Column containing X coordinates before transform',
value='', editor=node.editors.combo_editor(options=[], edit=True))
parameters.set_string(
'ybefore', label='Y column before',
description='Column containing Y coordinates before transform',
value='', editor=node.editors.combo_editor(options=[], edit=True))
parameters.set_string(
'xafter', label='X column after',
description='Column containing X coordinates after transform',
value='', editor=node.editors.combo_editor(options=[], edit=True))
parameters.set_string(
'yafter', label='Y column after',
description='Column containing Y coordinates after transform',
value='', editor=node.editors.combo_editor(options=[], edit=True))
def adjust_parameters(self, node_context):
names = node_context.input['coords'].column_names()
try:
if node_context.parameters['xbefore'].value == '':
node_context.parameters['xbefore'].value = names[0]
if node_context.parameters['ybefore'].value == '':
node_context.parameters['ybefore'].value = names[1]
if node_context.parameters['xafter'].value == '':
node_context.parameters['xafter'].value = names[2]
if node_context.parameters['yafter'].value == '':
node_context.parameters['yafter'].value = names[3]
except Exception:
pass
adjust(node_context.parameters['xbefore'],
node_context.input['coords'])
adjust(node_context.parameters['ybefore'],
node_context.input['coords'])
adjust(node_context.parameters['xafter'],
node_context.input['coords'])
adjust(node_context.parameters['yafter'],
node_context.input['coords'])
def execute(self, node_context):
params = node_context.parameters
image = node_context.input['image'].get_image()
coords_table = node_context.input['coords']
xbefore = params['xbefore'].value
ybefore = params['ybefore'].value
xafter = params['xafter'].value
yafter = params['yafter'].value
for name in [xbefore, ybefore, xafter, yafter]:
if name not in coords_table.column_names():
raise SyConfigurationError(
'Invalid column name "{}" in configuration, column does '
'not exist in input table'.format(name))
xbefore = coords_table[xbefore]
ybefore = coords_table[ybefore]
xafter = coords_table[xafter]
yafter = coords_table[yafter]
before = np.float32(list(zip(xbefore, ybefore)))
after = np.float32(list(zip(xafter, yafter)))
try:
matrix = _cv2().getPerspectiveTransform(before, after)
except _cv2().error as e:
raise SyDataError(
'Error creating perspective transformation from input points, '
'make sure you have 4 points of which 3 are non-colinear.\n'
'{}'.format(e)
) from e
im = _cv2().warpPerspective(image, matrix,
(image.shape[1], image.shape[0]))
node_context.output['result'].set_image(im)