source: trunk/src/PixelMap/Object3D.cc

Last change on this file was 1423, checked in by MatthewWhiting, 7 years ago

Applying a patch from ASKAPsoft development, where we ensure that the
spatial map for an Object3D has offsets applied as well.
ASKAPSDP revision r6719

File size: 17.6 KB
RevLine 
[301]1// -----------------------------------------------------------------------
[528]2// Object3D.cc: Member functions for Object3D class.
[301]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// -----------------------------------------------------------------------
[244]28#include <iostream>
[1144]29#include <fstream>
[658]30#include <sstream>
[393]31#include <duchamp/PixelMap/Voxel.hh>
[1293]32#include <duchamp/PixelMap/Line.hh>
[393]33#include <duchamp/PixelMap/Scan.hh>
34#include <duchamp/PixelMap/Object2D.hh>
35#include <duchamp/PixelMap/Object3D.hh>
[927]36#include <duchamp/Utils/Section.hh>
[238]37#include <vector>
[570]38#include <map>
[238]39
[252]40namespace PixelInfo
41{
[365]42  Object3D::Object3D()
43  {
44    this->numVox=0;
[570]45    this->xSum = 0;
46    this->ySum = 0;
47    this->zSum = 0;
48    this->xmin = this->xmax = this->ymin = this->ymax = this->zmin = this->zmax = -1;
[365]49  }
[570]50  //--------------------------------------------
[365]51
[270]52  Object3D::Object3D(const Object3D& o)
53  {
[365]54    operator=(o);
[252]55  }
56  //--------------------------------------------
57
[270]58  Object3D& Object3D::operator= (const Object3D& o)
59  {
60    if(this == &o) return *this;
[570]61    this->chanlist = o.chanlist;
[252]62    this->numVox  = o.numVox;
[927]63    this->spatialMap = o.spatialMap;
[252]64    this->xSum    = o.xSum;
65    this->ySum    = o.ySum;
66    this->zSum    = o.zSum;
67    this->xmin    = o.xmin;
68    this->ymin    = o.ymin;
69    this->zmin    = o.zmin;
70    this->xmax    = o.xmax;
71    this->ymax    = o.ymax;
72    this->zmax    = o.zmax;
[270]73    return *this;
[252]74  }
75  //--------------------------------------------
[570]76
77  Object3D operator+ (Object3D lhs, Object3D rhs)
78  {
79    Object3D output = lhs;
80    for(std::map<long, Object2D>::iterator it = rhs.chanlist.begin(); it!=rhs.chanlist.end();it++)
81      output.addChannel(it->first, it->second);
[770]82      //      output.addChannel(*it);
[570]83    return output;
84  }
85
86  //--------------------------------------------
87  float Object3D::getXaverage()
88  {
89    if(numVox>0) return xSum/float(numVox);
90    else return 0.;
91  }
92  //--------------------------------------------
93
94  float Object3D::getYaverage()
95  {
96    if(numVox>0) return ySum/float(numVox);
97    else return 0.;
98  }
99  //--------------------------------------------
100
101  float Object3D::getZaverage()
102  {
103    if(numVox>0) return zSum/float(numVox);
104    else return 0.;
105  }
106  //--------------------------------------------
[243]107 
[252]108  bool Object3D::isInObject(long x, long y, long z)
109  {
[570]110    std::map<long,Object2D>::iterator it=this->chanlist.begin();
111    while(it!=this->chanlist.end() && it->first!=z) it++;
112
113    if(it==this->chanlist.end()) return false;
114    else                         return it->second.isInObject(x,y);
[238]115  }
[252]116  //--------------------------------------------
[238]117
[252]118  void Object3D::addPixel(long x, long y, long z)
119  {
[570]120 
121    std::map<long,Object2D>::iterator it=this->chanlist.begin();
122    while(it!=this->chanlist.end() && it->first!=z) it++;
[238]123
[570]124    if(it==this->chanlist.end()){ //new channel
125      Object2D obj;
126      obj.addPixel(x,y);
127      chanlist.insert( std::pair<int,Object2D>(z,obj) );
[252]128      // update the centres, min & max, as well as the number of voxels
129      if(this->numVox==0){
130        this->xSum = this->xmin = this->xmax = x;
131        this->ySum = this->ymin = this->ymax = y;
132        this->zSum = this->zmin = this->zmax = z;
133      }
134      else{
135        this->xSum += x;
136        this->ySum += y;
137        this->zSum += z;
138        if(x<this->xmin) this->xmin = x;
139        if(x>this->xmax) this->xmax = x;
140        if(y<this->ymin) this->ymin = y;
141        if(y>this->ymax) this->ymax = y;
[570]142        // since we've ordered the maplist, the min & max z fall out naturally
143        this->zmin = this->chanlist.begin()->first;
144        this->zmax = this->chanlist.rbegin()->first;
[252]145      }
146      this->numVox++;   
[246]147    }
[570]148    else{ // existing channel
149      // This method deals with the case of a new pixel being added AND
150      // with the new pixel already existing in the Object2D
151 
[252]152      // Remove that channel's information from the Object's information
[570]153      this->xSum -= it->second.xSum;
154      this->ySum -= it->second.ySum;
[776]155      this->zSum -= z*it->second.numPix;
156      this->numVox -= it->second.numPix;
[252]157
[570]158      // Add the pixel
159      it->second.addPixel(x,y);
[252]160   
[776]161      this->numVox += it->second.numPix;
[570]162      this->xSum += it->second.xSum;
163      this->ySum += it->second.ySum;
[776]164      this->zSum += z*it->second.numPix;
[246]165      if(x<this->xmin) this->xmin = x;
166      if(x>this->xmax) this->xmax = x;
167      if(y<this->ymin) this->ymin = y;
168      if(y>this->ymax) this->ymax = y;
[252]169      // don't need to do anything to zmin/zmax -- the z-value is
170      // already in the list
[246]171    }
172
[927]173    this->spatialMap.addPixel(x,y);
174
[238]175  }
[252]176  //--------------------------------------------
[238]177
[472]178  void Object3D::addScan(Scan s, long z)
179  {
180    long y=s.getY();
181    for(int x=s.getX(); x<=s.getXmax(); x++)
182      this->addPixel(x,y,z);
183  }
184
185  //--------------------------------------------
186
[770]187  // void Object3D::addChannel(const std::pair<long, Object2D> *chan)
188  // {
189  //   long z = chan->first;
190  //   Object2D
191  // }
192
193
[570]194  void Object3D::addChannel(const long &z, Object2D &obj)
[252]195  {
[238]196
[570]197    std::map<long,Object2D>::iterator it=this->chanlist.begin();
198    while(it!=this->chanlist.end() && it->first!=z) it++;
199
[577]200    if(it == this->chanlist.end()){ // channel z is not already in object, so add it.
[570]201      this->chanlist.insert(std::pair<long,Object2D>(z,obj));
[577]202      if(this->numVox == 0){ // if there are no other pixels, so initialise mins,maxs,sums
[570]203        this->xmin = obj.xmin;
204        this->xmax = obj.xmax;
205        this->ymin = obj.ymin;
206        this->ymax = obj.ymax;
207        this->zmin = this->zmax = z;
208        this->xSum = obj.xSum;
209        this->ySum = obj.ySum;
210        this->zSum = z * obj.getSize();
[252]211      }
[577]212      else{ // there are other pixels in other channels, so update mins, maxs, sums
[570]213        if(obj.xmin<this->xmin) this->xmin = obj.xmin;
214        if(obj.xmax>this->xmax) this->xmax = obj.xmax;
215        if(obj.ymin<this->ymin) this->ymin = obj.ymin;
216        if(obj.ymax>this->ymax) this->ymax = obj.ymax;
217        if(z<this->zmin) this->zmin = z;
218        if(z>this->zmax) this->zmax = z;
219        this->xSum += obj.xSum;
220        this->ySum += obj.ySum;
221        this->zSum += z * obj.getSize();
[252]222      }
[570]223      this->numVox += obj.getSize();
[246]224    }
[577]225    else{ // channel is already present, so need to combine objects.
[570]226      this->xSum -= it->second.xSum;
227      this->ySum -= it->second.ySum;
228      this->zSum -= z*it->second.getSize();
229      this->numVox -= it->second.getSize();
[577]230      it->second = it->second + obj;
[570]231      this->xSum += it->second.xSum;
232      this->ySum += it->second.ySum;
233      this->zSum += z*it->second.getSize();
234      this->numVox += it->second.getSize();
235      if(obj.xmin<this->xmin) this->xmin = obj.xmin;
236      if(obj.xmax>this->xmax) this->xmax = obj.xmax;
237      if(obj.ymin<this->ymin) this->ymin = obj.ymin;
238      if(obj.ymax>this->ymax) this->ymax = obj.ymax;
[252]239    }
[419]240
[927]241    this->spatialMap = this->spatialMap + obj;
[238]242
243  }
244
[252]245  //--------------------------------------------
[238]246 
[252]247  void Object3D::calcParams()
248  {
249    this->xSum = 0;
250    this->ySum = 0;
251    this->zSum = 0;
[570]252    this->numVox = 0;
[238]253
[570]254    this->zmin = this->chanlist.begin()->first;
255    this->zmax = this->chanlist.rbegin()->first;
256    for(std::map<long, Object2D>::iterator it = this->chanlist.begin();
257        it!=this->chanlist.end();it++){
[238]258
[570]259      it->second.calcParams();
260
261      if(it==this->chanlist.begin()){
262        this->xmin = it->second.getXmin();
263        this->xmax = it->second.getXmax();
264        this->ymin = it->second.getYmin();
265        this->ymax = it->second.getYmax();
[252]266      }
267      else{
[570]268        if(it->second.xmin<this->xmin) this->xmin = it->second.xmin;
269        if(it->second.xmax>this->xmax) this->xmax = it->second.xmax;
270        if(it->second.ymin<this->ymin) this->ymin = it->second.ymin;
271        if(it->second.ymax>this->ymax) this->ymax = it->second.ymax;
[252]272      }
273
[570]274      this->xSum += it->second.xSum;
275      this->ySum += it->second.ySum;
276      this->zSum += it->first * it->second.getSize();
277      this->numVox += it->second.getSize();
[252]278
[238]279    }
280
281  }
[252]282  //------------------------------------------------------
[238]283
[1146]284  void Object3D::write(std::string filename)
[1144]285  {
286    std::ofstream outfile(filename.c_str(), std::ios::out | std::ios::binary | std::ios::app);
287    size_t size=this->chanlist.size();
288    outfile.write(reinterpret_cast<const char*>(&size), sizeof size);
289    for(std::map<long, Object2D>::iterator it = this->chanlist.begin();
290        it!=this->chanlist.end();it++){
291     
292      outfile.write(reinterpret_cast<const char*>(&(it->first)), sizeof it->first);
293      size=it->second.scanlist.size();
294      outfile.write(reinterpret_cast<const char*>(&size), sizeof size);
295      for(std::vector<Scan>::iterator s=it->second.scanlist.begin();s!=it->second.scanlist.end();s++){
296        outfile.write(reinterpret_cast<const char*>(&(s->itsX)),sizeof s->itsX);
297        outfile.write(reinterpret_cast<const char*>(&(s->itsXLen)),sizeof s->itsXLen);
298        outfile.write(reinterpret_cast<const char*>(&(s->itsY)),sizeof s->itsY);
299      }
300
301    }
302    outfile.close();
303     
304  }
305
[1146]306  std::streampos Object3D::read(std::string filename, std::streampos loc)
[1144]307  {
308    std::ifstream infile(filename.c_str(), std::ios::in | std::ios::binary);
[1146]309    infile.seekg(loc);
[1144]310    size_t mapsize,scanlistsize;
311    long z,x,xl,y;
312    infile.read(reinterpret_cast<char*>(&mapsize), sizeof mapsize);
313    for(size_t i=0;i<mapsize;i++){
314      infile.read(reinterpret_cast<char*>(&z), sizeof z);
315      Object2D obj;
316      infile.read(reinterpret_cast<char*>(&scanlistsize), sizeof scanlistsize);
317      for(size_t j=0;j<scanlistsize;j++){
318        infile.read(reinterpret_cast<char*>(&x),sizeof x);
319        infile.read(reinterpret_cast<char*>(&xl),sizeof xl);
320        infile.read(reinterpret_cast<char*>(&y),sizeof y);
321        Scan scn(y,x,xl);
322        obj.addScan(scn);
323      }
324      this->addChannel(z,obj);
325    }
[1146]326    std::streampos newloc = infile.tellg();
[1144]327    infile.close();
[1146]328    return newloc;
[1144]329  }
330
331
[773]332  void Object3D::print(std::ostream& theStream)
[252]333  {
[773]334    for(std::map<long, Object2D>::iterator it = this->chanlist.begin();
335        it!=this->chanlist.end();it++){
336      for(std::vector<Scan>::iterator s=it->second.scanlist.begin();s!=it->second.scanlist.end();s++){
337        theStream << *s << "," << it->first << "\n";
[244]338      }
[252]339    } 
340    theStream << "\n";
[773]341  }
342
343
344  std::ostream& operator<< ( std::ostream& theStream, Object3D& obj)
345  {
346    obj.print(theStream);
[270]347    return theStream;
[252]348  }
349  //--------------------------------------------
[241]350
[252]351  std::vector<Voxel> Object3D::getPixelSet()
352  {
[724]353    /// @details Returns a vector of the Voxels in the object. All
354    /// flux values are set to 0.
355
[252]356    std::vector<Voxel> voxList(this->numVox);
357    long count = 0;
[570]358    for(std::map<long, Object2D>::iterator it = this->chanlist.begin();
359        it!=this->chanlist.end();it++){
360      long z = it->first;
[773]361      for(std::vector<Scan>::iterator s=it->second.scanlist.begin();s!=it->second.scanlist.end();s++){
362        long y = s->getY();
363        for(long x=s->getX(); x<=s->getXmax(); x++){
[252]364          voxList[count].setXYZF(x,y,z,0);
365          count++;
[241]366        }
[252]367      }
[241]368    }
[252]369    return voxList;
[243]370
371  }
372
[399]373  //--------------------------------------------------------------------
374
[1002]375  std::vector<Voxel> Object3D::getPixelSet(float *array, size_t *dim)
[724]376  {
377    /// @details Returns a vector of Voxels with the flux values for each voxel
378    /// taken from the array provided. No check is made as to whether
379    /// the pixels fall in the array boundaries
380    /// @param array Array of pixel values
381    /// @param dim Array of axis dimensions
382
383    std::vector<Voxel> voxList(this->numVox);
384    long count = 0;
385    for(std::map<long, Object2D>::iterator it = this->chanlist.begin();
386        it!=this->chanlist.end();it++){
387      long z = it->first;
[773]388      for(std::vector<Scan>::iterator s=it->second.scanlist.begin();s!=it->second.scanlist.end();s++){
389        long y = s->getY();
390        for(long x=s->getX(); x<=s->getXmax(); x++){
[724]391          voxList[count].setXYZF(x,y,z,array[x+dim[0]*y+dim[0]*dim[1]*z]);
392          count++;
393        }
394      }
395    }
396    return voxList;
397
398  }
399
400  //--------------------------------------------------------------------
401
[570]402  std::vector<long> Object3D::getChannelList()
[399]403  {
[570]404
405    std::vector<long> chanlist;
406    for(std::map<long, Object2D>::iterator it = this->chanlist.begin();
407        it != this->chanlist.end(); it++){
408      chanlist.push_back(it->first);
409    }
410    return chanlist;
[399]411  }
[570]412
[399]413  //--------------------------------------------------------------------
414
[570]415  Object2D Object3D::getChanMap(long z)
416  {
417    Object2D obj;
418    std::map<long,Object2D>::iterator it=this->chanlist.begin();
419    while(it!=this->chanlist.end() && it->first!=z) it++;
420
421    if(it==this->chanlist.end()) obj = Object2D();
422    else obj = it->second;
423
424    return obj;
425  }
426
427  //--------------------------------------------------------------------
428
[1261]429  unsigned int Object3D::getMaxAdjacentChannels()
[570]430  {
[691]431    /// @details Find the maximum number of contiguous channels in the
432    /// object. Since there can be gaps in the channels included in an
433    /// object, we run through the list of channels and keep track of
434    /// sizes of contiguous segments. Then return the largest size.
435
[1261]436    unsigned int maxnumchan=0;
437    unsigned int zcurrent=0, zprevious,zcount=0;
[691]438    std::map<long, Object2D>::iterator it;
439    for(it = this->chanlist.begin(); it!=this->chanlist.end();it++)
[570]440      {
[691]441        if(it==this->chanlist.begin()){
442          zcount++;
443          zcurrent = it->first;
[570]444        }
[691]445        else{
446          zprevious = zcurrent;
447          zcurrent = it->first;
448          if(zcurrent-zprevious>1){
449            maxnumchan = std::max(maxnumchan, zcount);
450            zcount=1;
451          }
452          else zcount++;
453        }
[570]454      }
455    maxnumchan = std::max(maxnumchan,zcount);
456    return maxnumchan;
457  }
458
459  //--------------------------------------------------------------------
460
[399]461  void Object3D::addOffsets(long xoff, long yoff, long zoff)
[419]462  {
[658]463    std::map<long,Object2D> newmap;
464    for(std::map<long, Object2D>::iterator it = this->chanlist.begin(); it!=this->chanlist.end();it++){
465      std::pair<long,Object2D> newOne(it->first+zoff, it->second);
466      newOne.second.addOffsets(xoff,yoff);
467      newmap.insert(newOne);
468    }
469    this->chanlist.clear();
470    this->chanlist = newmap;
[1423]471    this->spatialMap.addOffsets(xoff,yoff);
[570]472    if(this->numVox>0){
473      this->xSum += xoff*numVox;
474      this->xmin += xoff; this->xmax += xoff;
475      this->ySum += yoff*numVox;
476      this->ymin += yoff; this->ymax += yoff;
477      this->zSum += zoff*numVox;
478      this->zmin += zoff; this->zmax += zoff;
479    }
[419]480  }
[399]481
[658]482
483  duchamp::Section Object3D::getBoundingSection(int boundary)
484  {
485    std::stringstream ss;
486    ss << "[" << this->xmin-boundary <<":"<<this->xmax+boundary<<","<< this->ymin-boundary <<":"<<this->ymax+boundary<<","<< this->zmin-boundary <<":"<<this->zmax+boundary<<"]";
487    std::string sec=ss.str();
488    duchamp::Section section(sec);
489    return section;
490  }
491
[1293]492  std::vector<std::vector<Voxel> > Object3D::getVertexSet()
493  {
494    ///  @details
[1353]495    /// Returns a vector of vectors of Voxels. Each vector of Voxels is a join-the-dots outline of an island of pixels, and there is one vector for each separate island (since an Object3D may have more than one island of connected pixels).
496    /// \return The vector of vectors of Voxels.
[1293]497
498    int xmin = this->getXmin() - 1;
499    int xmax = this->getXmax() + 1;
500    int ymin = this->getYmin() - 1;
501    int ymax = this->getYmax() + 1;
502    int xsize = xmax - xmin + 1;
503    int ysize = ymax - ymin + 1;
504
505    std::vector<Voxel> voxlist = this->getPixelSet();
506    std::vector<bool> isObj(xsize*ysize,false);
507    std::vector<Voxel>::iterator vox;
508    for(vox=voxlist.begin();vox<voxlist.end();vox++){
[1353]509      size_t pos = (vox->getX()-xmin) + (vox->getY()-ymin)*xsize;
[1293]510      isObj[pos] = true;
511    }
512    voxlist.clear();
513
514    std::vector<Line> linelist;   
515    for(int x=xmin; x<=xmax; x++){
516      // for each column...
517      for(int y=ymin+1;y<=ymax;y++){
518        int current  = (y-ymin)*xsize + x-xmin;
519        int previous = (y-ymin-1)*xsize + x-xmin;
520        if((isObj[current]&&!isObj[previous])   ||
521           (!isObj[current]&&isObj[previous])){
522          linelist.push_back(Line(x,y,x+1,y));
523        }
524      }
525    }
526    for(int y=ymin; y<=ymax; y++){
527      // now for each row...
528      for(int x=xmin+1;x<=xmax;x++){
529        int current  = (y-ymin)*xsize + x-xmin;
530        int previous = (y-ymin)*xsize + x-xmin - 1;
531        if((isObj[current]&&!isObj[previous])   ||
532           (!isObj[current]&&isObj[previous])){
533          linelist.push_back(Line(x,y,x,y+1));
534        }
535      }
536    }
537
538    std::vector<std::vector<Voxel> > vertSet;
539    while(linelist.size()>0){
540        std::vector<Voxel> orderedVertices;
541        std::vector<Line>::iterator line=linelist.begin();
542        orderedVertices.push_back(line->start());
543        Voxel comp=line->end(),prev=line->start();
544        orderedVertices.push_back(comp);
545        linelist.erase(line);
546        bool atEnd=false;
547        do{
548            bool foundIt=false;
549            line=linelist.begin();
550            while(line!=linelist.end() && !foundIt){
551                foundIt = line->has(comp);
552                atEnd = line->has(orderedVertices[0]);
553                if(comp == line->start()){
554                    orderedVertices.push_back(line->end());
555                    comp=line->end();
556                }
557                else if (comp==line->end()){
558                    orderedVertices.push_back(line->start());
559                    comp=line->start();
560                }
561                if(foundIt) linelist.erase(line);
562                else line++;
563            }
564        }  while(linelist.size()>0 && !atEnd);
565        vertSet.push_back(orderedVertices);
566    }
567
568    return vertSet;
569 
570  }
571
572
573
574
[243]575}
Note: See TracBrowser for help on using the repository browser.