void setSeeds(V3DPluginCallback2 &v3d, QWidget *parent )
{
    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);
}
void MovieFrom3Dviewer(V3DPluginCallback2 & v3d, QWidget * parent)
{
	v3dhandle curwin = v3d.currentImageWindow();
	if (!curwin)
	{
		v3d_msg("You don't have any image open in the main window.");
		return;
	}
	v3d.open3DWindow(curwin);

	if (controlPanel::m_pLookPanel)
	{
		controlPanel::m_pLookPanel->show();
		return;
	}

	controlPanel* p = new controlPanel(v3d, parent);
	if (p)	p->show();
}
void SnapShoot3Dviewer(V3DPluginCallback2 & v3d, QWidget * parent)
{
	v3dhandle curwin = v3d.currentImageWindow();
	if (!curwin)
	{
		v3d_msg("You don't have any image opened in the main window.");
		return;
	}
	v3d.open3DWindow(curwin);

	QFileDialog d(parent);
	d.setWindowTitle(QObject::tr("Choose output snapshot filename"));
	d.setAcceptMode(QFileDialog::AcceptSave);
	if (!d.exec()) return;

	QString BMPfilename = (d.selectedFiles())[0];
	if (BMPfilename.endsWith(".BMP", Qt::CaseInsensitive))
	   BMPfilename.resize(BMPfilename.length()-4); //by PHC
	v3d.screenShot3DWindow(curwin, BMPfilename);
	QMessageBox::information(0, title, QString("Snapshot was saved to: %1.BMP\n").arg(BMPfilename));
}
bool anisodiff_func(V3DPluginCallback2 &callback, QWidget *parent, input_PARA &PARA, bool bmenu)
{
	unsigned char* p_img_input = 0;
	V3DLONG sz_img_input[4];
	if(bmenu)
	{
		v3dhandle curwin = callback.currentImageWindow();
		if (!curwin)
		{
			QMessageBox::information(0, "", "You don't have any image open in the main window.");
			return false;
		}
		Image4DSimple* p4DImage = callback.getImage(curwin);
		if (!p4DImage)
		{
			QMessageBox::information(0, "", "The image pointer is invalid. Ensure your data is valid and try again!");
			return false;
		}
		if(p4DImage->getDatatype()!=V3D_UINT8)
		{
			QMessageBox::information(0, "", "Please convert the image to be UINT8 and try again!");
			return false;
		}
		if(p4DImage->getCDim()!=1)
		{
			QMessageBox::information(0, "", "The input image is not one channel image!");
			return false;
		}
		p_img_input = p4DImage->getRawData();
		sz_img_input[0] = p4DImage->getXDim();
		sz_img_input[1] = p4DImage->getYDim();
		sz_img_input[2] = p4DImage->getZDim();
		sz_img_input[3] = 1;
	}
	else
	{
		int datatype = 0;
		if (!simple_loadimage_wrapper(callback,PARA.inimg_file.toStdString().c_str(), p_img_input, sz_img_input, datatype))
		{
			fprintf (stderr, "Error happens in reading the subject file [%s]. Exit. \n",PARA.inimg_file.toStdString().c_str());
			return false;
		}
		if(PARA.channel < 1 || PARA.channel > sz_img_input[3])
		{
			fprintf (stderr, "Invalid channel number. \n");
			return false;
		}

		if(datatype !=1)
		{
			fprintf (stderr, "Please convert the image to be UINT8 and try again!\n");
			return false;
		}
	}

	//-----------------------------------------------------------------------------------------
	printf("1. Find the bounding box and crop image. \n");
	long l_boundbox_min[3],l_boundbox_max[3];//xyz
	V3DLONG sz_img_crop[4];
	long l_npixels_crop;
	unsigned char *p_img8u_crop=0;
	{
	//find bounding box
	unsigned char ***p_img8u_3d=0;
	if(!new3dpointer(p_img8u_3d,sz_img_input[0],sz_img_input[1],sz_img_input[2],p_img_input))
	{
		printf("ERROR: Fail to allocate memory for the 4d pointer of image.\n");
		if(p_img8u_3d) 				{delete3dpointer(p_img8u_3d,sz_img_input[0],sz_img_input[1],sz_img_input[2]);}
		return false;
	}

	l_boundbox_min[0]=sz_img_input[0];	l_boundbox_min[1]=sz_img_input[1];	l_boundbox_min[2]=sz_img_input[2];
	l_boundbox_max[0]=0;				l_boundbox_max[1]=0;				l_boundbox_max[2]=0;
	for(long X=0;X<sz_img_input[0];X++)
		for(long Y=0;Y<sz_img_input[1];Y++)
			for(long Z=0;Z<sz_img_input[2];Z++)
				if(p_img8u_3d[Z][Y][X]>0.1)
				{
					if(l_boundbox_min[0]>X) l_boundbox_min[0]=X;	if(l_boundbox_max[0]<X) l_boundbox_max[0]=X;
					if(l_boundbox_min[1]>Y) l_boundbox_min[1]=Y;	if(l_boundbox_max[1]<Y) l_boundbox_max[1]=Y;
					if(l_boundbox_min[2]>Z) l_boundbox_min[2]=Z;	if(l_boundbox_max[2]<Z) l_boundbox_max[2]=Z;
				}
	printf(">>boundingbox: x[%ld~%ld],y[%ld~%ld],z[%ld~%ld]\n",l_boundbox_min[0],l_boundbox_max[0],
															   l_boundbox_min[1],l_boundbox_max[1],
															   l_boundbox_min[2],l_boundbox_max[2]);

	//crop image
	sz_img_crop[0]=l_boundbox_max[0]-l_boundbox_min[0]+1;
	sz_img_crop[1]=l_boundbox_max[1]-l_boundbox_min[1]+1;
	sz_img_crop[2]=l_boundbox_max[2]-l_boundbox_min[2]+1;
	sz_img_crop[3]=1;
	l_npixels_crop=sz_img_crop[0]*sz_img_crop[1]*sz_img_crop[2];

	p_img8u_crop=new(std::nothrow) unsigned char[l_npixels_crop]();
	if(!p_img8u_crop)
	{
		printf("ERROR: Fail to allocate memory for p_img32f_crop!\n");
		if(p_img8u_3d) 				{delete3dpointer(p_img8u_3d,sz_img_input[0],sz_img_input[1],sz_img_input[2]);}
		return false;
	}
	unsigned char *p_tmp=p_img8u_crop;
	for(long Z=0;Z<sz_img_crop[2];Z++)
		for(long Y=0;Y<sz_img_crop[1];Y++)
			for(long X=0;X<sz_img_crop[0];X++)
			{
				*p_tmp = p_img8u_3d[Z+l_boundbox_min[2]][Y+l_boundbox_min[1]][X+l_boundbox_min[0]];
				p_tmp++;
			}
	if(p_img8u_3d) 			{delete3dpointer(p_img8u_3d,sz_img_input[0],sz_img_input[1],sz_img_input[2]);}
	}
	//saveImage("d:/SVN/Vaa3D_source_code/v3d_external/released_plugins/v3d_plugins/anisodiffusion_littlequick/crop.raw",p_img8u_crop,sz_img_crop,1);

	//-----------------------------------------------------------------------------------------
	//convert image data type to float
	printf("2. Convert image data to float and scale to [0~255]. \n");
	float *p_img32f_crop=0;
	{
	p_img32f_crop=new(std::nothrow) float[l_npixels_crop]();
	if(!p_img32f_crop)
	{
		printf("ERROR: Fail to allocate memory for p_img32f_crop!\n");
		if(p_img8u_crop) 			{delete []p_img8u_crop;		p_img8u_crop=0;}
		if(p_img32f_crop) 			{delete []p_img32f_crop;			p_img32f_crop=0;}
		return false;
	}
	//find the maximal intensity value
	float d_maxintensity_input=0.0;
	for(long i=0;i<l_npixels_crop;i++)
		if(p_img8u_crop[i]>d_maxintensity_input)
			d_maxintensity_input=p_img8u_crop[i];
	//convert and rescale
	for(long i=0;i<l_npixels_crop;i++)
		p_img32f_crop[i]=p_img8u_crop[i]/d_maxintensity_input*255.0;
	printf(">>d_maxintensity=%.2f\n",d_maxintensity_input);
	//free input image to save memory
	//if(p_img_input) 			{delete []p_img_input;		p_img_input=0;}
	if(p_img8u_crop) 			{delete []p_img8u_crop;		p_img8u_crop=0;}
	}

	//-----------------------------------------------------------------------------------------
	//do anisotropic diffusion
	printf("3. Do anisotropic diffusion... \n");
	float *p_img32f_crop_output=0;
	if(!q_AnisoDiff3D(p_img32f_crop,sz_img_crop,p_img32f_crop_output))
	{
		printf("ERROR: q_AnisoDiff3D() return false!\n");
		if(p_img8u_crop) 			{delete []p_img8u_crop;		p_img8u_crop=0;}
		if(p_img32f_crop) 				{delete []p_img32f_crop;		p_img32f_crop=0;}
		if(p_img32f_crop_output) 		{delete []p_img32f_crop_output;	p_img32f_crop_output=0;}
		return false;
	}
	if(p_img32f_crop) 				{delete []p_img32f_crop;		p_img32f_crop=0;}

	//-----------------------------------------------------------------------------------------
	printf("4. Reconstruct processed crop image back to original size. \n");
	unsigned char *p_img8u_output=0;
	long l_npixels=sz_img_input[0]*sz_img_input[1]*sz_img_input[2]*sz_img_input[3];
	{
	p_img8u_output=new(std::nothrow) unsigned char[l_npixels]();
	if(!p_img8u_output)
	{
		printf("ERROR: Fail to allocate memory for p_img8u_output!\n");
		if(p_img32f_crop_output) 		{delete []p_img32f_crop_output;	p_img32f_crop_output=0;}
		return false;
	}
	//copy original image data to output image
	for(long i=0;i<l_npixels;i++)
		p_img8u_output[i]=p_img_input[i];

	unsigned char ***p_img8u_3d=0;
	if(!new3dpointer(p_img8u_3d,sz_img_input[0],sz_img_input[1],sz_img_input[2],p_img8u_output))
	{
		printf("ERROR: Fail to allocate memory for the 4d pointer of image.\n");
		if(p_img8u_output) 				{delete []p_img8u_output;	p_img8u_output=0;}
		if(p_img32f_crop_output) 		{delete []p_img32f_crop_output;	p_img32f_crop_output=0;}
		return false;
	}

	float *p_tmp=p_img32f_crop_output;
	for(long Z=0;Z<sz_img_crop[2];Z++)
		for(long Y=0;Y<sz_img_crop[1];Y++)
			for(long X=0;X<sz_img_crop[0];X++)
			{
				p_img8u_3d[Z+l_boundbox_min[2]][Y+l_boundbox_min[1]][X+l_boundbox_min[0]]=(unsigned char)(*p_tmp);
				p_tmp++;
			}

	if(p_img8u_3d) 	{delete3dpointer(p_img8u_3d,sz_img_input[0],sz_img_input[1],sz_img_input[2]);}
	if(p_img32f_crop_output) 		{delete []p_img32f_crop_output;	p_img32f_crop_output=0;}
	}

	//-----------------------------------------------------------------------------------------
	//save or display
	if(bmenu)
	{
		printf("5. Display the processed image in Vaa3D. \n");
		//push result image back to v3d
		v3dhandle newwin=callback.newImageWindow("output");
		Image4DSimple img4D_output;
		img4D_output.setData(p_img8u_output,sz_img_input[0],sz_img_input[1],sz_img_input[2],1,V3D_UINT8);
		callback.setImage(newwin,&img4D_output);
		callback.updateImageWindow(newwin);
		callback.open3DWindow(newwin);
	}
	else
	{
		printf("5. Save the processed image to file. \n");
		QString str_outimg_filename = PARA.inimg_file + "_anisodiff.raw";
		saveImage(qPrintable(str_outimg_filename),p_img8u_output,sz_img_input,1);

		if(p_img8u_output) 		{delete []p_img8u_output;		p_img8u_output=0;}
	}

	printf(">>Program complete success!\n");
	return true;
}
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;
}