|
16 | 16 | #
|
17 | 17 | # ==========================================================================*/
|
18 | 18 |
|
| 19 | +import enum |
19 | 20 | import re
|
20 | 21 | from typing import Optional, Union, Dict, Any, List, Tuple, Sequence, TYPE_CHECKING
|
21 | 22 | from sys import stderr as system_error_stream
|
|
104 | 105 | "dict_from_mesh",
|
105 | 106 | "pointset_from_dict",
|
106 | 107 | "dict_from_pointset",
|
| 108 | + "transform_from_dict", |
| 109 | + "dict_from_transform", |
107 | 110 | "transformwrite",
|
108 | 111 | "transformread",
|
109 | 112 | "search",
|
@@ -1012,6 +1015,144 @@ def dict_from_pointset(pointset: "itkt.PointSet") -> Dict:
|
1012 | 1015 | pointData=point_data_numpy,
|
1013 | 1016 | )
|
1014 | 1017 |
|
| 1018 | +def dict_from_transform(transform: "itkt.TransformBase") -> Dict: |
| 1019 | + import itk |
| 1020 | + |
| 1021 | + def update_transform_dict(current_transform): |
| 1022 | + current_transform_type = current_transform.GetTransformTypeAsString() |
| 1023 | + current_transform_type_split = current_transform_type.split('_') |
| 1024 | + component = itk.template(current_transform) |
| 1025 | + |
| 1026 | + in_transform_dict = dict() |
| 1027 | + in_transform_dict["name"] = current_transform.GetObjectName() |
| 1028 | + in_transform_dict["numberOfTransforms"] = 1 |
| 1029 | + |
| 1030 | + datatype_dict = {'double': itk.D, 'float': itk.F} |
| 1031 | + in_transform_dict["parametersValueType"] = python_to_js(datatype_dict[current_transform_type_split[1]]) |
| 1032 | + in_transform_dict["inDimension"] = int(current_transform_type_split[2]) |
| 1033 | + in_transform_dict["outDimension"] = int(current_transform_type_split[3]) |
| 1034 | + in_transform_dict["transformName"] = current_transform_type_split[0] |
| 1035 | + |
| 1036 | + # transformType field to be used for single transform object only. |
| 1037 | + # For composite transforms we lose the information for child transform objects. |
| 1038 | + data_type_dict = {itk.D: 'D', itk.F: 'F'} |
| 1039 | + mangle = data_type_dict[component[1][0]] |
| 1040 | + for p in component[1][1:]: |
| 1041 | + mangle += str(p) |
| 1042 | + in_transform_dict["transformType"] = mangle |
| 1043 | + |
| 1044 | + # To avoid copying the parameters for the Composite Transform as it is a copy of child transforms. |
| 1045 | + if 'Composite' not in current_transform_type_split[0]: |
| 1046 | + p = np.array(current_transform.GetParameters()) |
| 1047 | + in_transform_dict["parameters"] = p |
| 1048 | + |
| 1049 | + fp = np.array(current_transform.GetFixedParameters()) |
| 1050 | + in_transform_dict["fixedParameters"] = fp |
| 1051 | + |
| 1052 | + in_transform_dict["numberOfParameters"] = p.shape[0] |
| 1053 | + in_transform_dict["numberOfFixedParameters"] = fp.shape[0] |
| 1054 | + else: |
| 1055 | + in_transform_dict["parameters"] = np.array([]) |
| 1056 | + in_transform_dict["fixedParameters"] = np.array([]) |
| 1057 | + in_transform_dict["numberOfParameters"] = 0 |
| 1058 | + in_transform_dict["numberOfFixedParameters"] = 0 |
| 1059 | + |
| 1060 | + return in_transform_dict |
| 1061 | + |
| 1062 | + |
| 1063 | + dict_array = [] |
| 1064 | + transform_type = transform.GetTransformTypeAsString() |
| 1065 | + if 'CompositeTransform' in transform_type: |
| 1066 | + transform_dict = update_transform_dict(transform) |
| 1067 | + transform_dict["numberOfTransforms"] = transform.GetNumberOfTransforms() |
| 1068 | + |
| 1069 | + # Add the first entry for the composite transform |
| 1070 | + dict_array.append(transform_dict) |
| 1071 | + |
| 1072 | + # Rest follows the transforms inside the composite transform |
| 1073 | + # range is over-ridden so using this hack to create a list |
| 1074 | + for i, _ in enumerate([0]*transform.GetNumberOfTransforms()): |
| 1075 | + current_transform = transform.GetNthTransform(i) |
| 1076 | + dict_array.append(update_transform_dict(current_transform)) |
| 1077 | + else: |
| 1078 | + dict_array.append(update_transform_dict(transform)) |
| 1079 | + |
| 1080 | + return dict_array |
| 1081 | + |
| 1082 | +def transform_from_dict(transform_dict: Dict)-> "itkt.TransformBase": |
| 1083 | + import itk |
| 1084 | + |
| 1085 | + def set_parameters(transform, transform_parameters, transform_fixed_parameters): |
| 1086 | + o1 = transform.GetParameters() |
| 1087 | + o1.SetSize(transform_parameters.shape[0]) |
| 1088 | + for j, v in enumerate(transform_parameters): |
| 1089 | + o1.SetElement(j, v) |
| 1090 | + transform.SetParameters(o1) |
| 1091 | + |
| 1092 | + o2 = transform.GetFixedParameters() |
| 1093 | + o2.SetSize(transform_fixed_parameters.shape[0]) |
| 1094 | + for j, v in enumerate(transform_fixed_parameters): |
| 1095 | + o2.SetElement(j, v) |
| 1096 | + transform.SetFixedParameters(o2) |
| 1097 | + |
| 1098 | + |
| 1099 | + # For checking transforms which don't take additional parameters while instantiation |
| 1100 | + def special_transform_check(transform_name): |
| 1101 | + if '2D' in transform_name or '3D' in transform_name: |
| 1102 | + return True |
| 1103 | + |
| 1104 | + check_list = ['VersorTransform', 'QuaternionRigidTransform'] |
| 1105 | + for t in check_list: |
| 1106 | + if transform_name == t: |
| 1107 | + return True |
| 1108 | + return False |
| 1109 | + |
| 1110 | + # We only check for the first transform as composite similar to the |
| 1111 | + # convention followed in the itkTxtTransformIO.cxx |
| 1112 | + if 'CompositeTransform' in transform_dict[0]["transformName"]: |
| 1113 | + # Loop over all the transforms in the dictionary |
| 1114 | + transforms_list = [] |
| 1115 | + for i, _ in enumerate(transform_dict): |
| 1116 | + if transform_dict[i]["parametersValueType"] == "float32": |
| 1117 | + data_type = itk.F |
| 1118 | + else: |
| 1119 | + data_type = itk.D |
| 1120 | + |
| 1121 | + # No template parameter needed for transforms having 2D or 3D name |
| 1122 | + # Also for some selected transforms |
| 1123 | + if special_transform_check(transform_dict[i]["transformName"]): |
| 1124 | + transform_template = getattr(itk, transform_dict[i]["transformName"]) |
| 1125 | + transform = transform_template[data_type].New() |
| 1126 | + # Currently only BSpline Transform has 3 template parameters |
| 1127 | + # For future extensions the information will have to be encoded in |
| 1128 | + # the transformType variable. The transform object once added in a |
| 1129 | + # composite transform lose the information for other template parameters ex. BSpline. |
| 1130 | + # The Spline order is fixed as 3 here. |
| 1131 | + elif transform_dict[i]["transformName"] == 'BSplineTransform': |
| 1132 | + transform_template = getattr(itk, transform_dict[i]["transformName"]) |
| 1133 | + transform = transform_template[data_type, transform_dict[i]["inDimension"], 3].New() |
| 1134 | + else: |
| 1135 | + transform_template = getattr(itk, transform_dict[i]["transformName"]) |
| 1136 | + transform = transform_template[data_type, transform_dict[i]["inDimension"]].New() |
| 1137 | + |
| 1138 | + transform.SetObjectName(transform_dict[i]["name"]) |
| 1139 | + transforms_list.append(transform) |
| 1140 | + |
| 1141 | + # Obtain the first object which is composite transform object |
| 1142 | + # and add all the transforms in it. |
| 1143 | + transform = transforms_list[0] |
| 1144 | + for current_transform in transforms_list[1:]: |
| 1145 | + transform.AddTransform(current_transform) |
| 1146 | + else: |
| 1147 | + # For handling single transform objects we rely on itk.template |
| 1148 | + # because that way we can handle future extensions easily. |
| 1149 | + transform_template = getattr(itk, transform_dict[0]["transformName"]) |
| 1150 | + transform = getattr(transform_template, transform_dict[0]["transformType"]).New() |
| 1151 | + transform.SetObjectName(transform_dict[0]["name"]) |
| 1152 | + set_parameters(transform, transform_dict[0]["parameters"], transform_dict[0]["fixedParameters"]) |
| 1153 | + |
| 1154 | + return transform |
| 1155 | + |
1015 | 1156 | def image_intensity_min_max(image_or_filter: "itkt.ImageOrImageSource"):
|
1016 | 1157 | """Return the minimum and maximum of values in a image of in the output image of a filter
|
1017 | 1158 |
|
|
0 commit comments