Mercurial > repos > imgteam > image_math
comparison image_math.py @ 0:33b2ca53a566 draft
planemo upload for repository https://github.com/BMCV/galaxy-image-analysis/tree/master/tools/image_math commit b356d76025941b691c156f8ff931cd759d35b107
| author | imgteam |
|---|---|
| date | Sat, 09 Mar 2024 22:04:19 +0000 |
| parents | |
| children | 48fa3ac55df2 |
comparison
equal
deleted
inserted
replaced
| -1:000000000000 | 0:33b2ca53a566 |
|---|---|
| 1 import argparse | |
| 2 import ast | |
| 3 import operator | |
| 4 | |
| 5 import numpy as np | |
| 6 import skimage.io | |
| 7 | |
| 8 | |
| 9 supported_operators = { | |
| 10 ast.Add: operator.add, | |
| 11 ast.Sub: operator.sub, | |
| 12 ast.Mult: operator.mul, | |
| 13 ast.Div: operator.truediv, | |
| 14 ast.FloorDiv: operator.floordiv, | |
| 15 ast.Pow: operator.pow, | |
| 16 ast.USub: operator.neg, | |
| 17 } | |
| 18 | |
| 19 | |
| 20 supported_functions = { | |
| 21 'sqrt': np.sqrt, | |
| 22 'abs': abs, | |
| 23 } | |
| 24 | |
| 25 | |
| 26 def eval_ast_node(node, inputs): | |
| 27 """ | |
| 28 Evaluates a node of the syntax tree. | |
| 29 """ | |
| 30 | |
| 31 # Numeric constants evaluate to numeric values. | |
| 32 if isinstance(node, ast.Constant): | |
| 33 assert type(node.value) in (int, float) | |
| 34 return node.value | |
| 35 | |
| 36 # Variables are looked up from the inputs and resolved. | |
| 37 if isinstance(node, ast.Name): | |
| 38 assert node.id in inputs.keys() | |
| 39 return inputs[node.id] | |
| 40 | |
| 41 # Binary operators are evaluated based on the `supported_operators` dictionary. | |
| 42 if isinstance(node, ast.BinOp): | |
| 43 assert type(node.op) in supported_operators.keys(), node.op | |
| 44 op = supported_operators[type(node.op)] | |
| 45 return op(eval_ast_node(node.left, inputs), eval_ast_node(node.right, inputs)) | |
| 46 | |
| 47 # Unary operators are evaluated based on the `supported_operators` dictionary. | |
| 48 if isinstance(node, ast.UnaryOp): | |
| 49 assert type(node.op) in supported_operators.keys(), node.op | |
| 50 op = supported_operators[type(node.op)] | |
| 51 return op(eval_ast_node(node.operand, inputs)) | |
| 52 | |
| 53 # Function calls are evaluated based on the `supported_functions` dictionary. | |
| 54 if isinstance(node, ast.Call): | |
| 55 assert len(node.args) == 1 and len(node.keywords) == 0 | |
| 56 assert node.func.id in supported_functions.keys(), node.func.id | |
| 57 func = supported_functions[node.func.id] | |
| 58 return func(eval_ast_node(node.args[0], inputs)) | |
| 59 | |
| 60 # The node is unsupported and could not be evaluated. | |
| 61 raise TypeError(f'Unsupported node type: "{node}"') | |
| 62 | |
| 63 | |
| 64 def eval_expression(expr, inputs): | |
| 65 return eval_ast_node(ast.parse(expr, mode='eval').body, inputs) | |
| 66 | |
| 67 | |
| 68 if __name__ == '__main__': | |
| 69 | |
| 70 parser = argparse.ArgumentParser() | |
| 71 parser.add_argument('--expression', type=str, required=True) | |
| 72 parser.add_argument('--output', type=str, required=True) | |
| 73 parser.add_argument('--input', default=list(), action='append', required=True) | |
| 74 args = parser.parse_args() | |
| 75 | |
| 76 inputs = dict() | |
| 77 im_shape = None | |
| 78 for input in args.input: | |
| 79 name, filepath = input.split(':') | |
| 80 im = skimage.io.imread(filepath) | |
| 81 assert name not in inputs, 'Input name "{name}" is ambiguous.' | |
| 82 inputs[name] = im | |
| 83 if im_shape is None: | |
| 84 im_shape = im.shape | |
| 85 else: | |
| 86 assert im.shape == im_shape, 'Input images differ in size and/or number of channels.' | |
| 87 | |
| 88 result = eval_expression(args.expression, inputs) | |
| 89 | |
| 90 skimage.io.imsave(args.output, result) |
