#include <processor.h>
Inheritance diagram for EMAN::KmeansSegmentProcessor:
Public Member Functions | |
string | get_name () const |
Get the processor's name. | |
virtual EMData * | process (const EMData *const image) |
To proccess an image out-of-place. | |
void | process_inplace (EMData *image) |
To process an image in-place. | |
TypeDict | get_param_types () const |
Get processor parameter information in a dictionary. | |
string | get_desc () const |
Get the descrition of this specific processor. | |
Static Public Member Functions | |
static Processor * | NEW () |
Static Public Attributes | |
static const string | NAME = "segment.kmeans" |
ctf[in] | A Ctf object to use |
Definition at line 720 of file processor.h.
string EMAN::KmeansSegmentProcessor::get_desc | ( | ) | const [inline, virtual] |
Get the descrition of this specific processor.
This function must be overwritten by a subclass.
Implements EMAN::Processor.
Definition at line 750 of file processor.h.
00751 { 00752 return "Performs K-means segmentation on a volume. Note that this method uses random seeds, and thus will return different results each time it is run. Returned map contains number of segment for each voxel (or 0 for unsegmented voxels). Segmentation centers are stored in 'segmentcenters' attribute, consisting of a list of 3n floats in x,y,z triples."; 00753 }
string EMAN::KmeansSegmentProcessor::get_name | ( | ) | const [inline, virtual] |
Get the processor's name.
Each processor is identified by a unique name.
Implements EMAN::Processor.
Definition at line 723 of file processor.h.
References NAME.
00724 { 00725 return NAME; 00726 }
TypeDict EMAN::KmeansSegmentProcessor::get_param_types | ( | ) | const [inline, virtual] |
Get processor parameter information in a dictionary.
Each parameter has one record in the dictionary. Each record contains its name, data-type, and description.
Reimplemented from EMAN::Processor.
Definition at line 731 of file processor.h.
References EMAN::EMObject::FLOAT, EMAN::EMObject::INT, and EMAN::TypeDict::put().
00732 { 00733 TypeDict d ; 00734 d.put("nseg", EMObject::INT, "Number of segments to divide the image into. default=12" ); 00735 d.put("thr",EMObject::FLOAT,"Isosurface threshold value. Pixels below this will not be segmented"); 00736 d.put("ampweight",EMObject::INT,"If set, will weight centers by voxel amplitude. default = 1"); 00737 d.put("maxsegsize",EMObject::FLOAT,"Maximum radial distance from segment center to member voxel. Default=10000"); 00738 d.put("minsegsep",EMObject::FLOAT,"Minimum segment separation. Segments too close will trigger a reseed"); 00739 d.put("maxiter",EMObject::FLOAT,"Maximum number of iterations to run before stopping. Default=100"); 00740 d.put("maxvoxmove",EMObject::FLOAT,"Maximum number of voxels that can move before quitting. Default=25"); 00741 d.put("verbose",EMObject::INT,"Be verbose while running"); 00742 return d; 00743 }
static Processor* EMAN::KmeansSegmentProcessor::NEW | ( | ) | [inline, static] |
Definition at line 745 of file processor.h.
00746 { 00747 return new KmeansSegmentProcessor(); 00748 }
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.
image | The image will be copied, actual process happen on copy of image. |
Reimplemented from EMAN::Processor.
Definition at line 901 of file processor.cpp.
References EMAN::EMData::copy(), EMAN::Util::get_frand(), EMAN::EMData::get_value_at(), EMAN::EMData::get_xsize(), EMAN::EMData::get_ysize(), EMAN::EMData::get_zsize(), EMAN::Util::hypot3(), nx, ny, EMAN::Processor::params, EMAN::EMData::set_attr(), EMAN::Dict::set_default(), EMAN::EMData::set_value_at(), x, and y.
00902 { 00903 EMData * result = image->copy(); 00904 00905 int nseg = params.set_default("nseg",12); 00906 float thr = params.set_default("thr",-1.0e30f); 00907 int ampweight = params.set_default("ampweight",1); 00908 float maxsegsize = params.set_default("maxsegsize",10000.0f); 00909 float minsegsep = params.set_default("minsegsep",0.0f); 00910 int maxiter = params.set_default("maxiter",100); 00911 int maxvoxmove = params.set_default("maxvoxmove",25); 00912 int verbose = params.set_default("verbose",0); 00913 00914 vector<float> centers(nseg*3); 00915 vector<float> count(nseg); 00916 int nx=image->get_xsize(); 00917 int ny=image->get_ysize(); 00918 int nz=image->get_zsize(); 00919 // int nxy=nx*ny; 00920 00921 // seed 00922 for (int i=0; i<nseg*3; i+=3) { 00923 centers[i]= Util::get_frand(0.0f,(float)nx); 00924 centers[i+1]=Util::get_frand(0.0f,(float)ny); 00925 centers[i+2]=Util::get_frand(0.0f,(float)nz); 00926 } 00927 00928 for (int iter=0; iter<maxiter; iter++) { 00929 // **** classify 00930 size_t pixmov=0; // count of moved pixels 00931 for (int z=0; z<nz; z++) { 00932 for (int y=0; y<ny; y++) { 00933 for (int x=0; x<nz; x++) { 00934 if (image->get_value_at(x,y,z)<thr) { 00935 result->set_value_at(x,y,z,-1.0); //below threshold -> -1 (unclassified) 00936 continue; 00937 } 00938 int bcls=-1; // best matching class 00939 float bdist=(float)(nx+ny+nz); // distance for best class 00940 for (int c=0; c<nseg; c++) { 00941 float d=Util::hypot3(x-centers[c*3],y-centers[c*3+1],z-centers[c*3+2]); 00942 if (d<bdist) { bdist=d; bcls=c; } 00943 } 00944 if ((int)result->get_value_at(x,y,z)!=bcls) pixmov++; 00945 if (bdist>maxsegsize) result->set_value_at(x,y,z,-1); // pixel is too far from any center 00946 else result->set_value_at(x,y,z,(float)bcls); // set the pixel to the class number 00947 } 00948 } 00949 } 00950 00951 // **** adjust centers 00952 for (int i=0; i<nseg*3; i++) centers[i]=0; 00953 for (int i=0; i<nseg; i++) count[i]=0; 00954 00955 // weighted sums 00956 for (int z=0; z<nz; z++) { 00957 for (int y=0; y<ny; y++) { 00958 for (int x=0; x<nz; x++) { 00959 int cls = (int)result->get_value_at(x,y,z); 00960 if (cls==-1) continue; 00961 float w=1.0; 00962 if (ampweight) w=image->get_value_at(x,y,z); 00963 00964 centers[cls*3]+=x*w; 00965 centers[cls*3+1]+=y*w; 00966 centers[cls*3+2]+=z*w; 00967 count[cls]+=w; 00968 } 00969 } 00970 } 00971 00972 // now each becomes center of mass, or gets randomly reseeded 00973 int nreseed=0; 00974 for (int c=0; c<nseg; c++) { 00975 // reseed 00976 if (count[c]==0) { 00977 nreseed++; 00978 do { 00979 centers[c*3]= Util::get_frand(0.0f,(float)nx); 00980 centers[c*3+1]=Util::get_frand(0.0f,(float)ny); 00981 centers[c*3+2]=Util::get_frand(0.0f,(float)nz); 00982 } while (image->get_value_at((int)centers[c*3],(int)centers[c*3+1],(int)centers[c*3+2])<thr); // This makes sure the new point is inside density 00983 } 00984 // center of mass 00985 else { 00986 centers[c*3]/=count[c]; 00987 centers[c*3+1]/=count[c]; 00988 centers[c*3+2]/=count[c]; 00989 } 00990 } 00991 00992 // with minsegsep, check separation 00993 if (minsegsep>0) { 00994 for (int c1=0; c1<nseg-1; c1++) { 00995 for (int c2=c1+1; c2<nseg; c2++) { 00996 if (Util::hypot3(centers[c1*3]-centers[c2*3],centers[c1*3+1]-centers[c2*3+1],centers[c1*3+2]-centers[c2*3+2])<=minsegsep) { 00997 nreseed++; 00998 do { 00999 centers[c1*3]= Util::get_frand(0.0f,(float)nx); 01000 centers[c1*3+1]=Util::get_frand(0.0f,(float)ny); 01001 centers[c1*3+2]=Util::get_frand(0.0f,(float)nz); 01002 } while (image->get_value_at((int)centers[c1*3],(int)centers[c1*3+1],(int)centers[c1*3+2])<thr); 01003 } 01004 } 01005 } 01006 } 01007 01008 01009 if (verbose) printf("Iteration %3d: %6ld voxels moved, %3d classes reseeded\n",iter,pixmov,nreseed); 01010 if (nreseed==0 && pixmov<(size_t)maxvoxmove) break; // termination conditions met 01011 } 01012 01013 result->set_attr("segment_centers",centers); 01014 01015 return result; 01016 }
void KmeansSegmentProcessor::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.
image | The image to be processed. |
Implements EMAN::Processor.
Definition at line 1018 of file processor.cpp.
01019 { 01020 printf("Process inplace not implemented. Please use process.\n"); 01021 return; 01022 }
const string KmeansSegmentProcessor::NAME = "segment.kmeans" [static] |