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) |