source: trunk/src/ATrous/ReconSearch.cc @ 582

Last change on this file since 582 was 582, checked in by MatthewWhiting, 15 years ago

Separating out the functionality of the searching from the Image classes, making the search functions more generic. They now accept just a vector of bools, indicating "detection" or not. The calling functions in the classes have been renamed to findSources1D (was spectrumDetect()) and findSources2D (was lutz_detect()).

File size: 14.1 KB
Line 
1// -----------------------------------------------------------------------
2// ReconSearch.cc: Searching a wavelet-reconstructed cube.
3// -----------------------------------------------------------------------
4// Copyright (C) 2006, Matthew Whiting, ATNF
5//
6// This program is free software; you can redistribute it and/or modify it
7// under the terms of the GNU General Public License as published by the
8// Free Software Foundation; either version 2 of the License, or (at your
9// option) any later version.
10//
11// Duchamp is distributed in the hope that it will be useful, but WITHOUT
12// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14// for more details.
15//
16// You should have received a copy of the GNU General Public License
17// along with Duchamp; if not, write to the Free Software Foundation,
18// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
19//
20// Correspondence concerning Duchamp may be directed to:
21//    Internet email: Matthew.Whiting [at] atnf.csiro.au
22//    Postal address: Dr. Matthew Whiting
23//                    Australia Telescope National Facility, CSIRO
24//                    PO Box 76
25//                    Epping NSW 1710
26//                    AUSTRALIA
27// -----------------------------------------------------------------------
28#include <fstream>
29#include <iostream>
30#include <iomanip>
31#include <vector>
32#include <duchamp/duchamp.hh>
33#include <duchamp/PixelMap/Object3D.hh>
34#include <duchamp/Cubes/cubes.hh>
35#include <duchamp/Detection/detection.hh>
36#include <duchamp/ATrous/atrous.hh>
37#include <duchamp/Utils/utils.hh>
38#include <duchamp/Utils/feedback.hh>
39#include <duchamp/Utils/Statistics.hh>
40
41using namespace PixelInfo;
42using namespace Statistics;
43
44namespace duchamp
45{
46
47  void Cube::ReconSearch()
48  {
49    /// The Cube is first reconstructed, using Cube::ReconCube().
50    /// The statistics of the cube are calculated next.
51    /// It is then searched, using searchReconArray.
52    /// The resulting object list is stored in the Cube, and outputted
53    ///  to the log file if the user so requests.
54
55    if(!this->par.getFlagATrous()){
56      duchampWarning("ReconSearch",
57                     "You've requested a reconSearch, but not allocated space for the reconstructed array.\nDoing the basic CubicSearch.\n");
58      this->CubicSearch();
59    }
60    else {
61 
62      this->ReconCube();
63
64      if(this->par.isVerbose()) std::cout << "  ";
65
66      this->setCubeStats();
67   
68      if(this->par.isVerbose()) std::cout << "  Searching... " << std::flush;
69 
70      *this->objectList = searchReconArraySimple(this->axisDim,this->array,
71                                                 this->recon,
72                                                 this->par,this->Stats);
73      //   this->objectList = searchReconArray(this->axisDim,this->array,
74      //                                      this->recon,this->par,this->Stats);
75
76      if(this->par.isVerbose()) std::cout << "  Updating detection map... "
77                                          << std::flush;
78      this->updateDetectMap();
79      if(this->par.isVerbose()) std::cout << "Done.\n";
80
81      if(this->par.getFlagLog()){
82        if(this->par.isVerbose())
83          std::cout << "  Logging intermediate detections... " << std::flush;
84        this->logDetectionList();
85        if(this->par.isVerbose()) std::cout << "Done.\n";
86      }
87
88    }
89  }
90
91  /////////////////////////////////////////////////////////////////////////////
92  void Cube::ReconCube()
93  {
94    /// A front-end to the various reconstruction functions, the choice of
95    ///  which is determined by the use of the reconDim parameter.
96    /// Differs from ReconSearch only in that no searching is done.
97
98    int dimRecon = this->par.getReconDim();
99    // Test whether we have eg. an image, but have requested a 3-d
100    //  reconstruction.
101    // If dimension of data array is less than dimRecon, change dimRecon
102    //  to the dimension of the array.
103    int numGoodDim = this->head.getNumAxes();
104    if(numGoodDim<dimRecon){
105      dimRecon = numGoodDim;
106      this->par.setReconDim(dimRecon);
107      std::stringstream errmsg;
108      errmsg << "You requested a " << dimRecon << "-dimensional reconstruction,"
109             << " but the FITS file is only " << numGoodDim << "-dimensional.\n"
110             << "Changing reconDim to " << numGoodDim << ".\n";
111      duchampWarning("Reconstruction",errmsg.str());
112    }
113
114    switch(dimRecon)
115      {
116      case 1: this->ReconCube1D(); break;
117      case 2: this->ReconCube2D(); break;
118      case 3: this->ReconCube3D(); break;
119      default:
120        if(dimRecon<=0){
121          std::stringstream errmsg;
122          errmsg << "reconDim (" << dimRecon
123                 << ") is less than 1. Performing 1-D reconstruction.\n";
124          duchampWarning("Reconstruction", errmsg.str());
125          this->par.setReconDim(1);
126          this->ReconCube1D();
127        }
128        else if(dimRecon>3){
129          //this probably won't happen with new code above, but just in case...
130          std::stringstream errmsg;
131          errmsg << "reconDim (" << dimRecon
132                 << ") is more than 3. Performing 3-D reconstruction.\n";
133          duchampWarning("Reconstruction", errmsg.str());
134          this->par.setReconDim(3);
135          this->ReconCube3D();
136        }
137        break;
138      }
139  }
140
141  /////////////////////////////////////////////////////////////////////////////
142  void Cube::ReconCube1D()
143  {
144    /// This reconstructs a cube by performing a 1D a trous reconstruction
145    ///  in the spectrum of each spatial pixel.
146
147    long xySize = this->axisDim[0] * this->axisDim[1];
148
149    long zdim = this->axisDim[2];
150
151    ProgressBar bar;
152    if(!this->reconExists){
153      std::cout<<"  Reconstructing... ";
154      if(par.isVerbose()) bar.init(xySize);
155      for(int npix=0; npix<xySize; npix++){
156
157        if( par.isVerbose() ) bar.update(npix+1);
158
159        float *spec = new float[zdim];
160        float *newSpec = new float[zdim];
161        for(int z=0;z<zdim;z++) spec[z] = this->array[z*xySize + npix];
162        bool verboseFlag = this->par.isVerbose();
163        this->par.setVerbosity(false);
164        atrous1DReconstruct(this->axisDim[2],spec,newSpec,this->par);
165        this->par.setVerbosity(verboseFlag);
166        for(int z=0;z<zdim;z++) this->recon[z*xySize+npix] = newSpec[z];
167        delete [] spec;
168        delete [] newSpec;
169      }
170      this->reconExists = true;
171      bar.fillSpace(" All Done.");
172      printSpace(22);
173      std::cout << "\n";
174    }
175
176  }
177
178  /////////////////////////////////////////////////////////////////////////////
179  void Cube::ReconCube2D()
180  {
181    /// This reconstructs a cube by performing a 2D a trous reconstruction
182    ///  in each spatial image (ie. each channel map) of the cube.
183
184    long xySize = this->axisDim[0] * this->axisDim[1];
185    ProgressBar bar;
186    bool useBar = (this->axisDim[2]>1);
187
188    if(!this->reconExists){
189      std::cout<<"  Reconstructing... ";
190      if(useBar&&par.isVerbose()) bar.init(this->axisDim[2]);
191      for(int z=0;z<this->axisDim[2];z++){
192
193        if( par.isVerbose() && useBar ) bar.update((z+1));
194
195        if(!this->par.isInMW(z)){
196          float *im = new float[xySize];
197          float *newIm = new float[xySize];
198          for(int npix=0; npix<xySize; npix++)
199            im[npix] = this->array[z*xySize+npix];
200          bool verboseFlag = this->par.isVerbose();
201          this->par.setVerbosity(false);
202          atrous2DReconstruct(this->axisDim[0],this->axisDim[1],
203                              im,newIm,this->par);
204          this->par.setVerbosity(verboseFlag);
205          for(int npix=0; npix<xySize; npix++)
206            this->recon[z*xySize+npix] = newIm[npix];
207          delete [] im;
208          delete [] newIm;
209        }
210        else {
211          for(int i=z*xySize; i<(z+1)*xySize; i++)
212            this->recon[i] = this->array[i];
213        }
214      }
215      this->reconExists = true;
216      if(useBar) bar.fillSpace(" All Done.");
217      printSpace(22);
218      std::cout << "\n";
219    }
220  }
221
222  /////////////////////////////////////////////////////////////////////////////
223  void Cube::ReconCube3D()
224  {
225    /// This performs a full 3D a trous reconstruction of the cube
226
227    if(this->axisDim[2]==1) this->ReconCube2D();
228    else {
229
230      if(!this->reconExists){
231        std::cout<<"  Reconstructing... "<<std::flush;
232        atrous3DReconstruct(this->axisDim[0],this->axisDim[1],this->axisDim[2],
233                            this->array,this->recon,this->par);
234        this->reconExists = true;
235        std::cout << "  All Done.";
236        printSpace(22);
237        std::cout << "\n";
238      }
239
240    }
241  }
242
243  /////////////////////////////////////////////////////////////////////////////
244  std::vector <Detection> searchReconArray(long *dim, float *originalArray,
245                                           float *reconArray, Param &par,
246                                           StatsContainer<float> &stats)
247  {
248    ///  This searches for objects in a cube that has been reconstructed.
249    ///
250    ///  The search is conducted first in each spatial pixel (xdim*ydim 1D
251    ///   searches), then in each channel image (zdim 2D searches).
252    ///  The searches are done on the reconstructed array, although the detected
253    ///   objects have fluxes drawn from the corresponding pixels of the original
254    ///   array.
255    ///
256    ///  \param dim Array of dimension sizes
257    ///  \param originalArray Original, un-reconstructed image array.
258    ///  \param reconArray Reconstructed image array
259    ///  \param par The Param set.
260    ///  \param stats The StatsContainer that defines what a detection is.
261    ///
262    ///  \return A vector of Detections resulting from the search.
263
264    std::vector <Detection> outputList;
265    long zdim = dim[2];
266    long xySize = dim[0] * dim[1];
267    int num=0;
268    ProgressBar bar;
269
270    // First search --  in each spectrum.
271    if(zdim > 1){
272      if(par.isVerbose()){
273        std::cout << "1D: ";
274        bar.init(xySize);
275      }
276
277      bool *doPixel = new bool[xySize];
278      // doPixel is a bool array to say whether to look in a given spectrum
279      for(int npix=0; npix<xySize; npix++){
280        doPixel[npix] = false;
281        for(int z=0;z<zdim;z++) {
282          doPixel[npix] = doPixel[npix] ||
283            (!par.isBlank(originalArray[npix]) && !par.isInMW(z));
284        }
285        // doPixel[i] is false only when there are no good pixels in spectrum
286        //  of pixel #i.
287      }
288
289      long *specdim = new long[2];
290      specdim[0] = zdim; specdim[1]=1;
291      Image *spectrum = new Image(specdim);
292      delete [] specdim;
293      spectrum->saveParam(par);
294      spectrum->saveStats(stats);
295      spectrum->setMinSize(par.getMinChannels());
296      spectrum->pars().setBeamSize(2.);
297      // beam size: for spectrum, only neighbouring channels correlated
298
299      for(int y=0; y<dim[1]; y++){
300        for(int x=0; x<dim[0]; x++){
301
302          int npix = y*dim[0] + x;
303          if( par.isVerbose() ) bar.update(npix+1);
304
305          if(doPixel[npix]){
306
307            spectrum->extractSpectrum(reconArray,dim,npix);
308            spectrum->removeMW(); // only works if flagMW is true
309            std::vector<Scan> objlist = spectrum->findSources1D();
310            num += objlist.size();
311            for(unsigned int obj=0;obj<objlist.size();obj++){
312              Detection newObject;
313              // Fix up coordinates of each pixel to match original array
314              for(int z=objlist[obj].getX();z<=objlist[obj].getXmax();z++) {
315//              newObject.pixels().addPixel(x,y,z);
316                newObject.addPixel(x,y,z);
317              }
318              newObject.setOffsets(par);
319              mergeIntoList(newObject,outputList,par);
320            }
321          }
322
323        }
324      }
325
326      delete spectrum;
327      delete [] doPixel;
328
329      if(par.isVerbose()) {
330        bar.fillSpace("Found ");
331        std::cout << num <<";" << std::flush;
332      }
333    }
334
335    // Second search --  in each channel
336    if(par.isVerbose()){
337      std::cout << "  2D: ";
338      bar.init(zdim);
339    }
340
341    num = 0;
342
343    long *imdim = new long[2];
344    imdim[0] = dim[0]; imdim[1] = dim[1];
345    Image *channelImage = new Image(imdim);
346    delete [] imdim;
347    channelImage->saveParam(par);
348    channelImage->saveStats(stats);
349    channelImage->setMinSize(par.getMinPix());
350
351    for(int z=0; z<zdim; z++){  // loop over all channels
352
353      if( par.isVerbose() ) bar.update(z+1);
354
355      if(!par.isInMW(z)){
356        // purpose of this is to ignore the Milky Way channels
357        //  if we are flagging them
358
359        channelImage->extractImage(reconArray,dim,z);
360        std::vector<Object2D> objlist = channelImage->findSources2D();
361        num += objlist.size();
362        for(unsigned int obj=0;obj<objlist.size();obj++){
363          Detection newObject;
364//        newObject.pixels().addChannel(z,objlist[obj]);
365          newObject.addChannel(z,objlist[obj]);
366          newObject.setOffsets(par);
367          mergeIntoList(newObject,outputList,par);
368        }
369      }
370   
371    }
372
373    delete channelImage;
374
375    if(par.isVerbose()){
376      bar.fillSpace("Found ");
377      std::cout << num << ".\n";
378    }
379
380
381    return outputList;
382  }
383
384  /////////////////////////////////////////////////////////////////////////////
385  std::vector <Detection>
386  searchReconArraySimple(long *dim, float *originalArray,
387                         float *reconArray, Param &par,
388                         StatsContainer<float> &stats)
389  {
390    ///  This searches for objects in a cube that has been reconstructed.
391    ///
392    ///  The search is conducted only in each channel image (zdim 2D
393    ///  searches) -- no searches in 1D are done.
394    ///
395    ///  The searches are done on the reconstructed array, although the detected
396    ///   objects have fluxes drawn from the corresponding pixels of the original
397    ///   array.
398    ///
399    ///  \param dim Array of dimension sizes
400    ///  \param originalArray Original, un-reconstructed image array.
401    ///  \param reconArray Reconstructed image array
402    ///  \param par The Param set.
403    ///  \param stats The StatsContainer that defines what a detection is.
404    ///
405    ///  \return A vector of Detections resulting from the search.
406
407    std::vector <Detection> outputList;
408    long zdim = dim[2];
409    int num=0;
410    ProgressBar bar;
411    bool useBar = (zdim>1);
412    if(useBar&&par.isVerbose()) bar.init(zdim);
413 
414    long *imdim = new long[2];
415    imdim[0] = dim[0]; imdim[1] = dim[1];
416    Image *channelImage = new Image(imdim);
417    delete [] imdim;
418    channelImage->saveParam(par);
419    channelImage->saveStats(stats);
420    channelImage->setMinSize(1);
421
422    for(int z=0; z<zdim; z++){  // loop over all channels
423
424      if( par.isVerbose() && useBar ) bar.update(z+1);
425
426      if(!par.isInMW(z)){
427        // purpose of this is to ignore the Milky Way channels
428        //  if we are flagging them
429
430        channelImage->extractImage(reconArray,dim,z);
431        std::vector<Object2D> objlist = channelImage->findSources2D();
432        num += objlist.size();
433        for(unsigned int obj=0;obj<objlist.size();obj++){
434          Detection newObject;
435//        newObject.pixels().addChannel(z,objlist[obj]);
436          newObject.addChannel(z,objlist[obj]);
437          newObject.setOffsets(par);
438          mergeIntoList(newObject,outputList,par);
439        }
440      }
441   
442    }
443
444    delete channelImage;
445
446    if(par.isVerbose()){
447      if(useBar) bar.remove();
448      std::cout << "Found " << num << ".\n";
449    }
450
451
452    return outputList;
453  }
454
455}
Note: See TracBrowser for help on using the repository browser.