source: trunk/src/Detection/lutz_detect.cc @ 232

Last change on this file since 232 was 232, checked in by Matthew Whiting, 17 years ago

Large raft of changes. Most are minor ones related to fixing up the use of std::string and std::vector (whether they are declared as using, or not...). Other changes include:

  • Moving the reconstruction filter class Filter into its own header/implementation files filter.{hh,cc}. As a result, the atrous.cc file is removed, but atrous.hh remains with just the function prototypes.
  • Incorporating a Filter object into the Param set, so that the reconstruction routines can see it without the messy "extern" call. The define() function is now called in both the Param() and Param::readParams() functions, and no longer in the main body.
  • Col functions in columns.cc moved into the Column namespace, while the template function printEntry is moved into the columns.hh file -- it would not compile on delphinus with it in the columns.cc, even though all the implementations were present.
  • Improved the introductory section of the Guide, with a bit more detail about each of the execution steps. This way the reader can read this section and have a reasonably good idea about what is happening.
  • Other minor changes to the Guide.
File size: 7.0 KB
Line 
1#include <Cubes/cubes.hh>
2#include <Detection/detection.hh>
3#include <vector>
4
5enum STATUS { NONOBJECT, OBJECT, COMPLETE, INCOMPLETE };
6enum ROW { PRIOR=0, CURRENT};
7enum NULLS { NULLSTART=-1, NULLMARKER=45}; //ASCII 45 = '-' --> eases printing in case of debugging
8
9/**
10 * Local class to manage locating detections.
11 * Keeps a track of a detection, as well as the start and finish
12 * locations of the detection on the current row.
13 */
14class Object{
15public:
16  Object(){start=NULLSTART; end=NULLSTART;};
17  int start; ///< Pixel on the current row where the detection starts.
18  int end;   ///< Pixel on the current row where the detection finishes.
19  Detection info; ///< Collection of detected pixels.
20};
21
22void Image::lutz_detect()
23{
24/**
25 *  A detection algorithm for 2-dimensional images based on that of
26 *  Lutz (1980).
27 * 
28 *  The image is raster-scanned, and searched row-by-row. Objects
29 *  detected in each row are compared to objects in subsequent rows,
30 *  and combined if they are connected (in an 8-fold sense).
31 *
32 *  Note that "detected" here means according to the
33 *  Image::isDetection(long,long) function.
34 *
35 *  Upon return, the detected objects are stored in the
36 *  Image::objectList vector.
37 *
38 */
39
40  // Allocate necessary arrays.
41  STATUS *status   = new STATUS[2];
42  Detection *store = new Detection[this->axisDim[0]+1];
43  char *marker     = new char[this->axisDim[0]+1];
44  for(int i=0; i<(this->axisDim[0]+1); i++) marker[i] = NULLMARKER;
45  std::vector<Object>  *oS    = new std::vector<Object>;
46  std::vector<STATUS> *psS    = new std::vector<STATUS>;
47
48  Pixel *pix = new Pixel;
49
50  for(int posY=0;posY<(this->axisDim[1]+1);posY++){
51    // Loop over each row -- consider rows one at a time
52   
53    status[PRIOR] = COMPLETE;
54    status[CURRENT] = NONOBJECT;
55
56    pix->setY(posY);
57
58    for(int posX=0;posX<(this->axisDim[0]+1);posX++){
59      // Now the loop for a given row, looking at each column individually.
60
61      char currentMarker = marker[posX];
62      marker[posX] = NULLMARKER;
63      pix->setX(posX);
64
65      bool isObject = false;
66      if((posX<this->axisDim[0])&&(posY<this->axisDim[1])){
67        // if we are in the original image
68        isObject = this->isDetection(posX,posY);
69        pix->setF( this->array[posY*this->axisDim[0] + posX] );
70      }
71      // else we're in the padding row/col and isObject=FALSE;
72
73      //
74      // ------------------------------ START SEGMENT ------------------------
75      // If the current pixel is object and the previous pixel is not, then
76      // start a new segment.
77      // If the pixel touches an object on the prior row, the marker is either
78      // an S or an s, depending on whether the object has started yet.
79      // If it doesn't touch a prior object, this is the start of a completly
80      // new object on this row.
81      //
82      if ( (isObject) && (status[CURRENT] != OBJECT) ){
83
84        status[CURRENT] = OBJECT;
85        if(status[PRIOR] == OBJECT){
86         
87          if(oS->back().start==NULLSTART){
88            marker[posX] = 'S';
89            oS->back().start = posX;
90          }
91          else  marker[posX] = 's';
92        }
93        else{
94          psS->push_back(status[PRIOR]);  //PUSH PS onto PSSTACK;
95          marker[posX] = 'S';
96          oS->resize(oS->size()+1);        //PUSH OBSTACK;
97          oS->back().start = posX;
98
99          status[PRIOR] = COMPLETE;
100        }
101      }
102
103      //
104      // ------------------------------ PROCESS MARKER -----------------------
105      // If the current marker is not blank, then we need to deal with it.
106      // Four cases:
107      //   S --> start of object on prior row. Push priorStatus onto PSSTACK
108      //         and set priorStatus to OBJECT
109      //   s --> start of a secondary segment of object on prior row.
110      //         If current object joined, pop PSSTACK and join the objects.
111      //         Set priorStatus to OBJECT.
112      //   f --> end of a secondary segment of object on prior row.
113      //         Set priorStatus to INCOMPLETE.
114      //   F --> end of object on prior row. If no more of the object is to
115      //          come (priorStatus=COMPLETE), then finish it and output data.
116      //         Add to list, but only if it has more than the minimum number
117      //           of pixels.
118      //
119      if(currentMarker != NULLMARKER){
120
121        if(currentMarker == 'S'){
122          psS->push_back(status[PRIOR]);      // PUSH PS onto PSSTACK
123          if(status[CURRENT] == NONOBJECT){
124            psS->push_back(COMPLETE);         // PUSH COMPLETE ONTO PSSTACK;
125            oS->resize(oS->size()+1);          // PUSH OBSTACK;
126            oS->back().info = store[posX];
127          }
128          else oS->back().info.addAnObject( store[posX] );
129         
130          status[PRIOR] = OBJECT;
131        }
132
133        /*---------*/
134        if(currentMarker == 's'){
135
136          if( (status[CURRENT] == OBJECT) && (status[PRIOR] == COMPLETE) ){
137            status[PRIOR] = psS->back();
138            psS->pop_back();                   //POP PSSTACK ONTO PS
139
140//          oS->at(oS->size()-2).info.addAnObject( oS->back().info );
141//          if(oS->at(oS->size()-2).start == NULLSTART) oS->at(oS->size()-2).start = oS->back().start;
142//          else marker[oS->back().start] = 's';
143            (*oS)[oS->size()-2].info.addAnObject( oS->back().info );
144            if((*oS)[oS->size()-2].start == NULLSTART)
145              (*oS)[oS->size()-2].start = oS->back().start;
146            else marker[oS->back().start] = 's';
147
148            oS->pop_back();
149          }
150
151          status[PRIOR] = OBJECT;
152        }
153
154        /*---------*/
155        if(currentMarker == 'f') status[PRIOR] = INCOMPLETE;
156
157        /*---------*/
158        if(currentMarker == 'F') {
159
160          status[PRIOR] = psS->back();
161          psS->pop_back();                    //POP PSSTACK ONTO PS
162
163          if( (status[CURRENT] == NONOBJECT) && (status[PRIOR] == COMPLETE) ){
164
165            if(oS->back().start == NULLSTART){ // object completed
166              if(oS->back().info.getSize() >= this->minSize){
167                // is it big enough?
168                oS->back().info.calcParams(); // work out midpoints, fluxes etc
169                this->addObject(oS->back().info);
170              }
171            }
172            else{
173              marker[ oS->back().end ] = 'F';
174              store[ oS->back().start ] = oS->back().info;
175            }
176
177            oS->pop_back();
178
179            status[PRIOR] = psS->back();
180            psS->pop_back();
181          }
182        }
183
184      } // end of PROCESSMARKER section ( if(currentMarker!=NULLMARKER) )
185
186      if (isObject){
187        oS->back().info.addPixel(*pix);
188      }
189      else{
190        //
191        // ----------------------------- END SEGMENT -------------------------
192        // If the current pixel is background and the previous pixel was an
193        // object, then finish the segment.
194        // If the prior status is COMPLETE, it's the end of the final segment
195        // of the object section.
196        // If not, it's end of the segment, but not necessarily the section.
197        //
198        if ( status[CURRENT] == OBJECT) {
199
200          status[CURRENT] = NONOBJECT;
201
202          if(status[PRIOR] != COMPLETE){
203            marker[posX] = 'f';
204            oS->back().end = posX;
205          }
206          else{
207            status[PRIOR] = psS->back();
208            psS->pop_back();                   //POP PSSTACK onto PS;
209            marker[posX] = 'F';
210            store[ oS->back().start ] = oS->back().info;
211            oS->pop_back();
212          }
213        }
214       
215      } //-> end of END SEGMENT else{ clause
216
217    }//-> end of loop over posX
218
219  }//-> end of loop over posY
220
221  // clean up and remove declared arrays
222  delete [] marker;
223  delete oS;
224  delete psS;
225  delete [] store;
226  delete [] status;
227  delete pix;
228
229}
Note: See TracBrowser for help on using the repository browser.