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

Segment a volume into ~n subvolumes using K-means classification. More...

#include <processor.h>

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

Public Member Functions

string get_name () const
 Get the processor's name. More...
 
virtual EMDataprocess (const EMData *const image)
 To proccess an image out-of-place. More...
 
void process_inplace (EMData *image)
 To process an image in-place. More...
 
TypeDict get_param_types () const
 Get processor parameter information in a dictionary. More...
 
string get_desc () const
 Get the descrition of this specific processor. 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.kmeans"
 

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

Segment a volume into ~n subvolumes using K-means classification.

Author
Steve Ludtke
Date
2008/11/03
Parameters
ctf[in]A Ctf object to use

Definition at line 1744 of file processor.h.

Member Function Documentation

◆ get_desc()

string EMAN::KmeansSegmentProcessor::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 1781 of file processor.h.

1782 {
1783 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.";
1784 }

◆ get_name()

string EMAN::KmeansSegmentProcessor::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 1747 of file processor.h.

1748 {
1749 return NAME;
1750 }
static const string NAME
Definition: processor.h:1786

References NAME.

◆ get_param_types()

TypeDict EMAN::KmeansSegmentProcessor::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.

An option for pseudoatom generation in pathwalker. Instead of random seeding, seed on the gird initially.

Author
Muyuan Chen
Date
2014/06/05

Reimplemented from EMAN::Processor.

Definition at line 1755 of file processor.h.

1756 {
1757 TypeDict d ;
1758 d.put("nseg", EMObject::INT, "Number of segments to divide the image into. default=12" );
1759 d.put("thr",EMObject::FLOAT,"Isosurface threshold value. Pixels below this will not be segmented");
1760 d.put("ampweight",EMObject::INT,"If set, will weight centers by voxel amplitude. default = 1");
1761 d.put("maxsegsize",EMObject::FLOAT,"Maximum radial distance from segment center to member voxel. Default=10000");
1762 d.put("minsegsep",EMObject::FLOAT,"Minimum segment separation. Segments too close will trigger a reseed");
1763 d.put("maxiter",EMObject::FLOAT,"Maximum number of iterations to run before stopping. Default=100");
1764 d.put("maxvoxmove",EMObject::FLOAT,"Maximum number of voxels that can move before quitting. Default=25");
1765 d.put("verbose",EMObject::INT,"Be verbose while running");
1771 d.put("pseudoatom",EMObject::BOOL,"Doing pseudoatom generation");
1772 d.put("sep",EMObject::FLOAT,"Separation distance, used only in pseudoatom generation. Default=3.78");
1773 return d;
1774 }
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::BOOL, EMAN::EMObject::FLOAT, EMAN::EMObject::INT, and EMAN::TypeDict::put().

◆ NEW()

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

Definition at line 1776 of file processor.h.

1777 {
1778 return new KmeansSegmentProcessor();
1779 }
Segment a volume into ~n subvolumes using K-means classification.
Definition: processor.h:1745

◆ process()

EMData * KmeansSegmentProcessor::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 1739 of file processor.cpp.

1740{
1741 EMData * result = image->copy();
1742
1743 int nseg = params.set_default("nseg",12);
1744 float thr = params.set_default("thr",-1.0e30f);
1745 int ampweight = params.set_default("ampweight",1);
1746 float maxsegsize = params.set_default("maxsegsize",10000.0f);
1747 float minsegsep = params.set_default("minsegsep",0.0f);
1748 int maxiter = params.set_default("maxiter",100);
1749 int maxvoxmove = params.set_default("maxvoxmove",25);
1750 int verbose = params.set_default("verbose",0);
1751 bool pseudoatom = params.set_default("pseudoatom",0);
1752 float sep = params.set_default("sep",3.78f);
1753
1754 int nx=image->get_xsize();
1755 int ny=image->get_ysize();
1756 int nz=image->get_zsize();
1757// int nxy=nx*ny;
1758// image->process_inplace("threshold.belowtozero");
1759 if (thr==-1.0e30f){
1760 thr=float(image->get_attr("mean_nonzero"))+ 1.0 *float(image->get_attr("sigma_nonzero"));
1761 printf("Estimated map threshold: %4f\n", thr);
1762 }
1763 // seed
1764 vector<float> centers(nseg*3);
1765 vector<float> count(nseg);
1766 // Alternative seeding method for paudoatom generation. Seed on the gird.
1767 if (pseudoatom){
1768 float ax=image->get_attr("apix_x");
1769 sep/=ax;
1770 if (verbose) printf("Seeding .....\n");
1771 int sx=int(nx/sep)+1,sy=int(ny/sep)+1,sz=int(nz/sep)+1;
1772 EMData m(sx,sy,sz);
1773 EMData mcount(sx,sy,sz);
1774 for (int i=0; i<nx; i++){
1775 for (int j=0; j<ny; j++){
1776 for (int k=0; k<nz; k++){
1777 int ni=(i/sep),nj=(j/sep),nk=(k/sep);
1778 float v=image->get_value_at(i,j,k);
1779 if (v>thr){
1780 m.set_value_at(ni,nj,nk,(m.get_value_at(ni,nj,nk)+v));
1781 mcount.set_value_at(ni,nj,nk,(mcount.get_value_at(ni,nj,nk)+1));
1782 }
1783 }
1784 }
1785 }
1786 m.div((nx/sx)*(ny/sy)*(nz/sz));
1787 int nsum=0;
1788 float l=image->get_attr("minimum"),r=image->get_attr("maximum"),th=0;
1789 while (abs(nsum-nseg)>0){
1790 th=(l+r)/2;
1791 nsum=0;
1792 for (int i=0; i<sx; i++){
1793 for (int j=0; j<sy; j++){
1794 for (int k=0; k<sz; k++){
1795 if (m.get_value_at(i,j,k)>th) nsum+=1;
1796 }
1797 }
1798 }
1799// if (verbose) printf("%3f\t %3f\t %3f,\t %4d\t %4d\n", l,th,r,nsum,nseg);
1800 if (nsum>nseg) l=th;
1801 if (nsum<nseg) r=th;
1802 if ((r-l)<.0001)break;
1803 }
1804// nseg=nsum;
1805 if (verbose) printf("%3d pseudoatoms seeded at threshold value %3f\n", nsum, th);
1806 int q=0;
1807 for (int i=0; i<sx; i++){
1808 for (int j=0; j<sy; j++){
1809 for (int k=0; k<sz; k++){
1810 if (m.get_value_at(i,j,k)>th){
1811 if(q<nseg*3){
1812 centers[q]= float(i+.5)*sep;
1813 centers[q+1]=float(j+.5)*sep;
1814 centers[q+2]=float(k+.5)*sep;
1815 q+=3;
1816 }
1817 }
1818 }
1819 }
1820 }
1821
1822 }
1823 // Default: random seeding.
1824 else{
1825 for (int i=0; i<nseg*3; i+=3) {
1826 centers[i]= Util::get_frand(0.0f,(float)nx);
1827 centers[i+1]=Util::get_frand(0.0f,(float)ny);
1828 centers[i+2]=Util::get_frand(0.0f,(float)nz);
1829 }
1830 }
1831
1832 for (int iter=0; iter<maxiter; iter++) {
1833 // **** classify
1834 size_t pixmov=0; // count of moved pixels
1835 for (int z=0; z<nz; z++) {
1836 for (int y=0; y<ny; y++) {
1837 for (int x=0; x<nx; x++) {
1838 if (image->get_value_at(x,y,z)<thr) {
1839 result->set_value_at(x,y,z,-1.0); //below threshold -> -1 (unclassified)
1840 continue;
1841 }
1842 int bcls=-1; // best matching class
1843 float bdist=(float)(nx+ny+nz); // distance for best class
1844 for (int c=0; c<nseg; c++) {
1845 float d=Util::hypot3(x-centers[c*3],y-centers[c*3+1],z-centers[c*3+2]);
1846 if (d<bdist) { bdist=d; bcls=c; }
1847 }
1848 if ((int)result->get_value_at(x,y,z)!=bcls) pixmov++;
1849 if (bdist>maxsegsize) result->set_value_at(x,y,z,-1); // pixel is too far from any center
1850 else result->set_value_at(x,y,z,(float)bcls); // set the pixel to the class number
1851 }
1852 }
1853 }
1854
1855 // **** adjust centers
1856 for (int i=0; i<nseg*3; i++) centers[i]=0;
1857 for (int i=0; i<nseg; i++) count[i]=0;
1858 // weighted sums
1859 for (int z=0; z<nz; z++) {
1860 for (int y=0; y<ny; y++) {
1861 for (int x=0; x<nx; x++) {
1862 int cls = (int)result->get_value_at(x,y,z);
1863 if (cls==-1) continue;
1864 float w=1.0;
1865 if (ampweight) w=image->get_value_at(x,y,z);
1866
1867 centers[cls*3]+=x*w;
1868 centers[cls*3+1]+=y*w;
1869 centers[cls*3+2]+=z*w;
1870 count[cls]+=w;
1871 }
1872 }
1873 }
1874 // now each becomes center of mass, or gets randomly reseeded
1875 int nreseed=0;
1876 for (int c=0; c<nseg; c++) {
1877 // reseed
1878 if (count[c]==0) {
1879 nreseed++;
1880 do {
1881 centers[c*3]= Util::get_frand(0.0f,(float)nx);
1882 centers[c*3+1]=Util::get_frand(0.0f,(float)ny);
1883 centers[c*3+2]=Util::get_frand(0.0f,(float)nz);
1884 } 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
1885 }
1886 // center of mass
1887 else {
1888 centers[c*3]/=count[c];
1889 centers[c*3+1]/=count[c];
1890 centers[c*3+2]/=count[c];
1891 }
1892 }
1893
1894 // with minsegsep, check separation
1895 if (minsegsep>0) {
1896 for (int c1=0; c1<nseg-1; c1++) {
1897 for (int c2=c1+1; c2<nseg; c2++) {
1898 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) {
1899 nreseed++;
1900 do {
1901 centers[c1*3]= Util::get_frand(0.0f,(float)nx);
1902 centers[c1*3+1]=Util::get_frand(0.0f,(float)ny);
1903 centers[c1*3+2]=Util::get_frand(0.0f,(float)nz);
1904 } while (image->get_value_at((int)centers[c1*3],(int)centers[c1*3+1],(int)centers[c1*3+2])<thr);
1905 }
1906 }
1907 }
1908 }
1909
1910
1911 if (verbose) printf("Iteration %3d: %6ld voxels moved, %3d classes reseeded\n",iter,pixmov,nreseed);
1912 if (nreseed==0 && pixmov<(size_t)maxvoxmove) break; // termination conditions met
1913 }
1914
1915 result->set_attr("segment_centers",centers);
1916
1917 return result;
1918}
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
static float get_frand(int low, int high)
Get a float random number between low and high, [low, high)
Definition: util.cpp:725
static float hypot3(int x, int y, int z)
Euclidean distance function in 3D: f(x,y,z) = sqrt(x*x + y*y + z*z);.
Definition: util.h:827
#define y(i, j)
Definition: projector.cpp:1516
#define x(i)
Definition: projector.cpp:1517

References EMAN::Util::get_frand(), EMAN::Util::hypot3(), EMAN::Processor::params, EMAN::Dict::set_default(), x, and y.

◆ process_inplace()

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.

Parameters
imageThe image to be processed.

Implements EMAN::Processor.

Definition at line 1920 of file processor.cpp.

1921{
1922 printf("Process inplace not implemented. Please use process.\n");
1923 return;
1924}

Member Data Documentation

◆ NAME

const string KmeansSegmentProcessor::NAME = "segment.kmeans"
static

Definition at line 1786 of file processor.h.

Referenced by get_name().


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