void processImage(V3DPluginCallback2 &callback, QWidget *parent)
{
    v3dhandle curwin = callback.currentImageWindow();
    if (!curwin)
    {
        v3d_msg("You don't have any image open in the main window.");
        return;
    }
	
    Image4DSimple* p4DImage = callback.getImage(curwin);
    QString imgname = callback.getImageName(curwin);
	
    if (!p4DImage)
    {
        v3d_msg("The image pointer is invalid. Ensure your data is valid and try again!");
        return;
    }

    int tmpx,tmpy,tmpz,x1,y1,z1;
	LandmarkList listLandmarks = callback.getLandmark(curwin);
	LocationSimple tmpLocation(0,0,0);
	int marknum = listLandmarks.count();
    if(marknum ==0)
    {
        v3d_msg("No markers in the current image, please double check.");
        return;
    }

    UndirectedGraph g(marknum);

    for (int i=0;i<marknum;i++)
    {
        tmpLocation = listLandmarks.at(i);
        tmpLocation.getCoord(tmpx,tmpy,tmpz);
        x1 = tmpx;
        y1 = tmpy;
        z1 = tmpz;
        for (int j=0;j<marknum;j++)
        {
            EdgeQuery edgeq = edge(i, j, *&g);
            if (!edgeq.second && i!=j)
            {
                tmpLocation = listLandmarks.at(j);
                tmpLocation.getCoord(tmpx,tmpy,tmpz);
                double Vedge = sqrt(double(x1-tmpx)*double(x1-tmpx) + double(y1-tmpy)*double(y1-tmpy) + double(z1-tmpz)*double(z1-tmpz));
                add_edge(i, j, LastVoted(i, Weight(Vedge)), *&g);
            }
        }
    }

 //   property_map<UndirectedGraph, edge_weight_t>::type weightmap = get(edge_weight, *&g);
    vector < graph_traits < UndirectedGraph >::vertex_descriptor > p(num_vertices(*&g));
    prim_minimum_spanning_tree(*&g, &p[0]);

    NeuronTree marker_MST;
    QList <NeuronSWC> listNeuron;
    QHash <int, int>  hashNeuron;
    listNeuron.clear();
    hashNeuron.clear();

    for (std::size_t i = 0; i != p.size(); ++i)
    {
        NeuronSWC S;
        tmpLocation = listLandmarks.at(i);
        tmpLocation.getCoord(tmpx,tmpy,tmpz);
        int pn;
        if(p[i] == i)
            pn = -1;
        else
            pn = p[i] + 1;

        S.n 	= i+1;
        S.type 	= 7;
        S.x 	= tmpx;
        S.y 	= tmpy;
        S.z 	= tmpz;
        S.r 	= 1;
        S.pn 	= pn;
        listNeuron.append(S);
        hashNeuron.insert(S.n, listNeuron.size()-1);
    }

    marker_MST.n = -1;
    marker_MST.on = true;
    marker_MST.listNeuron = listNeuron;
    marker_MST.hashNeuron = hashNeuron;

    /*
	double** markEdge = new double*[marknum];
	for(int i = 0; i < marknum; i++)
	{
		markEdge[i] = new double[marknum];

	}

	
	for (int i=0;i<marknum;i++)
	{
		tmpLocation = listLandmarks.at(i);
		tmpLocation.getCoord(tmpx,tmpy,tmpz);
		x1 = tmpx;
		y1 = tmpy;
		z1 = tmpz;
		for (int j=0;j<marknum;j++)
		{
			tmpLocation = listLandmarks.at(j);
			tmpLocation.getCoord(tmpx,tmpy,tmpz);
            markEdge[i][j] = sqrt(double(x1-tmpx)*double(x1-tmpx) + double(y1-tmpy)*double(y1-tmpy) + double(z1-tmpz)*double(z1-tmpz));
		}
	}
	
    //NeutronTree structure
    NeuronTree marker_MST;
    QList <NeuronSWC> listNeuron;
    QHash <int, int>  hashNeuron;
    listNeuron.clear();
    hashNeuron.clear();

    //set node

    NeuronSWC S;
    tmpLocation = listLandmarks.at(0);
    tmpLocation.getCoord(tmpx,tmpy,tmpz);

    S.n 	= 1;
    S.type 	= 7;
    S.x 	= tmpx;
    S.y 	= tmpy;
    S.z 	= tmpz;
    S.r 	= 1;
    S.pn 	= -1;
    listNeuron.append(S);
    hashNeuron.insert(S.n, listNeuron.size()-1);

    int* pi = new int[marknum];
    for(int i = 0; i< marknum;i++)
        pi[i] = 0;
    pi[0] = 1;
    int indexi,indexj;
    for(int loop = 0; loop<marknum;loop++)
    {
        double min = INF;
        for(int i = 0; i<marknum; i++)
        {
            if (pi[i] == 1)
            {
                for(int j = 0;j<marknum; j++)
                {
                    if(pi[j] == 0 && min > markEdge[i][j])
                    {
                        min = markEdge[i][j];
                        indexi = i;
                        indexj = j;
                    }
                }
            }

        }
        if(indexi>=0)
        {
            tmpLocation = listLandmarks.at(indexj);
            tmpLocation.getCoord(tmpx,tmpy,tmpz);
            S.n 	= indexj+1;
            S.type 	= 7;
            S.x 	= tmpx;
            S.y 	= tmpy;
            S.z 	= tmpz;
            S.r 	= 1;
            S.pn 	= indexi+1;
            listNeuron.append(S);
            hashNeuron.insert(S.n, listNeuron.size()-1);

        }else
        {
            break;
        }
        pi[indexj] = 1;
        indexi = -1;
        indexj = -1;
    }
    marker_MST.n = -1;
    marker_MST.on = true;
    marker_MST.listNeuron = listNeuron;
    marker_MST.hashNeuron = hashNeuron;

*/
    QString outfilename = imgname + "_boost_marker.swc";
    if (outfilename.startsWith("http", Qt::CaseInsensitive))
    {
        QFileInfo ii(outfilename);
        outfilename = QDir::home().absolutePath() + "/" + ii.fileName();
    }
    //v3d_msg(QString("The anticipated output file is [%1]").arg(outfilename));
    writeSWC_file(outfilename,marker_MST);
    v3d_msg(QString("You have totally [%1] markers for the file [%2] and the computed MST has been saved to the file [%3]").arg(marknum).arg(imgname).arg(outfilename));
    return;
}
Exemple #2
0
void reconstruction_func(V3DPluginCallback2 &callback, QWidget *parent, input_PARA &PARA, bool bmenu)
{
    unsigned char* data1d = 0;
    V3DLONG N,M,P,sc,c;
    V3DLONG in_sz[4];
    v3dhandle curwin;
    if(bmenu)
    {
        curwin = callback.currentImageWindow();
        v3dhandle curwin = callback.currentImageWindow();
        if (!curwin)
        {
            QMessageBox::information(0, "", "You don't have any image open in the main window.");
            return;
        }

        Image4DSimple* p4DImage = callback.getImage(curwin);

        if (!p4DImage)
        {
            QMessageBox::information(0, "", "The image pointer is invalid. Ensure your data is valid and try again!");
            return;
        }


        data1d = p4DImage->getRawData();
        N = p4DImage->getXDim();
        M = p4DImage->getYDim();
        P = p4DImage->getZDim();
        sc = p4DImage->getCDim();

        in_sz[0] = N;
        in_sz[1] = M;
        in_sz[2] = P;
        in_sz[3] = sc;


        PARA.inimg_file = p4DImage->getFileName();
    }
    else
    {
        int datatype = 0;
        if (!simple_loadimage_wrapper(callback,PARA.inimg_file.toStdString().c_str(), data1d, in_sz, datatype))
        {
            fprintf (stderr, "Error happens in reading the subject file [%s]. Exit. \n",PARA.inimg_file.toStdString().c_str());
            return;
        }
        N = in_sz[0];
        M = in_sz[1];
        P = in_sz[2];
        sc = in_sz[3];

    }

    //main neuron reconstruction code

    //// THIS IS WHERE THE DEVELOPERS SHOULD ADD THEIR OWN NEURON TRACING CODE
//  ofstream oImgInfofile;
    string sImgPath = PARA.inimg_file.toStdString();
    g_sAppDir = normalizePath(parentPath(sImgPath));

//    g_sImageInfoPath = g_sAppDir + g_sImageInfoName;
//    g_sInputRawFilePath = g_sAppDir + g_sInputRawFileName;
    QString swc_name = PARA.inimg_file + "_nctuTW.swc";
    g_sOutSwcFilePath = swc_name.toStdString();
    //g_sOutSwcFilePath = g_sAppDir+ g_sOutSwcFileName;

    size_t nDataSize = N * M * P * sc ;

    width = N;
    height = M;
    zSize = P;

//    oImgInfofile.open(g_sImageInfoPath.data(), ios::out|ios::binary);
//    if(oImgInfofile.is_open()){
//        oImgInfofile << N << " " << M << " " << P << endl;
//        oImgInfofile.close();
//    }

    imgBuf_raw = new unsigned char [nDataSize];
    memcpy(imgBuf_raw, data1d, nDataSize);

//    ofstream oRawFile;
//    oRawFile.open(g_sInputRawFilePath.data(), ios::out|ios::binary);
//    if(oRawFile.is_open()){
//        oRawFile.write((char *)data1d, nDataSize);
//        oRawFile.close();
//    }


/*
    // For debug
    if(nParaState == QDialog::Accepted){
        std::string sPara = "Threshold = " + toString(g_rThreshold) + "; " +
                            "Soma = (" + toString(g_nSomaX) + ", " + toString(g_nSomaY) + ", " + toString(g_nSomaZ) + ")";
        v3d_msg(QString(sPara.c_str()));
    }
*/
    QDlgPara* pqDlgPara;

    g_nSomaX = -1;
    g_nSomaY = -1;
    g_nSomaZ = -1;

    int nParaState = 1;

    if(bmenu)       //ui
    {
        LandmarkList Landmark;
        Landmark = callback.getLandmark(curwin);
        if(Landmark.size()>0)
        {
            g_nSomaX = Landmark.at(0).x-1;
            g_nSomaY = Landmark.at(0).y-1;
            g_nSomaZ = Landmark.at(0).z-1;
        }
        pqDlgPara = new QDlgPara(parent);
        nParaState = pqDlgPara->exec();

    }
    else        //command line
    {    
        QList<ImageMarker> file_inmarkers;
        if(!PARA.inmarker_file.isEmpty())
        {
            file_inmarkers = readMarker_file(PARA.inmarker_file);
            g_nSomaX = file_inmarkers.at(0).x;
            g_nSomaY = file_inmarkers.at(0).y;
            g_nSomaZ = file_inmarkers.at(0).z;
        }
        else
        {
           g_nSomaX = -1;
           g_nSomaY = -1;
           g_nSomaZ = -1;
        }
        g_rThreshold = PARA.threshold;
    }


    if(nParaState)
    {
        NeuronTracingMain();
        v3d_msg(QString("Now you can drag and drop the generated swc fle [%1] into Vaa3D.").arg(swc_name.toStdString().c_str()),bmenu);
    }

    if(bmenu) delete pqDlgPara;
     bmenu=true;
    //Output

//    NeuronTree nt;
    //QString swc_name = PARA.inimg_file + "_nctuTW.swc";
//	nt.name = "nctuTW";
//    writeSWC_file(swc_name.toStdString().c_str(),nt);

    //QString swc_name(g_sOutSwcFilePath.data());
    //Output

    if(!bmenu)
    {
        if(data1d) {delete []data1d; data1d = 0;}
    }

    delete [] imgBuf_raw;

    return;
}
//void startVesselTracing ( V3DPluginCallback2 &v3d, QWidget *parent )
void startVesselTracing(V3DPluginCallback2 &v3d,int xflag,int yflag,int zflag,int xbegin, int xend,int xdis,int ybegin,int yend,int ydis,int zbegin,int zend,int zdis,QString swcfile,int slipsize,int pruning_flag,int c)
{
    v3dhandle curwin = v3d.currentImageWindow();
    if (!curwin)
    {
        v3d_msg("You don't have any image open in the main window.");
        return;
    }
    //ensure the 3d viewer window is open; if not, then open it
   // v3d.open3DWindow(curwin);

    // get land mark list

    LandmarkList seedList = v3d.getLandmark(curwin);

    Image4DSimple* oldimg = v3d.getImage(curwin);
    unsigned char* data1d = oldimg->getRawDataAtChannel(c-1);

    ImagePixelType pixeltype = oldimg->getDatatype();
    V3DLONG pagesz = oldimg->getTotalUnitNumberPerChannel();
    unsigned char *output_image=0;
    switch (pixeltype)
    {
    case V3D_UINT8:
        try {output_image = new unsigned char [pagesz];}
        catch(...)  {v3d_msg("cannot allocate memory for output_image."); return;}

        for(V3DLONG i = 0; i<pagesz; i++)
            output_image[i] = data1d[i];

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

    V3DLONG in_sz[4];
    in_sz[0] =  oldimg->getXDim(); in_sz[1] =  oldimg->getYDim(); in_sz[2] =  oldimg->getZDim();in_sz[3] = 1;

   // simple_saveimage_wrapper(v3d, "temp.v3draw",  (unsigned char *)output_image, in_sz, pixeltype);


    MOSTImage img;
    // set data
    img.setData( (unsigned char*)output_image, oldimg->getXDim(),oldimg->getYDim(),oldimg->getZDim(),oldimg->getCDim(),oldimg->getDatatype());


    if ( seedList.isEmpty() )
            {
               QTime qtime_seed;
               qtime_seed.start();
               //img.auto_detect_seedz(seedList,img.getZDim()/2);
               if(xflag)
               {
                   for(int i =xbegin;i<=xend;i+=xdis)
                   img.auto_detect_seedx(seedList,i,InitThreshold,seed_size_all);
                  // img.auto_detect_seedx(seedList,xend);
               }
               if(yflag)
               {
                   for(int i =ybegin;i<=yend;i+=ydis)
                   img.auto_detect_seedy(seedList,i,InitThreshold,seed_size_all);
                  // img.auto_detect_seedy(seedList,yend);
               }
               if(zflag)
               {
                   for(int i =zbegin;i<=zend;i+=zdis)
                   img.auto_detect_seedz(seedList,i,InitThreshold,seed_size_all);
                   //img.auto_detect_seedz(seedList,zend);
               }

               qDebug("  cost time seed = %g sec", qtime_seed.elapsed()*0.001);
            }
    // clear visited, only excute once
    static long init_flag = 0;
   /* if ( init_flag <= 0 )
    {
        visited.fill( false, oldimg->getTotalUnitNumber());
        init_flag ++;
    }*/
    for(init_flag = 0;init_flag<oldimg->getTotalUnitNumber();init_flag++)
        {
            visited.push_back(false);
        }

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

     v3d_msg(QString("Now you can drag and drop the generated swc fle [%1] into Vaa3D.").arg(swcfile),1);


//    NeuronTree vt_old = v3d.getSWC(curwin);

    // visualization
  //  v3d.setLandmark(curwin, seedList);
   // v3d.setSWC(curwin,vt);
  //  v3d.pushObjectIn3DWindow(curwin);
  //  v3d.updateImageWindow(curwin);
    //img.~MOSTImage();
}
bool do_AtlasGuidedStrAnno(V3DPluginCallback2 &callback,
     QString &qs_filename_img, QString &qs_filename_marker_input,  // input files
     QString &qs_filename_atals_input, QString &qs_filename_celloi_input, QString &qs_filename_celloi_2_input,
     CSParas &paras_str, CParas &paras_anno, bool &b_use_celloi_2, // paras
     QString &qs_filename_atals_output, QString &qs_filename_seglabel_output ) // output files
{
	//------------------------------------------------------------------------------------------------------------------------------------
	printf("1. Import image. \n");
	unsigned char *p_img_input=0;
    V3DLONG sz_img_input[4];
	int datatype_input=0;
	if(!paras_str.b_imgfromV3D)
	{
		if(qs_filename_img.isEmpty())
		{
			v3d_msg(QString("invalid image path!"));
			return false;
		}
        if(!simple_loadimage_wrapper(callback, (char *)qPrintable(qs_filename_img),p_img_input,sz_img_input,datatype_input))
		{
			v3d_msg(QString("open file [%1] failed!").arg(qs_filename_img));
			return false;
		}
		printf("\t>>read image file [%s] complete.\n",qPrintable(qs_filename_img));
	}
	else
	{
		printf("\t>>import image from V3D. \n");
		v3dhandleList h_wndlist=callback.getImageWindowList();
		if(h_wndlist.size()<1)
		{
			v3d_msg(QString("Make sure there are at least 1 image in V3D!"));
			return false;
		}
		Image4DSimple* image=callback.getImage(callback.currentImageWindow());
		p_img_input=image->getRawData();
        //sz_img_input=new V3DLONG[4]();
		sz_img_input[0]=image->getXDim();	sz_img_input[1]=image->getYDim();	sz_img_input[2]=image->getZDim();	sz_img_input[3]=image->getCDim();
		datatype_input=image->getDatatype();
	}
	printf("\t\timage size: [w=%ld, h=%ld, z=%ld, c=%ld]\n",sz_img_input[0],sz_img_input[1],sz_img_input[2],sz_img_input[3]);
	printf("\t\tdatatype: %d\n",datatype_input);

	//------------------------------------------------------------------------------------------------------------------------------------
	printf("2. Convert image datatype to uint8. \n");
	unsigned char * p_img_8u=0;
	{
	V3DLONG l_npixels=sz_img_input[0]*sz_img_input[1]*sz_img_input[2]*sz_img_input[3];
	p_img_8u=new unsigned char[l_npixels];
	if(!p_img_8u)
	{
		printf("ERROR: Fail to allocate memory. Do nothing. \n");
		if(p_img_input && !paras_str.b_imgfromV3D) 	{delete []p_img_input;		p_img_input=0;}
        //if(sz_img_input)						 	{delete []sz_img_input;		sz_img_input=0;}
		return false;
	}
	if(datatype_input==1)
	{
		printf("\t>>convert image data from uint8 to uint8. \n");
		for(V3DLONG i=0;i<l_npixels;i++)
			p_img_8u[i]=p_img_input[i];
	}
	else if(datatype_input==2)
	{
		printf("\t>>convert image data from uint16 to uint8. \n");
		double min,max;
		if(!rescale_to_0_255_and_copy((unsigned short int *)p_img_input,l_npixels,min,max,p_img_8u))
		{
			printf("ERROR: rescale_to_0_255_and_copy() return false.\n");
			if(p_img_8u) 								{delete []p_img_8u;			p_img_8u=0;}
			if(p_img_input && !paras_str.b_imgfromV3D) 	{delete []p_img_input;		p_img_input=0;}
            //if(sz_img_input)						 	{delete []sz_img_input;		sz_img_input=0;}
			return false;
		}
	}
	else if(datatype_input==4)
	{
		printf("\t>>convert image data from float to uint8. \n");
		double min,max;
		if(!rescale_to_0_255_and_copy((float *)p_img_input,l_npixels,min,max,p_img_8u))
		{
			printf("ERROR: rescale_to_0_255_and_copy() return false.\n");
			if(p_img_8u)								{delete []p_img_8u;			p_img_8u=0;}
			if(p_img_input && !paras_str.b_imgfromV3D) 	{delete []p_img_input;		p_img_input=0;}
            //if(sz_img_input)						 	{delete []sz_img_input;		sz_img_input=0;}
			return false;
		}
	}
	else
	{
		v3d_msg(QString("Unknown datatype!\n"));
		if(p_img_8u) 								{delete []p_img_8u;			p_img_8u=0;}
		if(p_img_input && !paras_str.b_imgfromV3D) 	{delete []p_img_input;		p_img_input=0;}
        //if(sz_img_input)						 	{delete []sz_img_input;		sz_img_input=0;}
		return false;
	}
	}

	//------------------------------------------------------------------------------------------------------------------------------------
    printf("3. Import markers. \n");
	//get initial head and tail marker position from V3D
	vector< vector<double> > vec2d_markers;
	if(!paras_str.b_markerfromV3D)
	{
        if(qs_filename_marker_input.isEmpty() || qs_filename_marker_input.toUpper()=="NULL")
		{
            v3d_msg(QString("Invalid marker path! Ignore it!"), 0);
            vec2d_markers.clear();
            /* //commented by PHC 2013-08-21
			if(p_img_8u) 								{delete []p_img_8u;			p_img_8u=0;}
			if(p_img_input && !paras_str.b_imgfromV3D) 	{delete []p_img_input;		p_img_input=0;}
			if(sz_img_input)						 	{delete []sz_img_input;		sz_img_input=0;}
			return false;
            */
		}
        else
        {
            QList<ImageMarker> ql_markers=readMarker_file(qs_filename_marker_input);
            printf("\t>>read %d markers from file: %s.\n",ql_markers.size(),qPrintable(qs_filename_marker_input));
            vector<double> vec_marker(3,0);
            for(V3DLONG i=0;i<ql_markers.size();i++)
            {
                vec_marker[0]=ql_markers[i].x;
                vec_marker[1]=ql_markers[i].y;
                vec_marker[2]=ql_markers[i].z;
                vec2d_markers.push_back(vec_marker);
            }
        }
	}
	else
	{
		printf("\t>>import markers from V3D. \n");
		v3dhandleList h_wndlist=callback.getImageWindowList();
		if(h_wndlist.size()<1)
		{
			v3d_msg(QString("Make sure there are at least 1 image in V3D!"));
			if(p_img_8u) 								{delete []p_img_8u;			p_img_8u=0;}
			if(p_img_input && !paras_str.b_imgfromV3D) 	{delete []p_img_input;		p_img_input=0;}
            //if(sz_img_input)						 	{delete []sz_img_input;		sz_img_input=0;}
			return false;
		}
		LandmarkList ml_makers=callback.getLandmark(callback.currentImageWindow());
		vector<double> vec_marker(3,0);
		for(V3DLONG i=0;i<ml_makers.size();i++)
		{
			vec_marker[0]=ml_makers[i].x;
			vec_marker[1]=ml_makers[i].y;
			vec_marker[2]=ml_makers[i].z;
			vec2d_markers.push_back(vec_marker);
		}
	}

	//------------------------------------------------------------------------------------------------------------------------------------
    printf("4. Read atlas apo file. \n");
	QList<CellAPO> ql_atlasapo;
	ql_atlasapo=readAPO_file(qs_filename_atals_input);
	printf("\t>>read %d points from [%s]\n",ql_atlasapo.size(),qPrintable(qs_filename_atals_input));
	if(ql_atlasapo.size()<=0)
	{
		v3d_msg(QString("Given atlas file is empty or invalid!"));
		if(p_img_8u) 								{delete []p_img_8u;			p_img_8u=0;}
		if(p_img_input && !paras_str.b_imgfromV3D) 	{delete []p_img_input;		p_img_input=0;}
        //if(sz_img_input) 							{delete []sz_img_input;		sz_img_input=0;}
		return false;
	}

	//------------------------------------------------------------------------------------------------------------------------------------
    printf("5. Read interesting cell file. \n");
	QList<QString> ql_celloi_name;
	if(!readCelloi_file(qs_filename_celloi_input,ql_celloi_name))
	{
		printf("ERROR: readCelloi_file() return false! \n");
		if(p_img_8u) 								{delete []p_img_8u;			p_img_8u=0;}
		if(p_img_input && !paras_str.b_imgfromV3D) 	{delete []p_img_input;		p_img_input=0;}
        //if(sz_img_input)						 	{delete []sz_img_input;		sz_img_input=0;}
		return false;
	}

	printf("\t>>interesting cell:\n");
	for(V3DLONG i=0;i<ql_celloi_name.size();i++)
		printf("\t\t%s\n",qPrintable(ql_celloi_name[i]));


	//------------------------------------------------------------------------------------------------------------------------------------
    printf("6. Do Straightening. \n");
	unsigned char *p_strimg=0;
	V3DLONG *sz_strimg=0;
	vector< vector< vector< vector<V3DLONG> > > > vec4d_mappingfield_str2ori;

	if(vec2d_markers.size()<2)
	{
		printf("\t>>marker num < 2, skip straightening.\n");
	}
	else
	{
		printf("\t>>marker num >= 2, do straightening.\n");

		V3DLONG l_width=paras_str.l_radius_cuttingplane*2+1;
		QList<ImageMarker> ql_marker;
		for(unsigned V3DLONG i=0;i<vec2d_markers.size();i++)
		{
			ImageMarker tmp;
			tmp.x=vec2d_markers[i][0];
			tmp.y=vec2d_markers[i][1];
			tmp.z=vec2d_markers[i][2];
			ql_marker.push_back(tmp);
		}

		if(!q_celegans_restacking_xy(
				p_img_8u,sz_img_input,
				ql_marker,l_width,
				p_strimg,sz_strimg,
				vec4d_mappingfield_str2ori))
		{
			printf("ERROR: q_celegans_restacking_xy() return false! \n");
			if(p_img_8u) 								{delete []p_img_8u;			p_img_8u=0;}
			if(p_img_input && !paras_str.b_imgfromV3D) 	{delete []p_img_input;		p_img_input=0;}
            //if(sz_img_input)						 	{delete []sz_img_input;		sz_img_input=0;}
			return false;
		}
	}

	//------------------------------------------------------------------------------------------------------------------------------------
    printf("7. Do Annotation. \n");
	QList<CellAPO> ql_musclecell_output;
	unsigned char *p_img8u_seglabel=0;
	COutputInfo outputinfo;

	{
	unsigned char *p_img_anno=0;
	V3DLONG *sz_img_anno=0;
	if(vec2d_markers.size()<2)	//on non-straightened image
	{
		p_img_anno=p_img_input;
		sz_img_anno=sz_img_input;
	}
	else						//on straightened image
	{
		p_img_anno=p_strimg;
		sz_img_anno=sz_strimg;
	}

	if(paras_anno.l_mode==-1)	//non-partial annotation
	{
		if(!q_atlas2image(paras_anno,callback,
				p_img_anno,sz_img_anno,ql_atlasapo,ql_celloi_name,
				ql_musclecell_output,p_img8u_seglabel,outputinfo))
		{
			printf("ERROR: q_atlas2image() return false!\n");
			if(p_strimg)								{delete []p_strimg; 		p_strimg=0;}
			if(sz_strimg) 								{delete []sz_strimg;		sz_strimg=0;}
			if(p_img_8u) 								{delete []p_img_8u;			p_img_8u=0;}
			if(p_img_input && !paras_str.b_imgfromV3D) 	{delete []p_img_input;		p_img_input=0;}
            //if(sz_img_input) 							{delete []sz_img_input;		sz_img_input=0;}
			return false;
		}
	}
	else if(paras_anno.l_mode==4) //align dapi
	{
		if(!q_align_dapicells(paras_anno,callback,
				p_img_anno,sz_img_anno,ql_atlasapo,ql_celloi_name,
				ql_musclecell_output,outputinfo))
		{
			printf("ERROR: q_atlas2image_partial() return false!\n");
			if(p_strimg)								{delete []p_strimg; 		p_strimg=0;}
			if(sz_strimg) 								{delete []sz_strimg;		sz_strimg=0;}
			if(p_img_8u) 								{delete []p_img_8u;			p_img_8u=0;}
			if(p_img_input && !paras_str.b_imgfromV3D) 	{delete []p_img_input;		p_img_input=0;}
            //if(sz_img_input) 							{delete []sz_img_input;		sz_img_input=0;}
			return false;
		}
	}
	else			//partial annotation
	{
		if(!q_atlas2image_partial(paras_anno,callback,
				p_img_anno,sz_img_anno,ql_atlasapo,ql_celloi_name,
				ql_musclecell_output,outputinfo))
		{
			printf("ERROR: q_atlas2image_partial() return false!\n");
			if(p_strimg)								{delete []p_strimg; 		p_strimg=0;}
			if(sz_strimg) 								{delete []sz_strimg;		sz_strimg=0;}
			if(p_img_8u) 								{delete []p_img_8u;			p_img_8u=0;}
			if(p_img_input && !paras_str.b_imgfromV3D) 	{delete []p_img_input;		p_img_input=0;}
            //if(sz_img_input) 							{delete []sz_img_input;		sz_img_input=0;}
			return false;
		}
	}
	}

	if(outputinfo.b_rotate90)
		v3d_msg("The deformed atlas maybe wrongly 90 degree rotated!\nCheck result!\n");


	//------------------------------------------------------------------------------------------------------------------------------------
	//warping the secondary interesting cells if provided based on the TPS paras obtained from the first group result
	QList<CellAPO> ql_cellio2_tps;
	if( b_use_celloi_2 || !qs_filename_celloi_2_input.isEmpty()) // b_use_celloi_2 = DLG_stranno.checkBox_celloi_2->isChecked()
	{
        printf("8-9. Warping the secondary interesting cells. \n");

		QList<QString> ql_celloi2_name;
		if(!readCelloi_file(qs_filename_celloi_2_input,ql_celloi2_name))
		{
			printf("ERROR: readCelloi_file() return false! \n");
			return false;
		}

		vector<point3D64F> vec_cellio1_ori,vec_cellio1_tps,vec_cellio2_ori;
		QList<CellAPO> ql_cellio2_ori;
		point3D64F tmp;
		//extract first interesting cells
		for(V3DLONG i=0;i<ql_atlasapo.size();i++)
		{
			QString qs_cellname=ql_atlasapo[i].name;
			qs_cellname=qs_cellname.simplified();
			qs_cellname=qs_cellname.toUpper();
			ql_atlasapo[i].name=qs_cellname;

			for(V3DLONG j=0;j<ql_celloi_name.size();j++)
			{
				if(ql_celloi_name[j].contains("*"))
				{
					QString qs_cellnamevalid=ql_celloi_name[j];
					qs_cellnamevalid.remove("*");
					if(qs_cellname.contains(qs_cellnamevalid,Qt::CaseInsensitive))
					{
						tmp.x=ql_atlasapo[i].x; tmp.y=ql_atlasapo[i].y; tmp.z=ql_atlasapo[i].z;
						vec_cellio1_ori.push_back(tmp);
					}
				}
				else if(qs_cellname.compare(ql_celloi_name[j],Qt::CaseInsensitive)==0)
				{
					tmp.x=ql_atlasapo[i].x; tmp.y=ql_atlasapo[i].y; tmp.z=ql_atlasapo[i].z;
					vec_cellio1_ori.push_back(tmp);
				}
			}
		}
		for(V3DLONG i=0;i<ql_musclecell_output.size();i++)
		{
			tmp.x=ql_musclecell_output[i].x;
			tmp.y=ql_musclecell_output[i].y;
			tmp.z=ql_musclecell_output[i].z;
			vec_cellio1_tps.push_back(tmp);
		}
		//extract secondary interesting cells
		for(V3DLONG i=0;i<ql_atlasapo.size();i++)
		{
			QString qs_cellname=ql_atlasapo[i].name;
			qs_cellname=qs_cellname.simplified();
			qs_cellname=qs_cellname.toUpper();
			ql_atlasapo[i].name=qs_cellname;

			for(V3DLONG j=0;j<ql_celloi2_name.size();j++)
			{
				if(ql_celloi2_name[j].contains("*"))
				{
					QString qs_cellnamevalid=ql_celloi2_name[j];
					qs_cellnamevalid.remove("*");
					if(qs_cellname.contains(qs_cellnamevalid,Qt::CaseInsensitive))
					{
						ql_cellio2_ori.push_back(ql_atlasapo[i]);
						tmp.x=ql_atlasapo[i].x; tmp.y=ql_atlasapo[i].y; tmp.z=ql_atlasapo[i].z;
						vec_cellio2_ori.push_back(tmp);
					}
				}
				else if(qs_cellname.compare(ql_celloi2_name[j],Qt::CaseInsensitive)==0)
				{
					ql_cellio2_ori.push_back(ql_atlasapo[i]);
					tmp.x=ql_atlasapo[i].x; tmp.y=ql_atlasapo[i].y; tmp.z=ql_atlasapo[i].z;
					vec_cellio2_ori.push_back(tmp);
				}
			}
		}
		ql_cellio2_tps=ql_cellio2_ori;
		printf("\t>>[%d] cells in the secondary intereting cell group.\n",ql_cellio2_ori.size());

		//compute TPS paras
		Matrix x4x4_affine,xnx4_c,xnxn_K;
		if(!q_TPS_cd(vec_cellio1_ori,vec_cellio1_tps,0,x4x4_affine,xnx4_c,xnxn_K))
		{
			printf("ERROR: q_TPS_cd() return false!\n");
			return false;
		}
		//compute TPS kernal matrix
		Matrix xmxn_K;
		if(!q_TPS_k(vec_cellio2_ori,vec_cellio1_ori,xmxn_K))
		{
			printf("ERROR: q_TPS_k() return false!\n");
			return false;
		}
		//warp the secondary cells
		Matrix x_ori(ql_cellio2_ori.size(),4),x_tps(ql_cellio2_ori.size(),4);
		for(V3DLONG i=0;i<ql_cellio2_ori.size();i++)
		{
			x_ori(i+1,1)=1.0;
			x_ori(i+1,2)=ql_cellio2_ori[i].x;
			x_ori(i+1,3)=ql_cellio2_ori[i].y;
			x_ori(i+1,4)=ql_cellio2_ori[i].z;
		}
		x_tps=x_ori*x4x4_affine+xmxn_K*xnx4_c;
		for(V3DLONG i=0;i<ql_cellio2_tps.size();i++)
		{
			ql_cellio2_tps[i].x=x_tps(i+1,2)/x_tps(1,1);
			ql_cellio2_tps[i].y=x_tps(i+1,3)/x_tps(1,1);
			ql_cellio2_tps[i].z=x_tps(i+1,4)/x_tps(1,1);
		}
	}

	//------------------------------------------------------------------------------------------------------------------------------------
    printf("10. Map the annotated cell back to non-straightened image. \n");
	QList<CellAPO> ql_musclecell_output_ori(ql_musclecell_output);

	//map back to non-straightened image
	if(vec2d_markers.size()>=2)
	{
		for(V3DLONG i=0;i<ql_musclecell_output.size();i++)
		{
			V3DLONG x=ql_musclecell_output[i].x;
			V3DLONG y=ql_musclecell_output[i].y;
			V3DLONG z=ql_musclecell_output[i].z;
			ql_musclecell_output_ori[i].x=vec4d_mappingfield_str2ori[y][x][z][0];
			ql_musclecell_output_ori[i].y=vec4d_mappingfield_str2ori[y][x][z][1];
			ql_musclecell_output_ori[i].z=vec4d_mappingfield_str2ori[y][x][z][2];
		}
	}

	if(b_use_celloi_2 || !qs_filename_celloi_2_input.isEmpty()) // b_use_celloi_2=DLG_stranno.checkBox_celloi_2->isChecked()
		ql_musclecell_output_ori.append(ql_cellio2_tps);

	//save deformed point cloud to apo file
	if(!qs_filename_atals_output.isEmpty())
		writeAPO_file(qPrintable(qs_filename_atals_output),ql_musclecell_output_ori);

	//show deformed atlas pts in V3D
//	if(!(paras_anno.b_showatlas || paras_anno.b_showsegmentation))
	{
		v3dhandle curwin=callback.currentImageWindow();
//		v3dhandle curwin=callback.getImageWindowList()[0];
		callback.open3DWindow(curwin);
		LandmarkList curlist;
		for(int i=0;i<ql_musclecell_output_ori.size();i++)
		{
			LocationSimple s;
			s.x=ql_musclecell_output_ori[i].x+1;//note: marker coord start from 1 instead of 0
			s.y=ql_musclecell_output_ori[i].y+1;//note: marker coord start from 1 instead of 0
			s.z=ql_musclecell_output_ori[i].z+1;//note: marker coord start from 1 instead of 0
			s.name=ql_musclecell_output_ori[i].name.toStdString();
			s.radius=10;

			curlist << s;
		}
		callback.setLandmark(curwin,curlist);
		callback.updateImageWindow(curwin);
		callback.pushObjectIn3DWindow(curwin);
	}

	//------------------------------------------------------------------------------------------------------------------------------------
    printf("11. Save segmentation label image to file. \n");
	if(!qs_filename_seglabel_output.isEmpty() && p_img8u_seglabel)
	{
		V3DLONG sz_seglabelimg[4]={sz_img_input[0],sz_img_input[1],sz_img_input[2],1};
        simple_saveimage_wrapper(callback, qPrintable(qs_filename_seglabel_output),p_img8u_seglabel,sz_seglabelimg,1);
	}

	//------------------------------------------------------------------------------------------------------------------------------------
	//free memory
	printf(">>Free memory\n");
	if(p_img8u_seglabel)						{delete []p_img8u_seglabel; p_img8u_seglabel=0;}
	if(p_strimg)								{delete []p_strimg; 		p_strimg=0;}
	if(sz_strimg) 								{delete []sz_strimg;		sz_strimg=0;}
	if(p_img_8u) 								{delete []p_img_8u;			p_img_8u=0;}
	if(p_img_input && !paras_str.b_imgfromV3D) 	{delete []p_img_input;		p_img_input=0;}
    //if(sz_img_input) 							{delete []sz_img_input;		sz_img_input=0;}

	//------------------------------------------------------------------------------------------------------------------------------------
	v3d_msg("Program exit successfully!\n", 0);
	return true;
}
int v3dneuron_tracing(V3DPluginCallback2 &callback, QWidget *parent)
{
	v3dhandleList win_list = callback.getImageWindowList();

	if(win_list.size()<1)
	{
		QMessageBox::information(0, title, QObject::tr("No image is open."));
		return -1;
	}
	v3dhandle curwin = callback.currentImageWindow();
	LandmarkList landmarks = callback.getLandmark(curwin);
	if(landmarks.empty())
	{
		v3d_msg("Please set a landmark!");
		return 0;
	}
	QList <ImageMarker> imagemarks;
	for(int i = 0; i < landmarks.size(); i++)
	{
		ImageMarker m;
		LocationSimple l = landmarks.at(i);
		m.x = l.x;
		m.y = l.y;
		m.z = l.z;
		imagemarks.push_back(m);
	}
	system("rm -f /tmp/mymarks.marker");
	system("rm -f /tmp/tmp_out*");
	writeMarker_file("/tmp/mymarks.marker",imagemarks);
	QString img_file = callback.getImageName(curwin);
	bool ok;
	QString nt_path = QInputDialog::getText(0, QObject::tr("Set path"), QObject::tr("v3dneuron_tracing path : "), QLineEdit::Normal, "~/Local/bin/v3dneuron_tracing", &ok);
	//QString paras = QObject::tr("v3dneuron_tracing -s %1 -S /tmp/mymarks.marker -o /tmp/tmp_out").arg(img_file);
	QString paras = QObject::tr("%1 -s \"%2\" -S /tmp/mymarks.marker -o /tmp/tmp_out").arg(nt_path).arg(img_file);
	qDebug(paras.toStdString().c_str());
	//QMessageBox::information(0,"",paras);
	system(paras.toStdString().c_str());
	NeuronTree nt = readSWC_file("/tmp/tmp_out_0.swc");
	//nt.editable = false;
	callback.setSWC(curwin, nt);
	callback.updateImageWindow(curwin);
	callback.open3DWindow(curwin);
	//callback.getView3DControl(curwin)->setShowSurfObjects(2);
	//TestDialog dialog(callback, parent);

	//if (dialog.exec()!=QDialog::Accepted) return -1;

	//dialog.update();
	//int i = dialog.i;
	//int c = dialog.channel;
	//Image4DSimple *p4DImage = callback.getImage(win_list[i]);
	//if(p4DImage->getCDim() <= c) {v3d_msg(QObject::tr("The channel isn't existed.")); return -1;}
	//V3DLONG sz[3];
	//sz[0] = p4DImage->getXDim();
	//sz[1] = p4DImage->getYDim();
	//sz[2] = p4DImage->getZDim();

	//unsigned char * inimg1d = p4DImage->getRawDataAtChannel(c);

	//v3dhandle newwin;
	//if(QMessageBox::Yes == QMessageBox::question(0, "", QString("Do you want to use the existing windows?"), QMessageBox::Yes, QMessageBox::No))
		//newwin = callback.currentImageWindow();
	//else
		//newwin = callback.newImageWindow();

	//p4DImage->setData(inimg1d, sz[0], sz[1], sz[2], sz[3]);
	//callback.setImage(newwin, p4DImage);
	//callback.setImageName(newwin, QObject::tr("v3dneuron_tracing"));
	//callback.updateImageWindow(newwin);
	return 1;
}