EMAN2
Public Member Functions | Static Public Member Functions | Static Public Attributes | List of all members
EMAN::WatershedProcessor Class Reference

'paints' a circle into the image at x,y,z with values inside r1 set to v1, values between r1 and r2 will be set to a value between v1 and v2, and values outside r2 will be unchanged More...

#include <processor.h>

Inheritance diagram for EMAN::WatershedProcessor:
Inheritance graph
[legend]
Collaboration diagram for EMAN::WatershedProcessor:
Collaboration graph
[legend]

Public Member Functions

virtual EMDataprocess (const EMData *const image)
 To proccess an image out-of-place. More...
 
virtual void process_inplace (EMData *)
 To process an image in-place. More...
 
virtual string get_name () const
 Get the processor's name. More...
 
virtual string get_desc () const
 Get the descrition of this specific processor. More...
 
virtual TypeDict get_param_types () const
 Get processor parameter information in a dictionary. More...
 
- Public Member Functions inherited from EMAN::Processor
virtual ~Processor ()
 
virtual void process_list_inplace (vector< EMData * > &images)
 To process multiple images using the same algorithm. More...
 
virtual Dict get_params () const
 Get the processor parameters in a key/value dictionary. More...
 
virtual void set_params (const Dict &new_params)
 Set the processor parameters using a key/value dictionary. More...
 

Static Public Member Functions

static ProcessorNEW ()
 
- Static Public Member Functions inherited from EMAN::Processor
static string get_group_desc ()
 Get the description of this group of processors. More...
 
static void EMFourierFilterInPlace (EMData *fimage, Dict params)
 Compute a Fourier-filter processed image in place. More...
 
static EMDataEMFourierFilter (EMData *fimage, Dict params)
 Compute a Fourier-processor processed image without altering the original image. More...
 

Static Public Attributes

static const string NAME = "segment.watershed"
 

Additional Inherited Members

- Public Types inherited from EMAN::Processor
enum  fourier_filter_types {
  TOP_HAT_LOW_PASS , TOP_HAT_HIGH_PASS , TOP_HAT_BAND_PASS , TOP_HOMOMORPHIC ,
  GAUSS_LOW_PASS , GAUSS_HIGH_PASS , GAUSS_BAND_PASS , GAUSS_INVERSE ,
  GAUSS_HOMOMORPHIC , BUTTERWORTH_LOW_PASS , BUTTERWORTH_HIGH_PASS , BUTTERWORTH_HOMOMORPHIC ,
  KAISER_I0 , KAISER_SINH , KAISER_I0_INVERSE , KAISER_SINH_INVERSE ,
  SHIFT , TANH_LOW_PASS , TANH_HIGH_PASS , TANH_HOMOMORPHIC ,
  TANH_BAND_PASS , RADIAL_TABLE , CTF_
}
 Fourier filter Processor type enum. More...
 
- Protected Attributes inherited from EMAN::Processor
Dict params
 

Detailed Description

'paints' a circle into the image at x,y,z with values inside r1 set to v1, values between r1 and r2 will be set to a value between v1 and v2, and values outside r2 will be unchanged

Parameters
xpointsx coordinates
ypointsy coordinates
zpointsz coordinates
minvalmin value

Definition at line 7695 of file processor.h.

Member Function Documentation

◆ get_desc()

virtual string EMAN::WatershedProcessor::get_desc ( ) const
inlinevirtual

Get the descrition of this specific processor.

This function must be overwritten by a subclass.

Returns
The description of this processor.

Implements EMAN::Processor.

Definition at line 7711 of file processor.h.

7712 {
7713 return "Watershed segmentation. Warning: uses up to 2.5x the map size in RAM. This will segment all voxels above threshold except for a 1-voxel wide border on all edges.";
7714 }

◆ get_name()

virtual string EMAN::WatershedProcessor::get_name ( ) const
inlinevirtual

Get the processor's name.

Each processor is identified by a unique name.

Returns
The processor's name.

Implements EMAN::Processor.

Definition at line 7701 of file processor.h.

7702 {
7703 return NAME;
7704 }
static const string NAME
Definition: processor.h:7726

References NAME.

◆ get_param_types()

virtual TypeDict EMAN::WatershedProcessor::get_param_types ( ) const
inlinevirtual

Get processor parameter information in a dictionary.

Each parameter has one record in the dictionary. Each record contains its name, data-type, and description.

Returns
A dictionary containing the parameter info.

Reimplemented from EMAN::Processor.

Definition at line 7716 of file processor.h.

7717 {
7718 TypeDict d;
7719 d.put("nseg", EMObject::INT, "Number of segments to (attempt) to produce. The actual number may be fewer. (default=12)" );
7720 d.put("thr",EMObject::FLOAT,"Isosurface threshold value. Pixels below this value will not be segmented. All voxels above this value will be segmented. (default=0.5)");
7721 d.put("segbymerge", EMObject::INT, "If set, will achieve the specified number of segments by progressively merging the most connected segments. Can produce very different results." );
7722 d.put("verbose", EMObject::INT, "If set, will print console output while running" );
7723 return d;
7724 }
TypeDict is a dictionary to store <string, EMObject::ObjectType> pair.
Definition: emobject.h:305
void put(const string &key, EMObject::ObjectType o, const string &desc="")
Definition: emobject.h:330

References EMAN::EMObject::FLOAT, EMAN::EMObject::INT, and EMAN::TypeDict::put().

◆ NEW()

static Processor * EMAN::WatershedProcessor::NEW ( )
inlinestatic

Definition at line 7706 of file processor.h.

7707 {
7708 return new WatershedProcessor();
7709 }
'paints' a circle into the image at x,y,z with values inside r1 set to v1, values between r1 and r2 w...
Definition: processor.h:7696

◆ process()

EMData * WatershedProcessor::process ( const EMData *const  image)
virtual

To proccess an image out-of-place.

For those processors which can only be processed out-of-place, override this function to give the right behavior.

Parameters
imageThe image will be copied, actual process happen on copy of image.
Returns
the image processing result, may or may not be the same size of the input image

Reimplemented from EMAN::Processor.

Definition at line 11885 of file processor.cpp.

11885 {
11886 //unsigned int nseg = params.set_default("nseg",12);
11887 int nseg = params.set_default("nseg",12);
11888 float thr = params.set_default("thr",0.5f);
11889 int segbymerge = params.set_default("segbymerge",0);
11890 vector<float> centers;
11891 int verbose = params.set_default("verbose",0);
11892 if (nseg<=1) throw InvalidValueException(nseg,"nseg must be greater than 1");
11893
11894 if (segbymerge) { segbymerge=nseg; nseg=4096; } // set max number of segments to a large (but not infinite) value. Too many will make connectivity matrix too big
11895
11896 EMData *ret=new EMData(image->get_xsize(),image->get_ysize(),image->get_zsize());
11897 ret->to_zero();
11898
11899
11900 int nx=image->get_xsize();
11901 int ny=image->get_ysize();
11902 int nz=image->get_zsize();
11903 if (nz==1) throw ImageDimensionException("Only 3-D data supported");
11904
11905 // Count the number of above threshold pixels
11906 size_t n2seg = 0;
11907 for (int z=1; z<nz-1; z++) {
11908 for (int y=1; y<ny-1; y++) {
11909 for (int x=1; x<nx-1; x++) {
11910 if (image->get_value_at(x,y,z)>=thr) n2seg++;
11911 }
11912 }
11913 }
11914 if (verbose) printf("%ld voxels above threshold\n",n2seg);
11915
11916 // Extract the pixels for sorting
11917 vector<WSsortlist> srt(n2seg);
11918 size_t i=0;
11919 for (int z=1; z<nz-1; z++) {
11920 for (int y=1; y<ny-1; y++) {
11921 for (int x=1; x<nx-1; x++) {
11922 if (image->get_value_at(x,y,z)>=thr) {
11923 srt[i].pix=image->get_value_at(x,y,z);
11924 srt[i].x=x;
11925 srt[i].y=y;
11926 srt[i].z=z;
11927 i++;
11928 }
11929 }
11930 }
11931 }
11932 if (verbose) printf("Voxels extracted, sorting\n");
11933
11934 // actual sort
11935 sort(srt.begin(), srt.end());
11936 if (verbose) printf("Voxels sorted (%1.4g max), starting watershed\n",srt[0].pix);
11937
11938 // now we start with the highest value and fill in the segments
11939 float cseg=1.0;
11940 int start=n2seg;
11941 for (i=0; i<n2seg; i++) {
11942 int x=srt[i].x;
11943 int y=srt[i].y;
11944 int z=srt[i].z;
11945 float lvl=0;
11946 for (int zz=z-1; zz<=z+1; zz++) {
11947 for (int yy=y-1; yy<=y+1; yy++) {
11948 for (int xx=x-1; xx<=x+1; xx++) {
11949 float v=ret->get_value_at(xx,yy,zz);
11950 if (v>lvl) lvl=v; // use the highest numbered border segment (arbitrary)
11951 }
11952 }
11953 }
11954 if (lvl==0) {
11955 if (verbose) printf("%d %d %d\t%1.0f\t%1.3g\n",x,y,z,cseg,srt[i].pix);
11956 lvl=cseg;
11957 centers.push_back(x);
11958 centers.push_back(y);
11959 centers.push_back(z);
11960 cseg+=1.0;
11961 }
11962 if (lvl>nseg) {
11963 start=i;
11964 if (verbose) printf("Requested number of segments achieved at density %1.4g\n",srt[i].pix);
11965 break;
11966 } // This means we've made as many segments as we need, so we switch to flood-filling
11967 ret->set_value_at_fast(x,y,z,lvl);
11968 }
11969
11970 // We have as many segments as we'll get, but not all voxels have been segmented, so we do a progressive flood fill in density order
11971 size_t chg=1;
11972 while (chg) {
11973 chg=0;
11974 for (i=start; i<n2seg; i++) {
11975 int x=srt[i].x;
11976 int y=srt[i].y;
11977 int z=srt[i].z;
11978 if (ret->get_value_at(x,y,z)!=0) continue; // This voxel is already done
11979
11980 float lvl=0;
11981 for (int zz=z-1; zz<=z+1; zz++) {
11982 for (int yy=y-1; yy<=y+1; yy++) {
11983 for (int xx=x-1; xx<=x+1; xx++) {
11984 float v=ret->get_value_at(xx,yy,zz);
11985 if (v>lvl) lvl=v; // use the highest numbered border segment (arbitrary)
11986 }
11987 }
11988 }
11989 if (lvl==0) continue; // we just skip voxels without any segmented neighbors
11990 ret->set_value_at_fast(x,y,z,lvl);
11991 chg+=1;
11992 }
11993 if (verbose) printf("%ld voxels changed\n",chg);
11994 }
11995 ret->set_attr("segment_centers",centers);
11996
11997 if (segbymerge) {
11998 if (cseg<segbymerge) return ret;
11999 }
12000 else if (cseg<=nseg) return ret; // We don't have too many segments, so we just return now
12001
12002 if (verbose) printf("Merging segments\n");
12003 // If requested, we now merge segments with the most surface contact until we have the correct final number
12004 if (segbymerge) {
12005 int nsegstart=(int)cseg; // Number of segments we actually generated
12006 nseg=(int)cseg;
12007 EMData *mx=new EMData(nsegstart,nsegstart,1); // This will be a "contact matrix" among segments
12008 float *mxd=mx->get_data();
12009
12010 // each cycle of the while loop, we eliminate one segment by merging
12011 int sub1=-1,sub2=-1; // sub2 will be merged into sub1
12012 nseg++; // since we don't actually remove one on the first pass, but decrement the counter
12013 while (segbymerge<nseg) {
12014 mx->to_zero();
12015
12016 for (i=0; i<n2seg; i++) {
12017 int x=srt[i].x;
12018 int y=srt[i].y;
12019 int z=srt[i].z;
12020
12021 int v1=(int)ret->get_value_at(x,y,z);
12022 if (v1==sub2) { ret->set_value_at_fast(x,y,z,sub1); v1=sub1; }
12023 mxd[v1+v1*nsegstart]++; // the diagonal is a count of the number of voxels in the segment
12024 for (int zz=z-1; zz<=z+1; zz++) {
12025 for (int yy=y-1; yy<=y+1; yy++) {
12026 for (int xx=x-1; xx<=x+1; xx++) {
12027 int v2=(int)ret->get_value_at(xx,yy,zz);
12028 if (v2==sub2) v2=sub1; // pretend that any sub2 values are actually sub1
12029 if (v1==v2) continue;
12030 mxd[v1+v2*nsegstart]+=image->get_value_at(xx,yy,zz); // We weight the connectivity by the image value
12031 }
12032 }
12033 }
12034 }
12035 mx->update();
12036 nseg--; // number of segments left
12037 if (verbose && sub1==-1) { mx->write_image("contactmx.hdf",0); } // for debugging
12038
12039 sub1=-1;
12040 sub2=-1;
12041 // contact matrix complete, now figure out which 2 segments to merge
12042 // diagonal of matrix is a count of the 'volume' of the segment. off-diagonal elements are surface area of contact region (roughly)
12043 // we want to normalize the surface area elements so they are roughly proportional to the size of the segment, so we don't merge
12044 // based on total contact area, but contact area as a fraction of the total area.
12045 float bestv=-1.0;
12046 for (int s1=1; s1<nsegstart; s1++) {
12047 for (int s2=1; s2<nsegstart; s2++) {
12048 if (s1==s2) continue; // ignore the diagonal
12049 float v=mxd[s1+s2*nsegstart];
12050 if (v==0) continue; // empty segment
12051// v/=(pow(mxd[s1+s1*nsegstart],0.6667f)+pow(mxd[s2+s2*nsegstart],0.6667f)); // normalize by the sum of the estimated surface areas (no shape effects)
12052 v/=max(mxd[s1+s1*nsegstart],mxd[s2+s2*nsegstart]); // normalize by the sum of the estimated surface areas (no shape effects)
12053 if (v>bestv) { bestv=v; sub1=s1; sub2=s2; }
12054 }
12055 }
12056 float mv=0;
12057 int mvl=0;
12058 for (i=nsegstart+1; i<nsegstart*nsegstart; i+=nsegstart+1)
12059 if (mxd[i]>mv) { mv=mxd[i]; mvl=i/nsegstart; }
12060 if (verbose) printf("Merging %d to %d (%1.0f, %d)\n",sub2,sub1,mv,mvl);
12061 if (sub1==-1) {
12062 if (verbose) printf("Unable to find segments to merge, aborting\n");
12063 break;
12064 }
12065 }
12066
12067 }
12068
12069 return ret;
12070}
type set_default(const string &key, type val)
Default setting behavior This can be achieved using a template - d.woolford Jan 2008 (before there wa...
Definition: emobject.h:569
EMData stores an image's data and defines core image processing routines.
Definition: emdata.h:82
#define InvalidValueException(val, desc)
Definition: exception.h:285
#define ImageDimensionException(desc)
Definition: exception.h:166
#define y(i, j)
Definition: projector.cpp:1516
#define x(i)
Definition: projector.cpp:1517

References ImageDimensionException, InvalidValueException, EMAN::Processor::params, EMAN::Dict::set_default(), x, and y.

Referenced by process_inplace().

◆ process_inplace()

void WatershedProcessor::process_inplace ( EMData image)
virtual

To process an image in-place.

For those processors which can only be processed out-of-place, override this function to just print out some error message to remind user call the out-of-place version.

Parameters
imageThe image to be processed.

Implements EMAN::Processor.

Definition at line 11879 of file processor.cpp.

11879 {
11880 EMData *tmp=process(image);
11881 memcpy(image->get_data(),tmp->get_data(),image->get_size()*sizeof(float));
11882 delete tmp;
11883}
virtual EMData * process(const EMData *const image)
To proccess an image out-of-place.

References process().

Member Data Documentation

◆ NAME

const string WatershedProcessor::NAME = "segment.watershed"
static

Definition at line 7726 of file processor.h.

Referenced by get_name().


The documentation for this class was generated from the following files: