bool GVFplugin::dofunc(const QString & func_name, const V3DPluginArgList & input, V3DPluginArgList & output, V3DPluginCallback2 & callback,  QWidget * parent)
{


    if (func_name == tr("gvf_segmentation"))
	{
        int c=1;

        gvfsegPara segpara;  // default values
        segpara.diffusionIteration = 5;
        segpara.fusionThreshold = 3;
        segpara.minRegion = 10;

        vector<char*> infiles, inparas, outfiles;
        if(input.size() >= 1) infiles = *((vector<char*> *)input.at(0).p);
        if(input.size() >= 2)
        {
            inparas = *((vector<char*> *)input.at(1).p);
        if(inparas.size() >= 1) c = atoi(inparas.at(0));
        if(inparas.size() >= 2) segpara.diffusionIteration = atoi(inparas.at(1));
        if(inparas.size() >= 3) segpara.fusionThreshold = atoi(inparas.at(2));
        if(inparas.size() >= 4) segpara.minRegion = atoi(inparas.at(3));
        if(output.size() >= 1) outfiles = *((vector<char*> *)output.at(0).p);
        }
        char * inimg_file = ((vector<char*> *)(input.at(0).p))->at(0);
        char * outimg_file = ((vector<char*> *)(output.at(0).p))->at(0);




        cout<<"channel choice "<<c<<endl;
        cout<<"diffusion Iterations "<<segpara.diffusionIteration<<endl;
        cout<<"fusion threshold "<<segpara.fusionThreshold<<endl;
        cout<<"minimum region size "<<segpara.minRegion<<endl;
        cout<<"inimg_file = "<<inimg_file<<endl;
        cout<<"outimg_file = "<<outimg_file<<endl;

        // check the input parameters for invalid choices:

        if ((segpara.diffusionIteration<1)||(segpara.fusionThreshold<1)||(segpara.minRegion)<0)
        {
            cout<< "* * * * * * * * * * * * *  "<<endl;
            cout<< "*"<<endl;
            cout<< "INVALID parameter selection, type "<<endl;
            cout<<" vaa3d -x gvf_cellseg -f help "<<endl;
            cout<<"for more information"<<endl;
            cout<< "* * * * * * * * * * * * *  "<<endl;
            cout<<""<<endl;

return false;
        }


        V3DLONG in_sz[4];
        int datatype;
        unsigned char * data1d = 0;
        if(!simple_loadimage_wrapper(callback, inimg_file, data1d, in_sz, datatype))
        {
            cerr<<"load image "<<inimg_file<<" error!"<<endl;
            return false;
        }



        // allocate memory for the images

        Vol3DSimple <unsigned char> * tmp_inimg = 0;
        Vol3DSimple <USHORTINT16> * tmp_outimg = 0;
        try
        {
            tmp_inimg = new Vol3DSimple <unsigned char> (in_sz[0], in_sz[1], in_sz[2]);
            tmp_outimg = new Vol3DSimple <USHORTINT16> (in_sz[0], in_sz[1], in_sz[2]);
        }
        catch (...)
        {
            v3d_msg("Unable to allocate memory for processing.");
            if (tmp_inimg) {delete tmp_inimg; tmp_inimg=0;}
            if (tmp_outimg) {delete tmp_outimg; tmp_outimg=0;}
            return false;
        }



        //load image
        //
        Image4DSimple * temp4D = callback.loadImage(inimg_file);
        in_sz[0]=temp4D->getXDim();
        in_sz[1]=temp4D->getYDim();
        in_sz[2]=temp4D->getZDim();
        in_sz[3]=temp4D->getCDim();
                if (in_sz[3]==1)
                {
                    c=1;
                    cout<< "Image only has 1 channel, segmenting channel 1"<<endl;
                }

                if ((c>in_sz[3])||(c<1))
                {
                    cout<< "* * * * * * * * * * * * *  "<<endl;
                    cout<< "*"<<endl;
                    cout<< "INVALID CHANNEL SELECTION: User selected channel "<<c<< "; image has "<< in_sz[3] << "  channels."<<endl;
                    cout<< " aborting segmentation !"<<endl;
                    cout<<"*"<<endl;
                    cout<< "* * * * * * * * * * * * *  "<<endl;
                    cout<<""<<endl;

return false;
                }



//transfer single channel of data from Image4DSimple to old Vol3DSimple class

        memcpy((void *)tmp_inimg->getData1dHandle(), (void *)temp4D->getRawDataAtChannel(c-1), in_sz[0]*in_sz[1]*in_sz[2]);
        //now do computation using external function call

        bool b_res = gvfCellSeg(tmp_inimg, tmp_outimg, segpara);

        // clear out temporary space
        if (tmp_inimg) {delete tmp_inimg; tmp_inimg=0;}




        // now write to file
        in_sz[3]=1;//for single channel output from gvfCellSeg
        simple_saveimage_wrapper(callback, outimg_file, (unsigned char *)tmp_outimg->getData1dHandle(), in_sz, 2); //the output of gvfCellSeg is in 16bit


        // clear out temporary space
        if (tmp_outimg) {delete tmp_outimg; tmp_outimg=0;}

        if (temp4D) {delete temp4D; temp4D=0;}






        cout<<"Finished GVF Segmentation"<<endl;
	}
	else if (func_name == tr("help"))
	{
        cout<<endl;
        cout<<endl;
        cout<<" GVF segmentation plugin usage :  vaa3d -x gvf_cellseg  -f  gvf_segmentation -i <input filename> -o <output filename -p <c> <iter> <fusion> <size>"<<endl;
        cout<<" parameters:    (default values in parentheses) "<<endl;
        cout<<"c        =  channel of input file to use for segmentation    (1) "<<endl;
        cout<<"iter     =  number of diffusion iterations  (must be > 0)    (5)    "<<endl;
        cout<<"fusion   =  fusion size threshold         (must be > 0)      (3)  "<<endl;
        cout<<"size     =  minimum region size in voxels                   (10)"<<endl;


    }
	else return false;

	return true;
}
bool  profile_swc_func(V3DPluginCallback2 &callback, const V3DPluginArgList & input, V3DPluginArgList & output)
{
    vector<char*> infiles, inparas, outfiles;
    if(input.size() >= 1) infiles = *((vector<char*> *)input.at(0).p);
    if(input.size() >= 2) inparas = *((vector<char*> *)input.at(1).p);
    if(output.size() >= 1) outfiles = *((vector<char*> *)output.at(0).p);

    if(infiles.size() != 2 && infiles.size() != 3)
    {
        cerr<<"Invalid input"<<endl;
        return false;
    }
    QString imageFileName = QString(infiles[0]);
    QString swcFileName = QString(infiles[1]);
    QString output_csv_file;
    if(!outfiles.empty())
        output_csv_file = QString(outfiles[0]);
    else
        output_csv_file = swcFileName + ".csv";

    float  dilate_ratio = (inparas.size() >= 1) ? atof(inparas[0]) : 3.0;
    int  flip = (inparas.size() >= 2) ? atoi(inparas[1]) : 1;
    int  invert = (inparas.size() >= 3) ? atoi(inparas[2]) : 1;

    cout<<"inimg_file = "<< imageFileName.toStdString()<<endl;
    cout<<"inswc_file = "<< swcFileName.toStdString()<<endl;
    cout<<"output_file = "<< output_csv_file.toStdString()<<endl;
    cout<<"dilate_ratio = "<< dilate_ratio<<endl;
    cout<<"flip y = "<< flip <<endl;
    cout<<"invert intensity = "<< invert <<endl;

    NeuronTree  neuronTree;

    if (swcFileName.endsWith(".swc") || swcFileName.endsWith(".SWC"))
    {
        neuronTree = readSWC_file(swcFileName);
    }
    else
    {
        cout<<"The file type you specified is not supported."<<endl;
        return false;
    }

    Image4DSimple *image = callback.loadImage((char * )imageFileName.toStdString().c_str());

    QList<IMAGE_METRICS> result_metrics = intensity_profile(neuronTree, image, dilate_ratio,flip,invert, callback);
    IMAGE_METRICS m_stats = result_metrics[0];

    /*
    ENSEMBLE_METRICS m_stats = stats_ensemble(result_metrics);
    */

    cout << "Overall Contrast-to-Background Ratio:" << m_stats.cnr << "\n"
         << "Overall Dynamic Range:"<< m_stats.dy << "\n"
         << "Mean BG Intensity:" << m_stats.bg_mean << ", with std = "    << m_stats.bg_std << "\n"
         << "Mean FG Intensity:" << m_stats.fg_mean << ", with std = "    << m_stats.fg_std << "\n"
         << "Mean Tubularity:"   << m_stats.tubularity_mean << ", with std = " << m_stats.tubularity_std << "\n"
         << endl;

    if (result_metrics.isEmpty())
    {
        cout<<"Error in intensity_profile() !"<<endl;
        return false;
    }
    else{
        if (!writeMetrics2CSV(result_metrics, output_csv_file))
        {
            cout<< "error in writeMetrics2CSV()" <<endl;
        }
    }
    cout << "Segment type-specific screening metrics are exported in:  " << output_csv_file.toStdString() <<endl;

	return true;

}
bool findedgeimg(V3DPluginCallback2 &callback, const V3DPluginArgList & input, V3DPluginArgList & output)
{
    cout<<"Welcome to Label edge of a mask image"<<endl;
    if (output.size() != 1) return false;

    int method_code = 0;
    if (input.size()>=2)
    {
        vector<char*> paras = (*(vector<char*> *)(input.at(1).p));
        if(paras.size() >= 1) method_code = atoi(paras.at(0));
    }

    char * inimg_file = ((vector<char*> *)(input.at(0).p))->at(0);
    char * outimg_file = ((vector<char*> *)(output.at(0).p))->at(0);
    cout<<"method_code = "<<method_code<<endl;
    cout<<"inimg_file = "<<inimg_file<<endl;
    cout<<"outimg_file = "<<outimg_file<<endl;

    Image4DSimple *image = callback.loadImage(inimg_file);
    if (!image || !image->valid())
    {
        cerr<<"load image "<<inimg_file<<" error!"<<endl;
        return false;
    }

    V3DLONG szx=image->getXDim(),
            szy=image->getYDim(),
            szz=image->getZDim(),
            szc=image->getCDim();
    V3DLONG N = image->getTotalUnitNumber();

    //create the output buffer
    unsigned char *outputData = 0;
    try
    {
        outputData = new unsigned char [N];
        for (V3DLONG tmpi=0; tmpi<N; ++tmpi) outputData[tmpi] = 0; //preset to be all 0
    }
    catch (...)
    {
        v3d_msg("Fail to allocate memory.");
        if (outputData) {
            delete []outputData;
            outputData=0;
        }
        return false;
    }

    Image4DSimple outputImage;
    outputImage.setData((unsigned char*)outputData, szx, szy, szz, szc, V3D_UINT8);
    Image4DProxy<Image4DSimple> outputIProxy(&outputImage);

    //now do computation
    {
        bool bset255 = (method_code==0) ? false : true;

        Image4DProxy<Image4DSimple> p(image);
        Image4DProxy_foreach(p, ix, iy, iz, ic)
        {
            double v = p.value_at(ix, iy, iz, ic);
            V3DLONG cx, cy, cz;

            bool bb=false;
            for (cz = iz-1; cz<iz+2; ++cz)
            {
                for (cy = iy-1; cy<iy+2; ++cy)
                {
                    for (cx = ix-1; cx<ix+2; ++cx)
                    {
                        if (!p.is_inner(cx, cy, cz, ic))
                            continue;
                        if (v!=p.value_at(cx, cy, cz, ic))
                        {
                            *outputIProxy.at(ix, iy, iz, ic) = (bset255) ? 255 : v;
                            bb = true;
                            break;
                        }
                    }
                    if (bb)	break;
                }
                if (bb) break;
            }

            //note that all value had been preset as 0, thus no need to set as the background color in case not an edge point
        }
    }
bool autotrace(const V3DPluginArgList & input, V3DPluginArgList & output,V3DPluginCallback2 &callback)
{
    cout<<"Welcome to MOST tracing"<<endl;
    unsigned int c=1;
    int InitThreshold = 20;
    seed_size_all = 20;
    int slipsize=20;

    if (input.size()>=2)
    {
        vector<char*> paras = (*(vector<char*> *)(input.at(1).p));
        cout<<paras.size()<<endl;
        if(paras.size() >= 1) c = atoi(paras.at(0));
        if(paras.size() >= 2) InitThreshold = atoi(paras.at(1));
        if(paras.size() >= 3) seed_size_all = atoi(paras.at(2));
        if(paras.size() >= 4) slipsize = atoi(paras.at(3));
    }

    char * inimg_file = ((vector<char*> *)(input.at(0).p))->at(0);

    cout<<"ch = "<<c<<endl;
    cout<<"threshold = "<<InitThreshold<<endl;
    cout<<"inimg_file = "<<inimg_file<<endl;
    cout<<"seedsize = "<<seed_size_all<<endl;
    cout<<"slipsize = "<<slipsize<<endl;

    Image4DSimple *subject = callback.loadImage(inimg_file);
    if(!subject || !subject->valid())
    {
         v3d_msg("Fail to load the input image.",0);
         if (subject) {delete subject; subject=0;}
         return false;
    }

    if( c < 1 || c > subject->getCDim())
    {
         v3d_msg("Invalid channel input.",0);
         if (subject) {delete subject; subject=0;}
         return false;
    }

    V3DLONG N = subject->getXDim();
    V3DLONG M = subject->getYDim();
    V3DLONG P = subject->getZDim();

    V3DLONG pagesz = N*M*P;
    int datatype = subject->getDatatype();
    unsigned char *data1d = subject->getRawDataAtChannel(c-1);

    unsigned char *output_image=0;
    switch (datatype)
    {
    case V3D_UINT8:
        try {output_image = new unsigned char [pagesz];}
        catch(...)  {v3d_msg("cannot allocate memory for output_image.",0); return false;}
        for(V3DLONG i = 0; i<pagesz; i++)
            output_image[i] = data1d[i];


        break;
        default: v3d_msg("Invalid data type. Do nothing.",0); return false;
    }


    MOSTImage img;
    img.setData( (unsigned char*)output_image, subject->getXDim(),subject->getYDim(),subject->getZDim(),subject->getCDim(),subject->getDatatype());
    QString swcfile = QString(inimg_file) + "_MOST.swc";

    LandmarkList seedList;
    QTime qtime_seed;
    qtime_seed.start();
    if(1)
    {
        for(int i =1;i<=N;i+=20)
        img.auto_detect_seedx(seedList,i,InitThreshold,seed_size_all);
    }
    if(1)
    {
        for(int i =1;i<=M;i+=20)
        img.auto_detect_seedy(seedList,i,InitThreshold,seed_size_all);
    }
    if(1)
    {
        for(int i =1;i<=P;i+=20)
        img.auto_detect_seedz(seedList,i,InitThreshold,seed_size_all);
    }

    qDebug("  cost time seed = %g sec", qtime_seed.elapsed()*0.001);
    static long init_flag = 0;

    for(init_flag = 0;init_flag<subject->getTotalUnitNumberPerChannel();init_flag++)
    {
        visited.push_back(false);
    }

    // converte the formate
    NeuronTree vt;
    QTime qtime;
    qtime.start();
    vt = img.trace_seed_list(seedList, visited,InitThreshold,1.0,1.0,1.0,swcfile,slipsize,0);
    qDebug("  cost time totol= %g sec", qtime.elapsed()*0.001);

    v3d_msg(QString("\nNow you can drag and drop the generated swc fle [%1] into Vaa3D.").arg(swcfile),0);
    if (subject) {delete subject; subject=0;}
    return true;


}
bool dark_pruning_func(const V3DPluginArgList & input, V3DPluginArgList & output, V3DPluginCallback2 &callback)
{

        if(input.size() <2 )
        {
            cerr<<"You must specify input eswc file and the corresponding image file."<<endl;
            return false;
        }




        //parsing input
        vector<char *> * inlist =  (vector<char*> *)(input.at(0).p);
        if (inlist->size()<2)
        {
            cerr<<"You must specify input eswc file and the corresponding image file."<<endl;
            return false;
        }

        //parsing output
        vector<char *> * outlist = (vector<char*> *)(output.at(0).p);
        if (outlist->size() > 1)
        {
            cerr << "You can only specify one output file"<<endl;
            return false;
        }

        //parsing parameters
        int visible_thre =0;
        vector<char*> * paras = (vector<char*> *)(input.at(1).p);
        if (paras->size() == 1)
        {
            visible_thre = atoi(paras->at(0));
            cout<<"The visible threshold for dark pruning is: "<<visible_thre<<endl;

        }
        else
        {
            cerr<<"One ( and only one) parameter is required."<<endl;
            return false;
        }



        QString input_swc_fn = QString(inlist->at(0));
        NeuronTree input_nt = readSWC_file(input_swc_fn);


         Image4DSimple * p4dImage = callback.loadImage( inlist->at(1) );
        if (!p4dImage || !p4dImage->valid())
            return false;



        QString outfileName;
        if (outlist->size()==0)
            outfileName = input_swc_fn + "_dark_pruned.swc";
        else
            outfileName = QString(outlist->at(0));

        QList<NeuronSWC> result_swc;
        if (!dark_pruning (input_nt, result_swc,p4dImage,visible_thre))
        {
            cerr<<"Error in dark pruning."<<endl;
            return false;
        }

        export_listNeuron_2swc(result_swc,qPrintable(outfileName));
        printf("%s has been generated successfully\n",qPrintable(outfileName));

        return true;


}