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

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

Merging pixel-map-branch revisions 236:257 back into trunk.
The use of the PixelMap? functions is sorted now, so we put everything back into a uniform location.

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