Esempio n. 1
0
/* Do inference for class ------------------------------------------------- */
int EnsembleNaiveBayes::doInferenceForClass(int classNumber, const Matrix1D<double> &newFeatures, double &cost,
        Matrix1D<double> &classesProbs, Matrix1D<double> &allCosts)
{
    int nmax=ensemble.size();
    double minCost=1, maxCost=1;
    int votes=0;
    MultidimArray<double> newFeaturesn;
    for (int n=0; n<nmax; n++)
    {
        double costn;
        const MultidimArray<int> &ensembleFeatures_n=ensembleFeatures[n];
        newFeaturesn.resizeNoCopy(XSIZE(ensembleFeatures_n));
        FOR_ALL_ELEMENTS_IN_ARRAY1D(newFeaturesn)
        {
            int idx=A1D_ELEM(ensembleFeatures_n,i);
            A1D_ELEM(newFeaturesn,i)=VEC_ELEM(newFeatures,idx);
        }

        int k=ensemble[n]->doInference(newFeaturesn, costn, classesProbs, allCosts);
        if (k==classNumber)
        {
            votes++;
            if (minCost>0 || minCost>costn)
                minCost=costn;
            if (maxCost>0 || maxCost<costn)
                maxCost=costn;
        }
    }
    if      (judgeCombination[classNumber]=='m')
        cost=minCost;
    else if (judgeCombination[classNumber]=='M')
        cost=maxCost;
    else
        cost=minCost;
    return votes;
}
Esempio n. 2
0
void * blobs2voxels_SimpleGrid( void * data )
{
    ThreadBlobsToVoxels * thread_data = (ThreadBlobsToVoxels *) data;

    const MultidimArray<double> *vol_blobs = thread_data->vol_blobs;
    const SimpleGrid *grid = thread_data->grid;
    const struct blobtype *blob = thread_data->blob;
    MultidimArray<double> *vol_voxels = thread_data->vol_voxels;
    const Matrix2D<double> *D = thread_data->D;
    int istep = thread_data->istep;
    MultidimArray<double> *vol_corr = thread_data->vol_corr;
    const MultidimArray<double> *vol_mask = thread_data->vol_mask;
    ;
    bool FORW = thread_data->FORW;
    int eq_mode = thread_data->eq_mode;

    int min_separation = thread_data->min_separation;

    int z_planes = (int)(ZZ(grid->highest) - ZZ(grid->lowest) + 1);

    Matrix2D<double> Dinv;                   // Inverse of D
    Matrix1D<double> act_coord(3);           // Coord: Actual position inside
    // the voxel volume without deforming
    Matrix1D<double> real_position(3);       // Coord: actual position after
    // applying the V transformation
    Matrix1D<double> beginZ(3);              // Coord: Voxel coordinates of the
    // blob at the 3D point
    // (z0,YY(lowest),XX(lowest))
    Matrix1D<double> beginY(3);              // Coord: Voxel coordinates of the
    // blob at the 3D point
    // (z0,y0,XX(lowest))
    Matrix1D<double> corner2(3), corner1(3); // Coord: Corners of the
    // blob in the voxel volume
    Matrix1D<double> gcurrent(3);            // Position in g of current point
    MultidimArray<double> blob_table;             // Something like a blobprint
    // but with the values of the
    // blob in space
    double         d;                        // Distance between the center
    // of the blob and a voxel position
    int           id;                        // index inside the blob value
    // table for tha blob value at
    // a distance d
    double         intx, inty, intz;         // Nearest integer voxel
    int           i, j, k;                   // Index within the blob volume
    int           process;                   // True if this blob has to be
    // processed
    double         vol_correction=0;         // Correction to apply to the
    // volume when "projecting" back
    SPEED_UP_temps012;

    // Some aliases
#define x0 STARTINGX(*vol_voxels)
#define xF FINISHINGX(*vol_voxels)
#define y0 STARTINGY(*vol_voxels)
#define yF FINISHINGY(*vol_voxels)
#define z0 STARTINGZ(*vol_voxels)
#define zF FINISHINGZ(*vol_voxels)

#ifdef DEBUG

    bool condition = !FORW;
    if (condition)
    {
        (*vol_voxels)().printShape();
        std::cout << std::endl;
        std::cout << "x0= " << x0 << " xF= " << xF << std::endl;
        std::cout << "y0= " << y0 << " yF= " << yF << std::endl;
        std::cout << "z0= " << z0 << " zF= " << zF << std::endl;
        std::cout << grid;
    }
#endif

    // Invert deformation matrix ............................................
    if (D != NULL)
        Dinv = D->inv();

    // Compute a blob value table ...........................................
    blob_table.resize((int)(blob->radius*istep + 1));
    for (size_t i = 0; i < blob_table.xdim; i++)
    {
        A1D_ELEM(blob_table, i) = kaiser_value((double)i/istep, blob->radius, blob->alpha, blob->order);

#ifdef DEBUG_MORE

        if (condition)
            std::cout << "Blob (" << i << ") r=" << (double)i / istep <<
            " val= " << A1D_ELEM(blob_table, i) << std::endl;
#endif

    }

    int assigned_slice;

    do
    {
        assigned_slice = -1;
        do
        {
            pthread_mutex_lock(&blobs_conv_mutex);
            if( slices_processed == z_planes )
            {
                pthread_mutex_unlock(&blobs_conv_mutex);
                return (void*)NULL;
            }

            for(int w = 0 ; w < z_planes ; w++ )
            {
                if( slices_status[w]==0 )
                {
                    slices_status[w] = -1;
                    assigned_slice = w;
                    slices_processed++;

                    for( int in = (w-min_separation+1) ; in <= (w+min_separation-1 ) ; in ++ )
                    {
                        if( in != w )
                        {
                            if( ( in >= 0 ) && ( in < z_planes ))
                            {
                                if( slices_status[in] != -1 )
                                    slices_status[in]++;
                            }
                        }
                    }
                    break;
                }
            }

            pthread_mutex_unlock(&blobs_conv_mutex);
        }
        while( assigned_slice == -1);

        // Convert the whole grid ...............................................
        // Corner of the plane defined by Z. These coordinates are in the
        // universal coord. system
        Matrix1D<double> aux( grid->lowest );
        k = (int)(assigned_slice + ZZ( grid->lowest ));
        ZZ(aux) = k;
        grid->grid2universe(aux, beginZ);

        Matrix1D<double> grid_index(3);

        // Corner of the row defined by Y
        beginY = beginZ;
        for (i = (int) YY(grid->lowest); i <= (int) YY(grid->highest); i++)
        {
            // First point in the row
            act_coord = beginY;
            for (j = (int) XX(grid->lowest); j <= (int) XX(grid->highest); j++)
            {
                VECTOR_R3(grid_index, j, i, k);
#ifdef DEBUG

                if (condition)
                {
                    printf("Dealing blob at (%d,%d,%d) = %f\n", j, i, k, A3D_ELEM(*vol_blobs, k, i, j));
                    std::cout << "Center of the blob      "
                    << act_coord.transpose() << std::endl;
                }
#endif

                // Place act_coord in its right place
                if (D != NULL)
                {
                    M3x3_BY_V3x1(real_position, *D, act_coord);
#ifdef DEBUG

                    if (condition)
                        std::cout << "Center of the blob moved to "
                        //ROB, the "moved" coordinates are in
                        // real_position not in act_coord
                        << act_coord.transpose() << std::endl;
                    << real_position.transpose() << std::endl;
#endif
                    // ROB This is OK if blob.radius is in Cartesian space as I
                    // think is the case
                }
                else
                    real_position = act_coord;

                // These two corners are also real valued
                process = true;
                //ROB
                //This is OK if blob.radius is in Cartesian space as I think is the case
                V3_PLUS_CT(corner1, real_position, -blob->radius);
                V3_PLUS_CT(corner2, real_position, blob->radius);
#ifdef DEFORM_BLOB_WHEN_IN_CRYSTAL
                //ROB
                //we do not need this, it is already in Cartesian space
                //if (D!=NULL)
                //   box_enclosing(corner1,corner2, *D, corner1, corner2);
#endif

                if (XX(corner1) >= xF)
                    process = false;
                if (YY(corner1) >= yF)
                    process = false;
                if (ZZ(corner1) >= zF)
                    process = false;
                if (XX(corner2) <= x0)
                    process = false;
                if (YY(corner2) <= y0)
                    process = false;
                if (ZZ(corner2) <= z0)
                    process = false;
#ifdef DEBUG

                if (!process && condition)
                    std::cout << "   It is outside output volume\n";
#endif

                if (!grid->is_interesting(real_position))
                {
#ifdef DEBUG
                    if (process && condition)
                        std::cout << "   It is not interesting\n";
#endif

                    process = false;
                }

#ifdef DEBUG
                if (condition)
                {
                    std::cout << "Corner 1 for this point " << corner1.transpose() << std::endl;
                    std::cout << "Corner 2 for this point " << corner2.transpose() << std::endl;
                }
#endif

                if (process)
                {
                    // Clip the corners to the volume borders
                    XX(corner1) = ROUND(CLIP(XX(corner1), x0, xF));
                    YY(corner1) = ROUND(CLIP(YY(corner1), y0, yF));
                    ZZ(corner1) = ROUND(CLIP(ZZ(corner1), z0, zF));
                    XX(corner2) = ROUND(CLIP(XX(corner2), x0, xF));
                    YY(corner2) = ROUND(CLIP(YY(corner2), y0, yF));
                    ZZ(corner2) = ROUND(CLIP(ZZ(corner2), z0, zF));
#ifdef DEBUG

                    if (condition)
                    {
                        std::cout << "Clipped and rounded Corner 1 " << corner1.transpose() << std::endl;
                        std::cout << "Clipped and rounded Corner 2 " << corner2.transpose() << std::endl;
                    }
#endif

                    if (!FORW)
                        switch (eq_mode)
                        {
                        case VARTK:
                            vol_correction = 0;
                            break;
                        case VMAXARTK:
                            vol_correction = -1e38;
                            break;
                        }

                    // Effectively convert
                    long N_eq;
                    N_eq = 0;
                    for (intz = ZZ(corner1); intz <= ZZ(corner2); intz++)
                        for (inty = YY(corner1); inty <= YY(corner2); inty++)
                            for (intx = XX(corner1); intx <= XX(corner2); intx++)
                            {
                                int iz = (int)intz, iy = (int)inty, ix = (int)intx;
                                if (vol_mask != NULL)
                                    if (!A3D_ELEM(*vol_mask, iz, iy, ix))
                                        continue;

                                // Compute distance to the center of the blob
                                VECTOR_R3(gcurrent, intx, inty, intz);
#ifdef DEFORM_BLOB_WHEN_IN_CRYSTAL
                                // ROB
                                //if (D!=NULL)
                                //   M3x3_BY_V3x1(gcurrent,Dinv,gcurrent);
#endif

                                V3_MINUS_V3(gcurrent, real_position, gcurrent);
                                d = sqrt(XX(gcurrent) * XX(gcurrent) +
                                         YY(gcurrent) * YY(gcurrent) +
                                         ZZ(gcurrent) * ZZ(gcurrent));
                                if (d > blob->radius)
                                    continue;
                                id = (int)(d * istep);
#ifdef DEBUG_MORE

                                if (condition)
                                {
                                    std::cout << "At (" << intx << ","
                                    << inty << "," << intz << ") distance=" << d;
                                    std::cout.flush();
                                }
#endif

                                // Add at that position the corresponding blob value

                                if (FORW)
                                {
                                    A3D_ELEM(*vol_voxels, iz, iy, ix) +=
                                        A3D_ELEM(*vol_blobs, k, i, j) *
                                        A1D_ELEM(blob_table, id);
#ifdef DEBUG_MORE

                                    if (condition)
                                    {
                                        std::cout << " adding " << A3D_ELEM(*vol_blobs, k, i, j)
                                        << " * " << A1D_ELEM(blob_table, id) << " = "
                                        << A3D_ELEM(*vol_blobs, k, i, j)*
                                        A1D_ELEM(blob_table, id) << std::endl;
                                        std::cout.flush();
                                    }
#endif
                                    if (vol_corr != NULL)
                                        A3D_ELEM(*vol_corr, iz, iy, ix) +=
                                            A1D_ELEM(blob_table, id) * A1D_ELEM(blob_table, id);
                                }
                                else
                                {
                                    double contrib = A3D_ELEM(*vol_corr, iz, iy, ix) *
                                                     A1D_ELEM(blob_table, id);
                                    switch (eq_mode)
                                    {
                                    case VARTK:
                                        vol_correction += contrib;
                                        N_eq++;
                                        break;
                                    case VMAXARTK:
                                        if (contrib > vol_correction)
                                            vol_correction = contrib;
                                        break;

                                    }
#ifdef DEBUG_MORE
                                    if (condition)
                                    {
                                        std::cout << " adding " << A3D_ELEM(*vol_corr, iz, iy, ix)
                                        << " * " << A1D_ELEM(blob_table, id) << " = "
                                        << contrib << std::endl;
                                        std::cout.flush();
                                    }
#endif

                                }
                            }
                    if (N_eq == 0)
                        N_eq = 1;
                    if (!FORW)
                    {
                        A3D_ELEM(*vol_blobs, k, i, j) += vol_correction / N_eq;
#ifdef DEBUG_MORE

                        std::cout << " correction= " << vol_correction << std::endl
                        << " Number of eqs= " << N_eq << std::endl
                        << " Blob after correction= "
                        << A3D_ELEM(*vol_blobs, k, i, j) << std::endl;
#endif

                    }
                }

                // Prepare for next iteration
                XX(act_coord) = XX(act_coord) + grid->relative_size * (grid->basis)( 0, 0);
                YY(act_coord) = YY(act_coord) + grid->relative_size * (grid->basis)( 1, 0);
                ZZ(act_coord) = ZZ(act_coord) + grid->relative_size * (grid->basis)( 2, 0);
            }
//majorAxis and minorAxis is the estimated particle size in px
void ProgSortByStatistics::processInprocessInputPrepareSPTH(MetaData &SF, bool trained)
{
    //#define DEBUG
    PCAMahalanobisAnalyzer tempPcaAnalyzer0;
    PCAMahalanobisAnalyzer tempPcaAnalyzer1;
    PCAMahalanobisAnalyzer tempPcaAnalyzer2;
    PCAMahalanobisAnalyzer tempPcaAnalyzer3;
    PCAMahalanobisAnalyzer tempPcaAnalyzer4;

    //Morphology
    tempPcaAnalyzer0.clear();
    //Signal to noise ratio
    tempPcaAnalyzer1.clear();
    tempPcaAnalyzer2.clear();
    tempPcaAnalyzer3.clear();
    //Histogram analysis, to detect black points and saturated parts
    tempPcaAnalyzer4.clear();

    double sign = 1;//;-1;
    int numNorm = 3;
    int numDescriptors0=numNorm;
    int numDescriptors2=4;
    int numDescriptors3=11;
    int numDescriptors4 = 10;

    MultidimArray<float> v0(numDescriptors0);
    MultidimArray<float> v2(numDescriptors2);
    MultidimArray<float> v3(numDescriptors3);
    MultidimArray<float> v4(numDescriptors4);

    if (verbose>0)
    {
        std::cout << " Sorting particle set by new xmipp method..." << std::endl;
    }

    int nr_imgs = SF.size();
    if (verbose>0)
        init_progress_bar(nr_imgs);

    int c = XMIPP_MAX(1, nr_imgs / 60);
    int imgno = 0, imgnoPCA=0;

    bool thereIsEnable=SF.containsLabel(MDL_ENABLED);
    bool first=true;

    // We assume that at least there is one particle
    size_t Xdim, Ydim, Zdim, Ndim;
    getImageSize(SF,Xdim,Ydim,Zdim,Ndim);

    //Initialization:
    MultidimArray<double> nI, modI, tempI, tempM, ROI;
    MultidimArray<bool> mask;
    nI.resizeNoCopy(Ydim,Xdim);
    modI.resizeNoCopy(Ydim,Xdim);
    tempI.resizeNoCopy(Ydim,Xdim);
    tempM.resizeNoCopy(Ydim,Xdim);
    mask.resizeNoCopy(Ydim,Xdim);
    mask.initConstant(true);

    MultidimArray<double> autoCorr(2*Ydim,2*Xdim);
    MultidimArray<double> smallAutoCorr;

    Histogram1D hist;
    Matrix2D<double> U,V,temp;
    Matrix1D<double> D;

    MultidimArray<int> radial_count;
    MultidimArray<double> radial_avg;
    Matrix1D<int> center(2);
    MultidimArray<int> distance;
    int dim;
    center.initZeros();

    v0.initZeros(numDescriptors0);
    v2.initZeros(numDescriptors2);
    v3.initZeros(numDescriptors3);
    v4.initZeros(numDescriptors4);

    ROI.resizeNoCopy(Ydim,Xdim);
    ROI.setXmippOrigin();
    FOR_ALL_ELEMENTS_IN_ARRAY2D(ROI)
    {
        double temp = std::sqrt(i*i+j*j);
        if ( temp < (Xdim/2))
            A2D_ELEM(ROI,i,j)= 1;
        else
            A2D_ELEM(ROI,i,j)= 0;
    }

    Image<double> img;
    FourierTransformer transformer(FFTW_BACKWARD);

    FOR_ALL_OBJECTS_IN_METADATA(SF)
    {
        if (thereIsEnable)
        {
            int enabled;
            SF.getValue(MDL_ENABLED,enabled,__iter.objId);
            if ( (enabled==-1)  )
            {
                imgno++;
                continue;
            }
        }

        img.readApplyGeo(SF,__iter.objId);
        if (targetXdim!=-1 && targetXdim!=XSIZE(img()))
        	selfScaleToSize(LINEAR,img(),targetXdim,targetXdim,1);

        MultidimArray<double> &mI=img();
        mI.setXmippOrigin();
        mI.statisticsAdjust(0,1);
        mask.setXmippOrigin();
        //The size of v1 depends on the image size and must be declared here
        int numDescriptors1 = XSIZE(mI)/2; //=100;
        MultidimArray<float> v1(numDescriptors1);
        v1.initZeros(numDescriptors1);

        double var = 1;
        normalize(transformer,mI,tempI,modI,0,var,mask);
        modI.setXmippOrigin();
        tempI.setXmippOrigin();
        nI = sign*tempI*(modI*modI);
        tempM = (modI*modI);

        A1D_ELEM(v0,0) = (tempM*ROI).sum();
        int index = 1;
        var+=2;
        while (index < numNorm)
        {
            normalize(transformer,mI,tempI,modI,0,var,mask);
            modI.setXmippOrigin();
            tempI.setXmippOrigin();
            nI += sign*tempI*(modI*modI);
            tempM += (modI*modI);
            A1D_ELEM(v0,index) = (tempM*ROI).sum();
            index++;
            var+=2;
        }

        nI /= tempM;
        tempPcaAnalyzer0.addVector(v0);
        nI=(nI*ROI);

        auto_correlation_matrix(mI,autoCorr);
        if (first)
        {
            radialAveragePrecomputeDistance(autoCorr, center, distance, dim);
            first=false;
        }
        fastRadialAverage(autoCorr, distance, dim, radial_avg, radial_count);

        for (int n = 0; n < numDescriptors1; ++n)
            A1D_ELEM(v1,n)=(float)DIRECT_A1D_ELEM(radial_avg,n);

        tempPcaAnalyzer1.addVector(v1);

#ifdef DEBUG

        //String name = "000005@Images/Extracted/run_002/extra/BPV_1386.stk";
        String name = "000010@Images/Extracted/run_001/extra/KLH_Dataset_I_Training_0028.stk";
        //String name = "001160@Images/Extracted/run_001/DefaultFamily5";

        std::cout << img.name() << std::endl;

        if (img.name()==name2)
        {
            FileName fpName    = "test_1.txt";
            mI.write(fpName);
            fpName    = "test_2.txt";
            nI.write(fpName);
            fpName    = "test_3.txt";
            tempM.write(fpName);
            fpName    = "test_4.txt";
            ROI.write(fpName);
            //exit(1);
        }
#endif
        nI.binarize(0);
        int im = labelImage2D(nI,nI,8);
        compute_hist(nI, hist, 0, im, im+1);
        size_t l;
        int k,i,j;
        hist.maxIndex(l,k,i,j);
        A1D_ELEM(hist,j)=0;
        hist.maxIndex(l,k,i,j);
        nI.binarizeRange(j-1,j+1);

        double x0=0,y0=0,majorAxis=0,minorAxis=0,ellipAng=0;
        size_t area=0;
        fitEllipse(nI,x0,y0,majorAxis,minorAxis,ellipAng,area);

        A1D_ELEM(v2,0)=majorAxis/((img().xdim) );
        A1D_ELEM(v2,1)=minorAxis/((img().xdim) );
        A1D_ELEM(v2,2)= (fabs((img().xdim)/2-x0)+fabs((img().ydim)/2-y0))/((img().xdim)/2);
        A1D_ELEM(v2,3)=area/( (double)((img().xdim)/2)*((img().ydim)/2) );

        for (int n=0 ; n < numDescriptors2 ; n++)
        {
            if ( std::isnan(std::abs(A1D_ELEM(v2,n))))
                A1D_ELEM(v2,n)=0;
        }

        tempPcaAnalyzer2.addVector(v2);

        //mI.setXmippOrigin();
        //auto_correlation_matrix(mI*ROI,autoCorr);
        //auto_correlation_matrix(nI,autoCorr);
        autoCorr.window(smallAutoCorr,-5,-5, 5, 5);
        smallAutoCorr.copy(temp);
        svdcmp(temp,U,D,V);

        for (int n = 0; n < numDescriptors3; ++n)
            A1D_ELEM(v3,n)=(float)VEC_ELEM(D,n); //A1D_ELEM(v3,n)=(float)VEC_ELEM(D,n)/VEC_ELEM(D,0);

        tempPcaAnalyzer3.addVector(v3);


        double minVal=0.;
        double maxVal=0.;
        mI.computeDoubleMinMax(minVal,maxVal);
        compute_hist(mI, hist, minVal, maxVal, 100);

        for (int n=0 ; n <= numDescriptors4-1 ; n++)
        {
            A1D_ELEM(v4,n)= (hist.percentil((n+1)*10));
        }
        tempPcaAnalyzer4.addVector(v4);

#ifdef DEBUG

        if (img.name()==name1)
        {
            FileName fpName    = "test.txt";
            mI.write(fpName);
            fpName    = "test3.txt";
            nI.write(fpName);
        }
#endif
        imgno++;
        imgnoPCA++;

        if (imgno % c == 0 && verbose>0)
            progress_bar(imgno);
    }

    tempPcaAnalyzer0.evaluateZScore(2,20,trained);
    tempPcaAnalyzer1.evaluateZScore(2,20,trained);
    tempPcaAnalyzer2.evaluateZScore(2,20,trained);
    tempPcaAnalyzer3.evaluateZScore(2,20,trained);
    tempPcaAnalyzer4.evaluateZScore(2,20,trained);

    pcaAnalyzer.push_back(tempPcaAnalyzer0);
    pcaAnalyzer.push_back(tempPcaAnalyzer1);
    pcaAnalyzer.push_back(tempPcaAnalyzer1);
    pcaAnalyzer.push_back(tempPcaAnalyzer3);
    pcaAnalyzer.push_back(tempPcaAnalyzer4);

}
Esempio n. 4
0
/* Constructor ------------------------------------------------------------- */
LeafNode::LeafNode(const std::vector < MultidimArray<double> > &leafFeatures,
                   int discrete_levels)
{
    __discreteLevels = discrete_levels;
    K = leafFeatures.size();
    if (__discreteLevels==0)
    {
        // This is a dummy node for features that cannot classify
        MultidimArray<int> newBins(1);
        A1D_ELEM(newBins,0)=0;
        Histogram1D hist;
        hist.resize(1);
        A1D_ELEM(hist,0)=1;
        IrregularHistogram1D irregHist;
        for (int k=0; k<K; k++)
        {
            irregHist.init(hist, newBins);
            irregHist.selfNormalize();
            __leafPDF.push_back(irregHist);
        }
    }
    else
    {
        // Compute the minimum and maximum of each class
        double minval=0., maxval=0.;
        for(int k=0; k<K; k++)
        {
            double minvalk=0., maxvalk=0.;
            leafFeatures[k].computeDoubleMinMax(minvalk, maxvalk);
            if (k==0)
            {
                minval=minvalk;
                maxval=maxvalk;
            }
            else
            {
                minval=std::min(minval,minvalk);
                maxval=std::max(maxval,maxvalk);
            }
        }
        if (minval==maxval)
        {
            __discreteLevels=0;
            return;
        }

        // Compute the PDF of each class
        std::vector<Histogram1D> hist(K);
        for (int k=0; k<K; k++)
        {
            // There is variation of this feature for this class
            compute_hist(leafFeatures[k], hist[k], minval, maxval, 100);
            hist[k] += 1; // Apply Laplace correction
        }

        // Split the histograms into discrete_level (power of 2) bins
        std::queue< Matrix1D<int> > intervals, splittedIntervals;
        Matrix1D<int> limits(2);
        VECTOR_R2(limits,0,99);
        intervals.push(limits);
        int imax=ROUND(log2(__discreteLevels));
        for (int i=0; i<imax; i++)
        {
            // Split all the intervals in the queue
            while (!intervals.empty())
            {
                Matrix1D<int> currentInterval = intervals.front();
                intervals.pop();
                int lsplit = splitHistogramsUsingEntropy(hist,
                             currentInterval(0), currentInterval(1));
                VECTOR_R2(limits,currentInterval(0),lsplit);
                splittedIntervals.push(limits);
                VECTOR_R2(limits,lsplit+1, currentInterval(1));
                splittedIntervals.push(limits);
            }

            // Copy the splitted intervals to the interval list
            while (!splittedIntervals.empty())
            {
                intervals.push(splittedIntervals.front());
                splittedIntervals.pop();
            }
        }

        // Compute the bins of the split
        MultidimArray<int> newBins(__discreteLevels);
        imax=intervals.size();
        for (int i=0; i<imax; i++)
        {
            A1D_ELEM(newBins,i) = intervals.front()(1);
            intervals.pop();
        }

        // Compute now the irregular histograms
        IrregularHistogram1D irregHist;
        for (int k=0; k<K; k++)
        {
            irregHist.init(hist[k], newBins);
            irregHist.selfNormalize();
            __leafPDF.push_back(irregHist);
        }
    }
}
void ProgSortByStatistics::run()
{
    // Process input selfile ..............................................
    SF.read(fn);
    SF.removeDisabled();
    MetaData SF2 = SF;
    SF = SF2;

    bool trained = false;

    if (fn_train != "")
    {
        SFtrain.read(fn_train);
        processInprocessInputPrepareSPTH(SFtrain,trained);
        trained = true;
        processInprocessInputPrepareSPTH(SF,trained);
    }
    else
        processInprocessInputPrepareSPTH(SF,trained);

    int imgno = 0;
    int numPCAs = pcaAnalyzer.size();

    MultidimArray<double> finalZscore(SF.size());
    MultidimArray<double> ZscoreShape1(SF.size()), sortedZscoreShape1;
    MultidimArray<double> ZscoreShape2(SF.size()), sortedZscoreShape2;
    MultidimArray<double> ZscoreSNR1(SF.size()), sortedZscoreSNR1;
    MultidimArray<double> ZscoreSNR2(SF.size()), sortedZscoreSNR2;
    MultidimArray<double> ZscoreHist(SF.size()), sortedZscoreHist;


    finalZscore.initConstant(0);
    ZscoreShape1.resizeNoCopy(finalZscore);
    ZscoreShape2.resizeNoCopy(finalZscore);
    ZscoreSNR1.resizeNoCopy(finalZscore);
    ZscoreSNR2.resizeNoCopy(finalZscore);
    ZscoreHist.resizeNoCopy(finalZscore);
    sortedZscoreShape1.resizeNoCopy(finalZscore);
    sortedZscoreShape2.resizeNoCopy(finalZscore);
    sortedZscoreSNR1.resizeNoCopy(finalZscore);
    sortedZscoreSNR2.resizeNoCopy(finalZscore);
    sortedZscoreHist.resizeNoCopy(finalZscore);

    double zScore=0;
    int enabled;

    FOR_ALL_OBJECTS_IN_METADATA(SF)
    {
        SF.getValue(MDL_ENABLED,enabled,__iter.objId);
        if ( (enabled==-1)  )
        {
            A1D_ELEM(finalZscore,imgno) = 1e3;
            A1D_ELEM(ZscoreShape1,imgno) = 1e3;
            A1D_ELEM(ZscoreShape2,imgno) = 1e3;
            A1D_ELEM(ZscoreSNR1,imgno) = 1e3;
            A1D_ELEM(ZscoreSNR2,imgno) = 1e3;
            A1D_ELEM(ZscoreHist,imgno) = 1e3;
            imgno++;
            enabled = 0;
        }
        else
        {
            for (int num = 0; num < numPCAs; ++num)
            {
                if (num == 0)
                {
                    A1D_ELEM(ZscoreSNR1,imgno) = pcaAnalyzer[num].getZscore(imgno);
                }
                else if (num == 1)
                {
                    A1D_ELEM(ZscoreShape2,imgno) = pcaAnalyzer[num].getZscore(imgno);
                }
                else if (num == 2)
                {
                    A1D_ELEM(ZscoreShape1,imgno) = pcaAnalyzer[num].getZscore(imgno);
                }
                else if (num == 3)
                {
                    A1D_ELEM(ZscoreSNR2,imgno) = pcaAnalyzer[num].getZscore(imgno);
                }
                else
                {
                    A1D_ELEM(ZscoreHist,imgno) = pcaAnalyzer[num].getZscore(imgno);
                }

                if(zScore < pcaAnalyzer[num].getZscore(imgno))
                    zScore = pcaAnalyzer[num].getZscore(imgno);
            }

            A1D_ELEM(finalZscore,imgno)=zScore;
            imgno++;
            zScore = 0;
        }
    }
    pcaAnalyzer.clear();

    // Produce output .....................................................
    MetaData SFout;
    std::ofstream fh_zind;

    if (verbose==2 && !fn_out.empty())
        fh_zind.open((fn_out.withoutExtension() + "_vectors.xmd").c_str(), std::ios::out);

    MultidimArray<int> sorted;
    finalZscore.indexSort(sorted);

    int nr_imgs = SF.size();
    bool thereIsEnable=SF.containsLabel(MDL_ENABLED);
    MDRow row;

    for (int imgno = 0; imgno < nr_imgs; imgno++)
    {
        int isort_1 = DIRECT_A1D_ELEM(sorted,imgno);
        int isort = isort_1 - 1;
        SF.getRow(row, isort_1);

        if (thereIsEnable)
        {
            int enabled;
            row.getValue(MDL_ENABLED, enabled);
            if (enabled==-1)
                continue;
        }

        double zscore=DIRECT_A1D_ELEM(finalZscore,isort);
        double zscoreShape1=DIRECT_A1D_ELEM(ZscoreShape1,isort);
        double zscoreShape2=DIRECT_A1D_ELEM(ZscoreShape2,isort);
        double zscoreSNR1=DIRECT_A1D_ELEM(ZscoreSNR1,isort);
        double zscoreSNR2=DIRECT_A1D_ELEM(ZscoreSNR2,isort);
        double zscoreHist=DIRECT_A1D_ELEM(ZscoreHist,isort);

        DIRECT_A1D_ELEM(sortedZscoreShape1,imgno)=DIRECT_A1D_ELEM(ZscoreShape1,isort);
        DIRECT_A1D_ELEM(sortedZscoreShape2,imgno)=DIRECT_A1D_ELEM(ZscoreShape2,isort);
        DIRECT_A1D_ELEM(sortedZscoreSNR1,imgno)=DIRECT_A1D_ELEM(ZscoreSNR1,isort);
        DIRECT_A1D_ELEM(sortedZscoreSNR2,imgno)=DIRECT_A1D_ELEM(ZscoreSNR2,isort);
        DIRECT_A1D_ELEM(sortedZscoreHist,imgno)=DIRECT_A1D_ELEM(ZscoreHist,isort);

        if (zscore>cutoff && cutoff>0)
        {
            row.setValue(MDL_ENABLED,-1);
            if (addToInput)
                SF.setValue(MDL_ENABLED,-1,isort_1);
        }
        else
        {
            row.setValue(MDL_ENABLED,1);
            if (addToInput)
                SF.setValue(MDL_ENABLED,1,isort_1);
        }

        row.setValue(MDL_ZSCORE,zscore);
        row.setValue(MDL_ZSCORE_SHAPE1,zscoreShape1);
        row.setValue(MDL_ZSCORE_SHAPE2,zscoreShape2);
        row.setValue(MDL_ZSCORE_SNR1,zscoreSNR1);
        row.setValue(MDL_ZSCORE_SNR2,zscoreSNR2);
        row.setValue(MDL_ZSCORE_HISTOGRAM,zscoreHist);

        if (addToInput)
        {
            SF.setValue(MDL_ZSCORE,zscore,isort_1);
            SF.setValue(MDL_ZSCORE_SHAPE1,zscoreShape1,isort_1);
            SF.setValue(MDL_ZSCORE_SHAPE2,zscoreShape2,isort_1);
            SF.setValue(MDL_ZSCORE_SNR1,zscoreSNR1,isort_1);
            SF.setValue(MDL_ZSCORE_SNR2,zscoreSNR2,isort_1);
            SF.setValue(MDL_ZSCORE_HISTOGRAM,zscoreHist,isort_1);
        }

        SFout.addRow(row);
    }

    //Sorting taking into account a given percentage
    if (per > 0)
    {
        MultidimArray<int> sortedShape1,sortedShape2,sortedSNR1,sortedSNR2,sortedHist,
        sortedShapeSF1,sortedShapeSF2,sortedSNR1SF,sortedSNR2SF,sortedHistSF;

        sortedZscoreShape1.indexSort(sortedShape1);
        sortedZscoreShape2.indexSort(sortedShape2);
        sortedZscoreSNR1.indexSort(sortedSNR1);
        sortedZscoreSNR2.indexSort(sortedSNR2);
        sortedZscoreHist.indexSort(sortedHist);
        size_t numPartReject = (size_t)std::floor((per/100)*SF.size());

        for (size_t numPar = SF.size()-1; numPar > (SF.size()-numPartReject); --numPar)
        {
            int isort_1 = DIRECT_A1D_ELEM(sortedShape1,numPar);
            SFout.getRow(row, isort_1);
            row.setValue(MDL_ENABLED,-1);
            SFout.setRow(row,isort_1);

            isort_1 = DIRECT_A1D_ELEM(sortedShape2,numPar);
            SFout.getRow(row, isort_1);
            row.setValue(MDL_ENABLED,-1);
            SFout.setRow(row,isort_1);

            isort_1 = DIRECT_A1D_ELEM(sortedSNR1,numPar);
            SFout.getRow(row, isort_1);
            row.setValue(MDL_ENABLED,-1);
            SFout.setRow(row,isort_1);

            isort_1 = DIRECT_A1D_ELEM(sortedSNR2,numPar);
            SFout.getRow(row, isort_1);
            row.setValue(MDL_ENABLED,-1);
            SFout.setRow(row,isort_1);

            isort_1 = DIRECT_A1D_ELEM(sortedHist,numPar);
            SFout.getRow(row, isort_1);
            row.setValue(MDL_ENABLED,-1);
            SFout.setRow(row,isort_1);

            if (addToInput)
            {
                ZscoreShape1.indexSort(sortedShapeSF1);
                ZscoreShape2.indexSort(sortedShapeSF2);
                ZscoreSNR1.indexSort(sortedSNR1SF);
                ZscoreSNR2.indexSort(sortedSNR2SF);
                ZscoreHist.indexSort(sortedHistSF);

                isort_1 = DIRECT_A1D_ELEM(sortedShapeSF1,numPar);
                SF.getRow(row, isort_1);
                row.setValue(MDL_ENABLED,-1);
                SF.setRow(row,isort_1);

                isort_1 = DIRECT_A1D_ELEM(sortedShapeSF2,numPar);
                SF.getRow(row, isort_1);
                row.setValue(MDL_ENABLED,-1);
                SF.setRow(row,isort_1);

                isort_1 = DIRECT_A1D_ELEM(sortedSNR1SF,numPar);
                SF.getRow(row, isort_1);
                row.setValue(MDL_ENABLED,-1);
                SF.setRow(row,isort_1);

                isort_1 = DIRECT_A1D_ELEM(sortedSNR2SF,numPar);
                SF.getRow(row, isort_1);
                row.setValue(MDL_ENABLED,-1);
                SF.setRow(row,isort_1);

                isort_1 = DIRECT_A1D_ELEM(sortedHistSF,numPar);
                SF.getRow(row, isort_1);
                row.setValue(MDL_ENABLED,-1);
                SF.setRow(row,isort_1);
            }
        }
    }

    if (verbose==2)
        fh_zind.close();
    if (!fn_out.empty())
    {
        MetaData SFsorted;
        SFsorted.sort(SFout,MDL_ZSCORE);
        SFout.write(fn_out,MD_OVERWRITE);
    }
    if (addToInput)
    {
        MetaData SFsorted;
        SFsorted.sort(SF,MDL_ZSCORE);
        SFsorted.write(fn,MD_APPEND);
    }
}