21 #ifndef mia_internal_seededwatershed_hh
22 #define mia_internal_seededwatershed_hh
32 class TSeededWS :
public watershed_traits<dim>::Handler::Product
35 typedef typename watershed_traits<dim>::PNeighbourhood PNeighbourhood;
36 typedef typename PNeighbourhood::element_type::value_type MPosition;
37 typedef typename watershed_traits<dim>::Handler Handler;
38 typedef typename watershed_traits<dim>::FileHandler FileHandler;
39 typedef typename Handler::Product CFilter;
40 typedef typename FileHandler::Instance::DataKey DataKey;
41 typedef typename CFilter::Pointer PFilter;
42 typedef typename CFilter::Image CImage;
43 typedef typename CImage::Pointer PImage;
44 typedef typename CImage::dimsize_type Position;
47 TSeededWS(
const DataKey& mask_image, PNeighbourhood neighborhood,
48 bool with_borders,
bool input_is_gradient);
50 template <
template <
typename>
class Image,
typename T>
51 typename TSeededWS<dim>::result_type operator () (
const Image<T>& data)
const;
53 virtual PImage do_filter(
const CImage& image)
const;
55 DataKey m_label_image_key;
56 PNeighbourhood m_neighborhood;
62 class TSeededWSFilterPlugin:
public watershed_traits<dim>::Handler::Interface
65 typedef typename watershed_traits<dim>::PNeighbourhood PNeighbourhood;
66 typedef typename watershed_traits<dim>::Handler Handler;
67 typedef typename watershed_traits<dim>::FileHandler FileHandler;
68 typedef typename Handler::Product CFilter;
70 TSeededWSFilterPlugin();
72 virtual CFilter *do_create()
const;
73 virtual const std::string do_get_descr()
const;
74 std::string m_seed_image_file;
75 PNeighbourhood m_neighborhood;
77 bool m_input_is_gradient;
80 template <
template <
typename>
class Image,
typename T,
typename S,
typename N,
typename R,
int dim,
bool supported>
82 static R apply(
const Image<T>& image,
const Image<S>& seed, N n,
bool with_borders);
85 template <
template <
typename>
class Image,
typename T,
typename S,
typename N,
typename R,
int dim>
86 struct seeded_ws<Image, T, S, N, R, dim, false> {
87 static R apply(
const Image<T>& ,
const Image<S>& , N ,
bool )
89 throw create_exception<std::invalid_argument>(
"C2DRunSeededWS: seed data type '", __type_descr<S>::value,
"' not supported");
95 template <
template <
typename>
class Image,
typename T,
typename N,
typename R,
int dim>
96 struct dispatch_RunSeededWS :
public TFilter<R> {
98 dispatch_RunSeededWS(N neighborhood,
const Image<T>& image,
bool with_borders):
99 m_neighborhood(neighborhood),
101 m_with_borders(with_borders)
104 template <
typename S>
105 R operator () (
const Image<S>& seed)
const
107 const bool supported = std::is_integral<S>::value && !std::is_same<S, bool>::value;
108 return seeded_ws<Image, T, S, N, R, dim, supported>::apply(m_image, seed, m_neighborhood, m_with_borders);
111 const Image<T>& m_image;
116 template <
typename L,
typename Position>
117 struct PixelWithLocation {
123 template <
typename L,
typename Position>
124 bool operator < (
const PixelWithLocation<L, Position>& lhs,
const PixelWithLocation<L, Position>& rhs)
126 mia::less_then<Position> l;
127 return lhs.value > rhs.value ||
128 ( lhs.value == rhs.value && l(rhs.pos, lhs.pos));
131 template <
template <
typename>
class Image,
typename T,
typename S,
int dim>
132 class TRunSeededWatershed
135 typedef typename watershed_traits<dim>::PNeighbourhood PNeighbourhood;
136 typedef typename PNeighbourhood::element_type::value_type MPosition;
137 typedef typename watershed_traits<dim>::Handler Handler;
138 typedef typename Handler::Product CFilter;
139 typedef typename CFilter::Pointer PFilter;
140 typedef typename CFilter::Image CImage;
141 typedef typename CImage::Pointer PImage;
142 typedef typename CImage::dimsize_type Position;
145 TRunSeededWatershed(
const Image<T>& image,
const Image<S>& seed, PNeighbourhood neighborhood,
bool with_borders);
148 void add_neighborhood(
const PixelWithLocation<S, Position>& pixel);
149 const Image<T>& m_image;
150 const Image<S>& m_seed;
151 PNeighbourhood m_neighborhood;
152 Image<unsigned char> m_visited;
153 Image<unsigned char> m_stored;
156 std::priority_queue<PixelWithLocation<S, Position>> m_seeds;
161 template <
template <
typename>
class Image,
typename T,
typename S,
int dim>
162 TRunSeededWatershed<Image, T, S, dim>::TRunSeededWatershed(
const Image<T>& image,
const Image<S>& seed,
163 PNeighbourhood neighborhood,
bool with_borders):
166 m_neighborhood(neighborhood),
167 m_visited(seed.get_size()),
168 m_stored(seed.get_size()),
169 m_watershed(
std::numeric_limits<S>::max()),
170 m_with_borders(with_borders)
172 m_result =
new Image<S>(seed.get_size(), image);
173 m_presult.reset(m_result);
176 template <
template <
typename>
class Image,
typename T,
typename S,
int dim>
177 void TRunSeededWatershed<Image, T, S, dim>::add_neighborhood(
const PixelWithLocation<S, Position>& pixel)
179 PixelWithLocation<S, Position> new_pixel;
180 new_pixel.label = pixel.label;
181 bool hit_boundary =
false;
183 for (
auto i = m_neighborhood->begin(); i != m_neighborhood->end(); ++i) {
184 Position new_pos( pixel.pos + *i);
186 if (new_pos != pixel.pos && new_pos < m_seed.get_size()) {
187 if (!m_visited(new_pos)) {
188 if (!m_stored(new_pos) ) {
189 new_pixel.value = m_image(new_pos);
190 new_pixel.pos = new_pos;
191 m_seeds.push(new_pixel);
192 m_stored(new_pos) = 1;
195 hit_boundary |= (*m_result)(new_pos) != pixel.label &&
196 (*m_result)(new_pos) != m_watershed;
202 if (!m_visited(pixel.pos)) {
203 m_visited(pixel.pos) =
true;
204 (*m_result)(pixel.pos) = (m_with_borders && hit_boundary) ? m_watershed : pixel.label;
208 template <
template <
typename>
class Image,
typename T,
typename S,
int dim>
209 typename TRunSeededWatershed<Image, T, S, dim>::PImage
210 TRunSeededWatershed<Image, T, S, dim>::run()
213 auto iv = m_visited.begin();
214 auto is = m_seed.begin_range(Position::_0, m_seed.get_size());
215 auto es = m_seed.end_range(Position::_0, m_seed.get_size());
216 auto ir = m_result->begin();
217 auto ii = m_image.begin();
218 auto ist = m_stored.begin();
219 PixelWithLocation<S, Position> pixel;
227 pixel.pos = is.pos();
240 while (!m_seeds.empty()) {
241 auto p = m_seeds.top();
249 template <
template <
typename>
class Image,
typename T,
typename S,
typename N,
typename R,
int dim,
bool supported>
250 R seeded_ws<Image, T, S, N, R, dim, supported>::apply(
const Image<T>& image,
251 const Image<S>& seed, N neighborhood,
bool with_borders)
253 TRunSeededWatershed<Image, T, S, dim> ws(image, seed, neighborhood, with_borders);
258 TSeededWS<dim>::TSeededWS(
const DataKey& label_image_key, PNeighbourhood neighborhood,
bool with_borders,
bool input_is_gradient):
259 m_label_image_key(label_image_key),
260 m_neighborhood(neighborhood),
261 m_with_borders(with_borders)
264 if (!input_is_gradient)
265 m_togradnorm = Handler::instance().produce(
"gradnorm");
269 template <
template <
typename>
class Image,
typename T>
270 typename TSeededWS<dim>::result_type TSeededWS<dim>::operator () (
const Image<T>& data)
const
273 auto in_image_list = m_label_image_key.get();
275 if (!in_image_list || in_image_list->empty())
276 throw create_exception<std::runtime_error>(
"C2DSeededWS: no seed image could be loaded");
278 if (in_image_list->size() > 1)
279 cvwarn() <<
"C2DSeededWS:got more than one seed image. Ignoring all but first";
281 auto seed = (*in_image_list)[0];
283 if (seed->get_size() != data.get_size()) {
284 throw create_exception<std::invalid_argument>(
"C2DSeededWS: seed and input differ in size: seed ", seed->get_size()
285 ,
", input ", data.get_size());
288 dispatch_RunSeededWS<Image, T, PNeighbourhood, PImage, dim> ws(m_neighborhood, data, m_with_borders);
293 typename TSeededWS<dim>::PImage TSeededWS<dim>::do_filter(
const CImage& image)
const
298 auto grad = m_togradnorm->filter(image);
307 TSeededWSFilterPlugin<dim>::TSeededWSFilterPlugin():
308 Handler::Interface(
"sws"),
309 m_with_borders(false),
310 m_input_is_gradient(false)
313 "seed input image containing the lables for the initial regions"));
314 this->add_parameter(
"n",
make_param(m_neighborhood,
"sphere:r=1",
false,
"Neighborhood for watershead region growing"));
315 this->add_parameter(
"mark",
new CBoolParameter(m_with_borders,
false,
"Mark the segmented watersheds with a special gray scale value"));
316 this->add_parameter(
"grad",
new CBoolParameter(m_input_is_gradient,
false,
"Interpret the input image as gradient. "));
320 typename TSeededWSFilterPlugin<dim>::CFilter *TSeededWSFilterPlugin<dim>::do_create()
const
322 auto seed = FileHandler::instance().load_to_pool(m_seed_image_file);
323 return new TSeededWS<dim>(seed, m_neighborhood, m_with_borders, m_input_is_gradient);
327 const std::string TSeededWSFilterPlugin<dim>::do_get_descr()
const
329 return "seeded watershead. The algorithm extracts exactly so "
330 "many reagions as initial labels are given in the seed image.";