18#ifndef __filter_zclean_h__
19#define __filter_zclean_h__
26#include "filter/base.h"
43 template <
class HeaderType>
44 ZClean (
const HeaderType& in) :
59 template <
class HeaderType>
75 template <
class InputImageType,
class MaskType,
class OutputImageType>
76 void operator() (InputImageType& input, MaskType& spatial_prior, OutputImageType& output)
78 if (output.ndim() > 3)
84 INFO (
"creating intensity mask from input mask");
85 Dilate dilation_filter (spatial_prior);
86 dilation_filter.set_npass(2);
87 dilation_filter (spatial_prior, int_roi);
89 for (
auto l =
Loop (0,3) (int_roi); l; ++l) {
90 cnt += int_roi.value();
92 ssize_t cnt_lower = std::max<size_t>(10000,
std::floor(
fov_min * input.size(0) * input.size(1) * input.size(2)));
93 ssize_t cnt_upper =
std::floor(
fov_max * input.size(0) * input.size(1) * input.size(2));
94 float mad,
median, previous_mad, previous_median;
95 calculate_median_mad<Image<float>,
Image<bool>> (input, int_roi, cnt,
median, mad);
100 INFO (
"eroding intensity mask");
101 while (cnt >= cnt_lower) {
104 Erode erosion_filter (int_roi);
105 erosion_filter.set_npass(1);
106 erosion_filter (int_roi, int_roi);
108 for (
auto l =
Loop (0,3) (int_roi); l; ++l)
109 cnt += int_roi.value();
111 throw Exception (
"mask empty after erosion");
114 calculate_median_mad<Image<float>,
Image<bool>> (input, int_roi, cnt,
median, mad);
118 INFO (
"mad: " +
str(mad) +
", changed: "+
str((mad - previous_mad) / previous_mad));
119 INFO (
"FOV: " +
str(
float(cnt) / (input.size(0) * input.size(1) * input.size(2))));
121 INFO (
"cnt_upper - cnt: " +
str(cnt_upper - cnt));
122 if (
lower > 0.0 && ((
median + 2.5 * mad) - (previous_median + 2.5 * previous_mad)) < 0.0 && (cnt < cnt_upper))
129 for (
auto l =
Loop (0,3) (masked_image, input, int_roi); l; ++l) {
131 masked_image.value() = input.value();
137 INFO (
"intensity sample mask");
150 for (
auto l =
Loop (0,3) (input, int_roi); l; ++l) {
151 if (int_roi.value()) {
152 float z = (input.value() -
median) / mad;
155 assign_pos_of(input, 0, 3).to(eroded_zscore_image);
159 int_roi.value() = good;
161 assign_pos_of(input, 0, 3).to(eroded_zscore_image);
162 eroded_zscore_image.value() =
NaN;
167 calculate_median_mad<Image<float>,
Image<bool>> (input, int_roi, cnt,
median, mad);
171 INFO(
"mad: " +
str(mad) +
", changed: " +
str((mad - previous_mad)));
173 float change =
MR::abs(
median - previous_median) / previous_mad;
174 INFO(
"convergence: "+
str(change));
184 WARN (
"likely not converged, setting lower to 0.0");
197 for (
auto l =
Loop (0,3) (input, mask, spatial_prior); l; ++l)
206 INFO (
"selecting largest ROI");
208 connected_filter.set_largest_only (
true);
209 connected_filter (mask, mask);
214 for (
auto l =
Loop (0,3) (mask); l; ++l)
215 mask.value() = !mask.value();
218 INFO (
"removing masked out islands");
220 connected_filter.set_largest_only (
true);
221 connected_filter (mask, mask);
228 for (
auto l =
Loop (0,3) (mask); l; ++l)
229 mask.value() = !mask.value();
232 Dilate dilation_filter (mask);
233 dilation_filter.set_npass(
bridge);
234 dilation_filter (mask, mask);
237 for (
auto l =
Loop (0,3) (mask); l; ++l)
238 mask.value() = !mask.value();
242 connected_filter.set_largest_only (
true);
243 connected_filter (mask, mask);
246 Dilate dilation_filter2 (mask);
247 dilation_filter2.set_npass(
bridge);
248 dilation_filter2 (mask, mask);
255 for (
auto l =
Loop (0,3) (mask, spatial_prior); l; ++l)
256 mask.value() = !mask.value() && spatial_prior.value();
260 float lo = std::max<float>(
median - 2.5 * mad,
lower);
261 float hi = std::min<float>(
median + 2.5 * mad,
upper);
262 for (
auto l =
Loop (0,3) (input, spatial_prior, mask, output); l; ++l) {
263 if (!spatial_prior.value())
265 float val = input.value();
268 output.value() = val;
272 output.value() = val;
290 void set_voxels_to_bridge (
size_t nvoxels)
304 template <
typename ImageType,
typename MaskType>
308 for (
auto l =
Loop (0,3) (mask, image); l; ++l) {
310 vals[idx++] = image.value();
311 assert (idx <= nvoxels);
314 for (
auto & v : vals)
static constexpr uint8_t Float32
a filter to dilate a mask
void calculate_median_mad(ImageType &image, MaskType &mask, size_t nvoxels, float &median, float &mad)
static Image scratch(const Header &template_header, const std::string &label="scratch image")
implements a progress meter to provide feedback to the user
constexpr I floor(const T x)
template function with cast to different type
FORCE_INLINE LoopAlongAxes Loop()
Container::value_type median(Container &list)
enable_if_image_type< ImageType, void >::type display(ImageType &x)
display the contents of an image in MRView (for debugging only)
constexpr std::enable_if< std::is_arithmetic< X >::value &&std::is_unsigned< X >::value, X >::type abs(X x)
std::string str(const T &value, int precision=0)
constexpr default_type NaN