SegmentProber.h
1 /*
2 
3 MIT License
4 
5 Copyright (c) 2017 FMI Open Development / Markus Peura, first.last@fmi.fi
6 
7 Permission is hereby granted, free of charge, to any person obtaining a copy
8 of this software and associated documentation files (the "Software"), to deal
9 in the Software without restriction, including without limitation the rights
10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 copies of the Software, and to permit persons to whom the Software is
12 furnished to do so, subject to the following conditions:
13 
14 The above copyright notice and this permission notice shall be included in all
15 copies or substantial portions of the Software.
16 
17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 SOFTWARE.
24 
25 */
26 /*
27 Part of Rack development has been done in the BALTRAD projects part-financed
28 by the European Union (European Regional Development Fund and European
29 Neighbourhood Partnership Instrument, Baltic Sea Region Programme 2007-2013)
30 */
31 #ifndef SEGMENT_PROBER_H
32 #define SEGMENT_PROBER_H
33 
34 #include <drain/image/ProbingControl.h> // Control
35 #include <sstream>
36 #include <ostream>
37 
38 #include "drain/util/ReferenceMap.h"
39 #include "CoordinateHandler.h"
40 #include "FilePng.h"
41 
42 
43 namespace drain
44 {
45 namespace image
46 {
47 
48 
50 
57 template <class S, class D>
59 
60 public:
61 
62  SegmentProberConf(S anchorMin=1, S anchorMax=255.0, D markerValue = 1) : anchor(anchorMin, anchorMax), markerValue(markerValue){
63  link("anchor", this->anchor.tuple(), "intensity");
64  //link("anchorMin", this->anchorMin = anchorMin, "intensity");
65  //link("anchorMax", this->anchorMax = anchorMax, "intensity");
66  link("marker", this->markerValue, "marker not universal?");
67  }
68 
69  SegmentProberConf(const SegmentProberConf & conf) : anchor(conf.anchor), markerValue(conf.markerValue){
70  // link("anchor", this->anchor.tuple(), "intensity");
71  copyStruct(conf, conf, *this);
72  }
73 
74  Range<S> anchor;
75 
78 
80  inline
81  bool isValidIntensity(S x) const {
82  return anchor.contains(x);
83  //return (x >= anchorMin) && (x <= anchorMax);
84  }
85 
86 
87 };
88 
90 
99 template <class S, class D, class C>
101 
102 protected:
103 
104  SimpleProberControl basicControl;
105 
106 public:
107 
108  ProberControl & control;
109 
110  typedef S src_t;
111  typedef D dst_t;
112  typedef C conf_t;
113 
114  conf_t conf;
115 
116  SegmentProber(const Channel &s) : control(basicControl), src(s), dst(NULL){
117  init();
118  };
119 
120  SegmentProber(const Channel &s, Channel &d) : control(basicControl), src(s), dst(&d) {
121  control.markerImage.setGeometry(s.getGeometry().area);
122  init();
123  };
124 
125  virtual
126  ~SegmentProber(){};
127 
129  void setDst(Channel & d){
130  dst = &d;
131  }
132 
133  /*
134  void setParams(const C & conf){
135  this->conf = conf;
136  // init()
137  }
138  */
139 
141  /*
142  void setParams(src_t min, src_t max, dst_t fillValue){
143  anchorMin = min;
144  anchorMax = max;
145  value = fillValue;
146  }
147  */
148 
150  virtual
151  void init(){
152 
153  drain::Logger mout(getImgLog(), __FILE__, __FUNCTION__);
154  control.handler.set(src.getGeometry(), src.getCoordinatePolicy());
155  // src.adjustCoordinateHandler(handler);
156  mout.debug(control.handler );
157  mout.debug2(src );
158  if (dst){
159  mout.debug2(*dst );
160  }
161 
162  }
163 
164 
166 
170  void scan(){
171 
172  drain::Logger mout(getImgLog(), __FILE__, __FUNCTION__);
173 
174  const CoordinatePolicy & cp = control.handler.getPolicy();
175  bool HORZ_MODE = ((cp.xUnderFlowPolicy != EdgePolicy::POLAR) && (cp.xOverFlowPolicy != EdgePolicy::POLAR));
176 
177  if (HORZ_MODE){
178  mout.debug("Horz Probe");
179  for (size_t i=0; i<src.getWidth(); ++i){
180  for (size_t j=0; j<src.getHeight(); ++j){
181  probe(i,j, true);
182  //probeH(i,j);
183  /*
184  clear();
185  if (handler.validate(i, j)){
186  scanHorzProbeVert(i,j);
187  }*/
188  }
189  }
190  }
191  else {
192  mout.debug("Vert Probe");
193  for (size_t j=0; j<src.getHeight(); ++j){
194  for (size_t i=0; i<src.getWidth(); ++i){
195  probe(i,j, false);
196  /*clear();
197  if (handler.validate(i, j)){
198  scanVertProbeHorz(i,j);
199  }
200  */
201  }
202  }
203  }
204  }
205 
206 
208  void probe(int i, int j, bool HORIZONTAL){
209 
210 
211  clear();
212  if (control.handler.validate(i, j)){
213  /*
214  if (isValidPixel(i,j)){
215  Logger mout(getImgLog(), "SegmentProber", __FUNCTION__);
216  mout.warn("accept: " , i , ',' , j , "\t=" , src.get<double>(i,j) , '\t' , dst->get<double>(i,j) );
217  }
218  */
219  if (HORIZONTAL)
220  scanHorzProbeVert(i,j);
221  else
222  scanVertProbeHorz(i,j);
223  }
224 
225  };
226 
227 
228 // consider protected:
229 
230  const Channel & src;
231  Channel *dst;
232 
233  // CoordinateHandler2D handler;
234 
235 
236 
238  inline
239  bool isValidPixel(int i, int j) const {
240  return (isValidSegment(i,j) && !isVisited(i,j));
241  }
242 
244 
251  virtual
252  bool isValidSegment(int i, int j) const = 0;
253  //return (src.get<src_t>(i,j) > 0);
254  //return (src.get<src_t>(i,j) >= anchorMin) && (src.get<src_t>(i,j) <= anchorMax);
255 
257  /*
258  virtual inline
259  bool isValidSegment(int i, int j) const {
260  return conf.isValidIntensity(src.get<src_t>(i,j));
261  }
262  */
263 
264 protected:
265 
267  virtual inline
268  bool isValidMove(int i0, int j0, int i, int j) const {
269  return true;
270  }
271 
272 
274  virtual inline
275  void update(int i, int j){
276  };
277 
278 
280 
289  virtual inline
290  void visit(int i, int j) {
291 
292  update(i, j);
293 
295  dst->put(i,j, 1);
296 
297  }
298 
299 protected:
300 
302 
305  virtual
306  void clear(){};
307 
308 
310 
312  virtual inline
313  bool isVisited(int i, int j) const {
314  return (dst->get<D>(i,j) != 0);
315  }
316 
317 
318 
320  template <int DI, int DJ>
321  inline
322  bool move(int & i, int & j){ //, int DI, int DJ) {
323 
324  // Save
325  const int i0 = i;
326  const int j0 = j;
327 
328  i += DI;
329  j += DJ;
330 
331  // Drop isValidSegment
332  if (control.handler.validate(i,j)){ // must be first, changes coords
333  if (isValidPixel(i,j))
334  if (isValidMove(i0,j0, i,j))
335  return true;
336  }
337 
338  // restore orig
339  i = i0;
340  j = j0;
341  return false;
342 
343  }
344 
345 
346 
347 
349 
354  void scanHorzProbeVert(int i, int j) {
355 
356  if (!isValidPixel(i,j))
357  return;
358 
359  visit(i,j); // mark & update
360 
361  const int i0 = i;
362  const int j0 = j;
363 
365  int iEnd;
366  while (move<1,0>(i,j)){
367  visit(i,j);
368  }
369  iEnd = i;
370  // Now i2 is the maximum valid i coordinate.
371 
372  // Rewrite code: iMax should support wrapping, so 200...256...10.
373 
375  i=i0;
376  j=j0;
377  while (move<-1,0>(i,j)){
378  visit(i, j);
379  }
380  // Now i is the minimum valid i coordinate.
381 
382 
384  int i2, j2;
385  bool done = false;
386  //while (i != iEnd){
387  while (!done){
388 
389  done = (i == iEnd);
390 
391  i2 = i;
392  j2 = j-1;
393  if (control.handler.validate(i2, j2)){
394  if (isValidMove(i,j, i2,j2))
395  scanHorzProbeVert(i2,j2);
396  }
397 
398  i2 = i;
399  j2 = j+1;
400  if (control.handler.validate(i2, j2)){
401  if (isValidMove(i,j, i2,j2))
402  scanHorzProbeVert(i2,j2);
403  }
404 
405  ++i;
406  control.handler.validate(i, j); // check?
407 
408  }; // while (i != iEnd);
409 
410  }
411 
412 
413  void scanVertProbeHorz(int i, int j) {
414 
415  if (!isValidPixel(i,j))
416  return;
417 
418  visit(i,j); // mark & update
419 
420  const int i0 = i;
421  const int j0 = j;
422 
424  int jEnd;
425  while (move<0,1>(i,j)){
426  visit(i,j);
427  }
428  jEnd = j;
429  // Now jEnd is the last (~maximum) valid i coordinate.
430 
431  // Rewrite code?: iMax should support wrapping, so 200...256...10.
432 
434  i=i0;
435  j=j0;
436  while (move<0,-1>(i,j)){
437  visit(i, j);
438  }
439  // Now j is the first (~minimum) valid j coordinate.
440 
441 
443  int i2, j2;
444  bool done = false;
445  while (!done){
446  done = (j == jEnd);
447  j2 = j;
448  // Test left side
449  i2 = i-1;
450  if (control.handler.validate(i2, j2)){
451  if (isValidMove(i,j, i2,j2))
452  scanVertProbeHorz(i2,j2);
453  }
454  j2 = j;
455  // Test right side
456  i2 = i+1;
457  if (control.handler.validate(i2, j2)){
458  if (isValidMove(i,j, i2,j2))
459  scanVertProbeHorz(i2,j2);
460  }
461  ++j;
462  control.handler.validate(i, j); // check?
463  };
464 
465  }
466 
467 };
468 
469 
470 
471 template <class S, class D, class C>
472 std::ostream & operator<<(std::ostream & ostr, const SegmentProber<S,D,C> & prober){
473  /*
474  ostr << "value=" << (float)prober.value << ',';
475  ostr << "anchorMin=" << (float)prober.anchorMin << ',';
476  ostr << "anchorMax=" << (float)prober.anchorMax << ',';
477  ostr << "size=" << (float)prober.size << ',';
478  */
479  ostr << "conf: " << prober.conf << ", ";
480  //ostr << "width=" << (float)prober.width << ',';
481  //ostr << "height=" << (float)prober.height << ',';
482  ostr << "handler: " << prober.control.handler << ',';
483  //ostr << "p=" << prober.p;
484  return ostr;
485 }
486 
487 
488 
489 
490 class FillProber : public SegmentProber<int,int,SegmentProberConf<int, int> > {
491 
492 public:
493 
495 
497 
498  virtual inline
499  void visit(int i, int j) {
500  count++;
501  update(i, j);
502  dst->put(i,j, conf.markerValue);
503  }
504 
506 
508  virtual inline
509  bool isVisited(int i, int j) const {
510  return (dst->get<dst_t>(i,j) == conf.markerValue);
511  }
512 
513  virtual inline
514  bool isValidSegment(int i, int j) const {
515  return conf.isValidIntensity(src.get<src_t>(i,j));
516  }
517 
518  size_t count;
519 
520 };
521 
522 
523 class SizeProber : public SegmentProber<int,int,SegmentProberConf<int, int> > {
524 
525 public:
526 
528 
529  virtual inline
530  void clear(){
531  size = 0;
532  };
533 
534 
535  virtual inline
536  void visit(int i, int j) {
537  update(i, j);
538  dst->put(i,j, conf.markerValue);
539  }
540 
542 
544  virtual inline
545  bool isVisited(int i, int j) const {
546  return (dst->get<dst_t>(i,j) > 0);
547  }
548 
549 
551  virtual inline
552  void update(int i, int j){
553  ++size;
554  }
555 
556  virtual inline
557  bool isValidSegment(int i, int j) const {
558  return conf.isValidIntensity(src.get<src_t>(i,j));
559  }
560 
561  mutable size_t size; // Consider deriving SegmentProber => SegmentAreaProber
562 
563 
564 };
565 
566 
567 
568 
569 } // image::
570 } // drain::
571 
572 #endif /* SEGMENT_PROBER_H_ */
573 
574 
575 
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition: Log.h:308
Logger & debug(const TT &... args)
Public, yet typically used "internally", when TIMING=true.
Definition: Log.h:676
Logger & debug2(const TT &... args)
Debug information.
Definition: Log.h:686
Definition: ReferenceMap.h:207
void copyStruct(const ReferenceMap &m, const T &src, T &dst, extLinkPolicy policy=RESERVE)
Experimental. Copies references and values of a structure to another.
Definition: ReferenceMap.h:399
Image with static geometry.
Definition: ImageChannel.h:60
bool validate(Point2D< int > &p) const
Handles the coordinate, returning true if the position is reversible.
Definition: CoordinateHandler.h:223
Policies for coordinate underflows and overflows.
Definition: CoordinatePolicy.h:106
Definition: SegmentProber.h:490
virtual bool isValidSegment(int i, int j) const
Application dependent, to be redefined. Assumes checked coordinates.
Definition: SegmentProber.h:514
virtual bool isVisited(int i, int j) const
Experimental.
Definition: SegmentProber.h:509
virtual void visit(int i, int j)
Visiting a single pixel when not coming from any direction.
Definition: SegmentProber.h:499
void put(size_t i, T x)
Sets the intensity in location i to x. See \address.
Definition: ImageFrame.h:192
T get(size_t i) const
Gets the intensity at location i. See address().
Definition: ImageFrame.h:254
const CoordinatePolicy & getCoordinatePolicy() const
Coord policy.
Definition: ImageLike.h:167
virtual void setGeometry(size_t width, size_t height, size_t imageChannels=1, size_t alphaChannels=0)
Resizes the image, keeps the current type.
Definition: Image.h:95
Container for parameters of SegmentProber.
Definition: SegmentProber.h:58
bool isValidIntensity(S x) const
Criterion.
Definition: SegmentProber.h:81
D markerValue
"fill value", also dynamically changing visit marker?
Definition: SegmentProber.h:77
A recursive method for visiting pixels of a segment in an image.
Definition: SegmentProber.h:100
void scan()
A convenience function for traversing a whole image.
Definition: SegmentProber.h:170
void probe(int i, int j, bool HORIZONTAL)
Start probings.
Definition: SegmentProber.h:208
void scanHorzProbeVert(int i, int j)
A semi-recursive approach that turns the 2D recursion to 1D traversal + 1D recursion.
Definition: SegmentProber.h:354
virtual void update(int i, int j)
Application dependent operation performed in each segment location (i,j).
Definition: SegmentProber.h:275
virtual bool isVisited(int i, int j) const
Experimental.
Definition: SegmentProber.h:313
bool move(int &i, int &j)
Try to move; change coords in success, else keep them intact.
Definition: SegmentProber.h:322
bool isValidPixel(int i, int j) const
Returns isValidSegment(i,j) and !isVisited(i,j).
Definition: SegmentProber.h:239
virtual void init()
Fills the segment having intensity between min and max.
Definition: SegmentProber.h:151
void setDst(Channel &d)
Set new target channel. Needed in multichannel operations.
Definition: SegmentProber.h:129
virtual void clear()
Called before processing each segment. Compare with init(), which is called once for each image.
Definition: SegmentProber.h:306
virtual void visit(int i, int j)
Visiting a single pixel when not coming from any direction.
Definition: SegmentProber.h:290
void scanVertProbeHorz(int i, int j)
Definition: SegmentProber.h:413
virtual bool isValidMove(int i0, int j0, int i, int j) const
Application dependent, to be redefined. Note: assumes checked coordinates.
Definition: SegmentProber.h:268
virtual bool isValidSegment(int i, int j) const =0
Application dependent, to be redefined. Assumes checked coordinates.
Definition: SegmentProber.h:523
virtual bool isValidSegment(int i, int j) const
Application dependent, to be redefined. Assumes checked coordinates.
Definition: SegmentProber.h:557
virtual void update(int i, int j)
Application dependent operation performed in each segment location (i,j).
Definition: SegmentProber.h:552
virtual bool isVisited(int i, int j) const
Experimental.
Definition: SegmentProber.h:545
virtual void clear()
Called before processing each segment. Compare with init(), which is called once for each image.
Definition: SegmentProber.h:530
virtual void visit(int i, int j)
Visiting a single pixel when not coming from any direction.
Definition: SegmentProber.h:536
Definition: DataSelector.cpp:1277
Container for parameters of SegmentProber.
Definition: ProbingControl.h:60
Definition: ProbingControl.h:195