function [xtable, ytable, utable, vtable, typevector,correlation_map] = piv_FFTensemble (autolimit,filepath,video_frame_selection,bg_img_A,bg_img_B,clahe,highp,intenscap,clahesize,highpsize,wienerwurst,wienerwurstsize,roi_inpt,maskiererx,maskierery,interrogationarea,step,subpixfinder,passes,int2,int3,int4,mask_auto,imdeform,repeat,do_pad)
%this funtion performs the  PIV analysis. It is a modification of the
%pivFFTmulti, and will do ensemble correlation. That is a suitable
%algorithm for low seeding density as it happens in microPIV.
warning off %#ok<*WNOFF> %MATLAB:log:logOfZero
%% pre-processing is done in this function
result_conv_ensemble = zeros(interrogationarea,interrogationarea); % prepare empty result_conv
if isempty(video_frame_selection) %list with image files was passed
	amount_input_imgs=size(filepath,1);
else
	amount_input_imgs=numel(video_frame_selection);
end
total_analyses_amount=amount_input_imgs / 2 * passes;
from_total = 0;
tic
skippy=0;
for ensemble_i1=1:2:amount_input_imgs
	if isempty(video_frame_selection) %list with image files was passed
		%detect if it is b16 or standard pixel image
		[~,~,ext] = fileparts(filepath{1});
		if strcmp(ext,'.b16')
			image1=f_readB16(filepath{ensemble_i1});
			image2=f_readB16(filepath{ensemble_i1+1});
		else
			image1=imread(filepath{ensemble_i1});
			image2=imread(filepath{ensemble_i1+1});
		end
	else % video file was passed
		image1 = read(filepath,video_frame_selection(ensemble_i1));
		image2 = read(filepath,video_frame_selection(ensemble_i1+1));
	end
	if size(image1,3)>1
		image1=uint8(mean(image1,3));
		image2=uint8(mean(image2,3));
		%disp('Warning: To optimize speed, your images should be grayscale, 8 bit!')
	end
	%Subtract background (if existent)
	if ~isempty(bg_img_A)
		image1=image1-bg_img_A;
	end
	if ~isempty(bg_img_B)
		image2=image2-bg_img_B;
	end
	%if autolimit == 1 %if autolimit is desired: do autolimit for each image seperately
		if size(image1,3)>1
			stretcher = stretchlim(rgb2gray(image1));
		else
			stretcher = stretchlim(image1);
		end
		minintens1 = stretcher(1);
		maxintens1 = stretcher(2);
		if size(image2,3)>1
			stretcher = stretchlim(rgb2gray(image2));
		else
			stretcher = stretchlim(image2);
		end
		minintens2 = stretcher(1);
		maxintens2 = stretcher(2);
	%end
	image1 = PIVlab_preproc (image1,roi_inpt,clahe, clahesize,highp,highpsize,intenscap,wienerwurst,wienerwurstsize,minintens1,maxintens1);
	image2 = PIVlab_preproc (image2,roi_inpt,clahe, clahesize,highp,highpsize,intenscap,wienerwurst,wienerwurstsize,minintens2,maxintens2);
	if numel(roi_inpt)>0
		xroi=roi_inpt(1);
		yroi=roi_inpt(2);
		widthroi=roi_inpt(3);
		heightroi=roi_inpt(4);
		image1_roi=double(image1(yroi:yroi+heightroi,xroi:xroi+widthroi));
		image2_roi=double(image2(yroi:yroi+heightroi,xroi:xroi+widthroi));
	else
		xroi=0;
		yroi=0;
		image1_roi=double(image1);
		image2_roi=double(image2);
	end
	gen_image1_roi = image1_roi;
	gen_image2_roi = image2_roi;
	%prepare a matrix for calculating the average mask of all images
	if ensemble_i1==1
		average_mask=zeros(size(image1_roi));
	end
	%get mask from mask list
	ximask={};
	yimask={};
	if size(maskiererx,2)>=ensemble_i1
		for j=1:size(maskiererx,1)
			if isempty(maskiererx{j,ensemble_i1})==0
				ximask{j,1}=maskiererx{j,ensemble_i1}; %#ok<*AGROW>
				yimask{j,1}=maskierery{j,ensemble_i1};
			else
				break
			end
		end
		if size(ximask,1)>0
			mask_inpt=[ximask yimask];
		else
			mask_inpt=[];
		end
	else
		mask_inpt=[];
	end
	if numel(mask_inpt)>0
		cellmask=mask_inpt;
		mask=zeros(size(image1_roi));
		for i=1:size(cellmask,1)
			masklayerx=cellmask{i,1};
			masklayery=cellmask{i,2};
			mask = mask + poly2mask(masklayerx-xroi,masklayery-yroi,size(image1_roi,1),size(image1_roi,2)); %kleineres eingangsbild und maske geshiftet
		end
	else
		mask=zeros(size(image1_roi));
	end
	mask(mask>1)=1;
	gen_mask = mask;
	try
		average_mask=average_mask + mask; %will fail if images are not same dimensions.
	catch
		cancel = 1;
		hgui=getappdata(0,'hgui');
		setappdata(hgui, 'cancel', cancel);
		text(gca(getappdata(0,'hgui')),10,10,'Error: Image dimensions inconsistent!','color',[1 0 0],'fontsize',20)
		drawnow;
		break
	end
	miniy=1+(ceil(interrogationarea/2));
	minix=1+(ceil(interrogationarea/2));
	maxiy=step*(floor(size(image1_roi,1)/step))-(interrogationarea-1)+(ceil(interrogationarea/2)); %statt size deltax von ROI nehmen
	maxix=step*(floor(size(image1_roi,2)/step))-(interrogationarea-1)+(ceil(interrogationarea/2));

	numelementsy=floor((maxiy-miniy)/step+1);
	numelementsx=floor((maxix-minix)/step+1);

	LAy=miniy;
	LAx=minix;
	LUy=size(image1_roi,1)-maxiy;
	LUx=size(image1_roi,2)-maxix;
	shift4centery=round((LUy-LAy)/2);
	shift4centerx=round((LUx-LAx)/2);
	if shift4centery<0 %shift4center will be negative if in the unshifted case the left border is bigger than the right border. the vectormatrix is hence not centered on the image. the matrix cannot be shifted more towards the left border because then image2_crop would have a negative index. The only way to center the matrix would be to remove a column of vectors on the right side. but then we weould have less data....
		shift4centery=0;
	end
	if shift4centerx<0 %shift4center will be negative if in the unshifted case the left border is bigger than the right border. the vectormatrix is hence not centered on the image. the matrix cannot be shifted more towards the left border because then image2_crop would have a negative index. The only way to center the matrix would be to remove a column of vectors on the right side. but then we weould have less data....
		shift4centerx=0;
	end
	miniy=miniy+shift4centery;
	minix=minix+shift4centerx;
	maxix=maxix+shift4centerx;
	maxiy=maxiy+shift4centery;

	image1_roi=padarray(image1_roi,[ceil(interrogationarea/2) ceil(interrogationarea/2)], min(min(image1_roi)));
	image2_roi=padarray(image2_roi,[ceil(interrogationarea/2) ceil(interrogationarea/2)], min(min(image1_roi)));
	mask=padarray(mask,[ceil(interrogationarea/2) ceil(interrogationarea/2)],0);

	if (rem(interrogationarea,2) == 0) %for the subpixel displacement measurement
		SubPixOffset=1;
	else
		SubPixOffset=0.5;
	end
	xtable=zeros(numelementsy,numelementsx);
	ytable=xtable; %#ok<*NASGU>
	utable=xtable;
	vtable=xtable;
	typevector=ones(numelementsy,numelementsx);

	%% MAINLOOP
	try %check if used from GUI
		handles=guihandles(getappdata(0,'hgui'));
		GUI_avail=1;
		hgui=getappdata(0,'hgui');
		cancel=getappdata(hgui, 'cancel');
		if cancel == 1
			break
			%disp('user cancelled');
		end

	catch %#ok<CTCH>
		GUI_avail=0;
		disp('no GUI')
	end
	% divide images by small pictures
	% new index for image1_roi and image2_roi
	s0 = (repmat((miniy:step:maxiy)'-1, 1,numelementsx) + repmat(((minix:step:maxix)-1)*size(image1_roi, 1), numelementsy,1))';
	s0 = permute(s0(:), [2 3 1]);
	s1 = repmat((1:interrogationarea)',1,interrogationarea) + repmat(((1:interrogationarea)-1)*size(image1_roi, 1),interrogationarea,1);
	ss1 = repmat(s1, [1, 1, size(s0,3)])+repmat(s0, [interrogationarea, interrogationarea, 1]);

	image1_cut = image1_roi(ss1);
	image2_cut = image2_roi(ss1);

	if do_pad==1 && passes == 1 %only on first pass
		%subtract mean to avoid high frequencies at border of correlation:
		image1_cut=image1_cut-mean(image1_cut,[1 2]);
		image2_cut=image2_cut-mean(image2_cut,[1 2]);
		% padding (faster than padarray) to get the linear correlation:
		image1_cut=[image1_cut zeros(interrogationarea,interrogationarea-1,size(image1_cut,3)); zeros(interrogationarea-1,2*interrogationarea-1,size(image1_cut,3))];
		image2_cut=[image2_cut zeros(interrogationarea,interrogationarea-1,size(image2_cut,3)); zeros(interrogationarea-1,2*interrogationarea-1,size(image2_cut,3))];
	end
	%do fft2:

	result_conv = fftshift(fftshift(real(ifft2(conj(fft2(image1_cut)).*fft2(image2_cut))), 1), 2);
	if do_pad==1 && passes == 1
		%cropping of correlation matrix:
		result_conv =result_conv((interrogationarea/2):(3*interrogationarea/2)-1,(interrogationarea/2):(3*interrogationarea/2)-1,:);
	end

	%% repeated  Correlation in the first pass (might make sense to repeat more often to make it even more robust...)
	if repeat == 1 && passes == 1
		ms=round(step/4); %multishift parameter so groß wie viertel int window
		%Shift left bot
		s0B = (repmat((miniy+ms:step:maxiy+ms)'-1, 1,numelementsx) + repmat(((minix-ms:step:maxix-ms)-1)*size(image1_roi, 1), numelementsy,1))';
		s0B = permute(s0B(:), [2 3 1]);
		s1B = repmat((1:interrogationarea)',1,interrogationarea) + repmat(((1:interrogationarea)-1)*size(image1_roi, 1),interrogationarea,1);
		ss1B = repmat(s1B, [1, 1, size(s0B,3)])+repmat(s0B, [interrogationarea, interrogationarea, 1]);
		image1_cutB = image1_roi(ss1B);
		image2_cutB = image2_roi(ss1B);
		if do_pad==1 && passes == 1
			%subtract mean to avoid high frequencies at border of correlation:
			image1_cutB=image1_cutB-mean(image1_cutB,[1 2]);
			image2_cutB=image2_cutB-mean(image2_cutB,[1 2]);
			% padding (faster than padarray) to get the linear correlation:
			image1_cutB=[image1_cutB zeros(interrogationarea,interrogationarea-1,size(image1_cutB,3)); zeros(interrogationarea-1,2*interrogationarea-1,size(image1_cutB,3))];
			image2_cutB=[image2_cutB zeros(interrogationarea,interrogationarea-1,size(image2_cutB,3)); zeros(interrogationarea-1,2*interrogationarea-1,size(image2_cutB,3))];
		end
		result_convB = fftshift(fftshift(real(ifft2(conj(fft2(image1_cutB)).*fft2(image2_cutB))), 1), 2);
		if do_pad==1 && passes == 1
			%cropping of correlation matrix:
			result_convB =result_convB((interrogationarea/2):(3*interrogationarea/2)-1,(interrogationarea/2):(3*interrogationarea/2)-1,:);
		end

		%Shift right bot
		s0C = (repmat((miniy+ms:step:maxiy+ms)'-1, 1,numelementsx) + repmat(((minix+ms:step:maxix+ms)-1)*size(image1_roi, 1), numelementsy,1))';
		s0C = permute(s0C(:), [2 3 1]);
		s1C = repmat((1:interrogationarea)',1,interrogationarea) + repmat(((1:interrogationarea)-1)*size(image1_roi, 1),interrogationarea,1);
		ss1C = repmat(s1C, [1, 1, size(s0C,3)])+repmat(s0C, [interrogationarea, interrogationarea, 1]);
		image1_cutC = image1_roi(ss1C);
		image2_cutC = image2_roi(ss1C);
		if do_pad==1 && passes == 1
			%subtract mean to avoid high frequencies at border of correlation:
			image1_cutC=image1_cutC-mean(image1_cutC,[1 2]);
			image2_cutC=image2_cutC-mean(image2_cutC,[1 2]);
			% padding (faster than padarray) to get the linear correlation:
			image1_cutC=[image1_cutC zeros(interrogationarea,interrogationarea-1,size(image1_cutC,3)); zeros(interrogationarea-1,2*interrogationarea-1,size(image1_cutC,3))];
			image2_cutC=[image2_cutC zeros(interrogationarea,interrogationarea-1,size(image2_cutC,3)); zeros(interrogationarea-1,2*interrogationarea-1,size(image2_cutC,3))];
		end
		result_convC = fftshift(fftshift(real(ifft2(conj(fft2(image1_cutC)).*fft2(image2_cutC))), 1), 2);
		if do_pad==1 && passes == 1
			%cropping of correlation matrix:
			result_convC =result_convC((interrogationarea/2):(3*interrogationarea/2)-1,(interrogationarea/2):(3*interrogationarea/2)-1,:);
		end

		%Shift left top
		s0D = (repmat((miniy-ms:step:maxiy-ms)'-1, 1,numelementsx) + repmat(((minix-ms:step:maxix-ms)-1)*size(image1_roi, 1), numelementsy,1))';
		s0D = permute(s0D(:), [2 3 1]);
		s1D = repmat((1:interrogationarea)',1,interrogationarea) + repmat(((1:interrogationarea)-1)*size(image1_roi, 1),interrogationarea,1);
		ss1D = repmat(s1D, [1, 1, size(s0D,3)])+repmat(s0D, [interrogationarea, interrogationarea, 1]);
		image1_cutD = image1_roi(ss1D);
		image2_cutD = image2_roi(ss1D);

		if do_pad==1 && passes == 1
			%subtract mean to avoid high frequencies at border of correlation:
			image1_cutD=image1_cutD-mean(image1_cutD,[1 2]);
			image2_cutD=image2_cutD-mean(image2_cutD,[1 2]);
			% padding (faster than padarray) to get the linear correlation:
			image1_cutD=[image1_cutD zeros(interrogationarea,interrogationarea-1,size(image1_cutD,3)); zeros(interrogationarea-1,2*interrogationarea-1,size(image1_cutD,3))];
			image2_cutD=[image2_cutD zeros(interrogationarea,interrogationarea-1,size(image2_cutD,3)); zeros(interrogationarea-1,2*interrogationarea-1,size(image2_cutD,3))];
		end
		result_convD = fftshift(fftshift(real(ifft2(conj(fft2(image1_cutD)).*fft2(image2_cutD))), 1), 2);
		if do_pad==1 && passes == 1
			%cropping of correlation matrix:
			result_convD =result_convD((interrogationarea/2):(3*interrogationarea/2)-1,(interrogationarea/2):(3*interrogationarea/2)-1,:);
		end

		%Shift right top
		s0E = (repmat((miniy-ms:step:maxiy-ms)'-1, 1,numelementsx) + repmat(((minix+ms:step:maxix+ms)-1)*size(image1_roi, 1), numelementsy,1))';
		s0E = permute(s0E(:), [2 3 1]);
		s1E = repmat((1:interrogationarea)',1,interrogationarea) + repmat(((1:interrogationarea)-1)*size(image1_roi, 1),interrogationarea,1);
		ss1E = repmat(s1E, [1, 1, size(s0E,3)])+repmat(s0E, [interrogationarea, interrogationarea, 1]);
		image1_cutE = image1_roi(ss1E);
		image2_cutE = image2_roi(ss1E);
		if do_pad==1 && passes == 1
			%subtract mean to avoid high frequencies at border of correlation:
			image1_cutE=image1_cutE-mean(image1_cutE,[1 2]);
			image2_cutE=image2_cutE-mean(image2_cutE,[1 2]);
			% padding (faster than padarray) to get the linear correlation:
			image1_cutE=[image1_cutE zeros(interrogationarea,interrogationarea-1,size(image1_cutE,3)); zeros(interrogationarea-1,2*interrogationarea-1,size(image1_cutE,3))];
			image2_cutE=[image2_cutE zeros(interrogationarea,interrogationarea-1,size(image2_cutE,3)); zeros(interrogationarea-1,2*interrogationarea-1,size(image2_cutE,3))];
		end
		result_convE = fftshift(fftshift(real(ifft2(conj(fft2(image1_cutE)).*fft2(image2_cutE))), 1), 2);
		if do_pad==1 && passes == 1
			%cropping of correlation matrix:
			result_convE =result_convE((interrogationarea/2):(3*interrogationarea/2)-1,(interrogationarea/2):(3*interrogationarea/2)-1,:);
		end
		result_conv=result_conv.*result_convB.*result_convC.*result_convD.*result_convE;
	end

	if mask_auto == 1
		%das zentrum der Matrize (3x3) mit dem mittelwert ersetzen = Keine Autokorrelation
		%MARKER
		h = fspecial('gaussian', 3, 1.5);
		h=h/h(2,2);
		h=1-h;
		%h=repmat(h,1,1,size(result_conv,3));
		h=repmat(h,[1,1,size(result_conv,3)]);
		h=h.*result_conv((interrogationarea/2)+SubPixOffset-1:(interrogationarea/2)+SubPixOffset+1,(interrogationarea/2)+SubPixOffset-1:(interrogationarea/2)+SubPixOffset+1,:);
		result_conv((interrogationarea/2)+SubPixOffset-1:(interrogationarea/2)+SubPixOffset+1,(interrogationarea/2)+SubPixOffset-1:(interrogationarea/2)+SubPixOffset+1,:)=h;
	end
	%apply mask
	ii = find(mask(ss1(round(interrogationarea/2+1), round(interrogationarea/2+1), :)));
	result_conv(:,:, ii) = 0;
	%average the correlation matrices
	try
		result_conv_ensemble=result_conv_ensemble+result_conv;
	catch % older matlab releases
		result_conv_ensemble = zeros(size(result_conv));
		result_conv_ensemble=result_conv_ensemble+result_conv;
	end

	if GUI_avail==1
		progri=ensemble_i1/(amount_input_imgs)*100;
		from_total=from_total+1;
		set(handles.progress, 'string' , ['Pass ' int2str(1) ' progress: ' int2str(progri) '%' ])
		set(handles.overall, 'string' , ['Total progress: ' int2str(from_total / total_analyses_amount * 100) '%'])
		zeit=toc;
		done=from_total;
		tocome=total_analyses_amount-done;
		zeit=zeit/done*tocome;
		hrs=zeit/60^2;
		mins=(hrs-floor(hrs))*60;
		secs=(mins-floor(mins))*60;
		hrs=floor(hrs);
		mins=floor(mins);
		secs=floor(secs);
		set(handles.totaltime,'string', ['Time left: ' sprintf('%2.2d', hrs) 'h ' sprintf('%2.2d', mins) 'm ' sprintf('%2.2d', secs) 's']);

		%xxx update display every 10 frames...?
		%aber wie, dann müsste man peakfinder machen
		if skippy ==0
			[xtable,ytable,utable, vtable] = peakfinding (result_conv_ensemble, mask, interrogationarea,minix,step,maxix,miniy,maxiy,SubPixOffset,ss1,subpixfinder);
			if verLessThan('matlab','8.4')
				delete (findobj(getappdata(0,'hgui'),'type', 'hggroup'))
			else
				delete (findobj(getappdata(0,'hgui'),'type', 'quiver'))
			end
			hold on;
			vecscale=str2double(get(handles.vectorscale,'string'));
			%Problem: wenn colorbar an, zï¿½hlt das auch als aexes...
			colorbar('off')

			%u_table original gibts nicjt, braichts auch nicht...
			quiver ((findobj(getappdata(0,'hgui'),'type', 'axes')),xtable(isnan(utable)==0)+xroi-interrogationarea/2,ytable(isnan(utable)==0)+yroi-interrogationarea/2,utable(isnan(utable)==0)*vecscale,vtable(isnan(utable)==0)*vecscale,'Color', [1-(from_total / total_analyses_amount) (from_total / total_analyses_amount) 0.15],'autoscale','off')
			%quiver ((findobj(getappdata(0,'hgui'),'type', 'axes')),xtable(isnan(utable)==1)+xroi-interrogationarea/2,ytable(isnan(utable)==1)+yroi-interrogationarea/2,utable(isnan(utable)==1)*vecscale,vtable(isnan(utable)==1)*vecscale,'Color',[0.7 0.15 0.15], 'autoscale','off')
			hold off
			drawnow;
		end
		if skippy <10
			skippy=skippy+1;
		else
			skippy=0;
		end
		try
			drawnow limitrate
		catch
			drawnow
		end
	else
		fprintf('.');
	end
	if passes==1 % only 1 pass selected, so correlation coefficient will be calculated in this (first & final) pass.
		if ensemble_i1==1 %first image pair
			correlation_map=zeros(size(typevector));
			corr_map_cnt=0;
		end
		for cor_i=1:size(image1_cut,3)
			correlation_map(cor_i)=correlation_map(cor_i) + corr2(image1_cut(:,:,cor_i),image2_cut(:,:,cor_i));
		end
		corr_map_cnt=corr_map_cnt+1;
	end
end
%correlation_map=[];
if cancel == 0
	%% Correlation matrix of pass 1 is done.
	[xtable,ytable,utable, vtable] = peakfinding (result_conv_ensemble, mask, interrogationarea,minix,step,maxix,miniy,maxiy,SubPixOffset,ss1,subpixfinder);

	for multipass=1:passes-1
		% unfortunately, preprocessing has to be done again for every pass, otherwise i would have to save the modified data somehow.
		if multipass==1
			interrogationarea=round(int2/2)*2;
		end
		if multipass==2
			interrogationarea=round(int3/2)*2;
		end
		if multipass==3
			interrogationarea=round(int4/2)*2;
		end
		result_conv_ensemble = zeros(interrogationarea,interrogationarea); % prepare empty result_conv
		skippy=0;
		for ensemble_i1=1:2:amount_input_imgs
			if skippy <10
				skippy=skippy+1;
			else
				skippy=0;
			end
			if isempty(video_frame_selection) %list with image files was passed
				if strcmp(ext,'.b16')
					image1=f_readB16(filepath{ensemble_i1});
					image2=f_readB16(filepath{ensemble_i1+1});
				else
					image1=imread(filepath{ensemble_i1});
					image2=imread(filepath{ensemble_i1+1});
				end
			else % video file was passed
				image1 = read(filepath,video_frame_selection(ensemble_i1));
				image2 = read(filepath,video_frame_selection(ensemble_i1+1));
			end
			if size(image1,3)>1
				image1=uint8(mean(image1,3));
				image2=uint8(mean(image2,3));
			end
			%subtract bg if present
			if ~isempty(bg_img_A)
				image1=image1-bg_img_A;
			end
			if ~isempty(bg_img_B)
				image2=image2-bg_img_B;
			end
			%if autolimit == 1 %if autolimit is desired: do autolimit for each image seperately
				if size(image1,3)>1
					stretcher = stretchlim(rgb2gray(image1));
				else
					stretcher = stretchlim(image1);
				end
				minintens1 = stretcher(1);
				maxintens1 = stretcher(2);
				if size(image2,3)>1
					stretcher = stretchlim(rgb2gray(image2));
				else
					stretcher = stretchlim(image2);
				end
				minintens2 = stretcher(1);
				maxintens2 = stretcher(2);
			%end
			image1 = PIVlab_preproc (image1,roi_inpt,clahe, clahesize,highp,highpsize,intenscap,wienerwurst,wienerwurstsize,minintens1,maxintens1);
			image2 = PIVlab_preproc (image2,roi_inpt,clahe, clahesize,highp,highpsize,intenscap,wienerwurst,wienerwurstsize,minintens2,maxintens2);
			if numel(roi_inpt)>0
				xroi=roi_inpt(1);
				yroi=roi_inpt(2);
				widthroi=roi_inpt(3);
				heightroi=roi_inpt(4);
				image1_roi=double(image1(yroi:yroi+heightroi,xroi:xroi+widthroi));
				image2_roi=double(image2(yroi:yroi+heightroi,xroi:xroi+widthroi));
			else
				xroi=0;
				yroi=0;
				image1_roi=double(image1);
				image2_roi=double(image2);
			end
			gen_image1_roi = image1_roi;
			gen_image2_roi = image2_roi;
			if GUI_avail==1
				progri=ensemble_i1/(amount_input_imgs)*100;
				from_total=from_total+1;
				set(handles.progress, 'string' , ['Pass ' int2str(multipass+1) ' progress: ' int2str(progri) '%' ])
				set(handles.overall, 'string' , ['Total progress: ' int2str(from_total / total_analyses_amount * 100) '%'])

				zeit=toc;
				done=from_total;
				tocome=total_analyses_amount-done;
				zeit=zeit/done*tocome;
				hrs=zeit/60^2;
				mins=(hrs-floor(hrs))*60;
				secs=(mins-floor(mins))*60;
				hrs=floor(hrs);
				mins=floor(mins);
				secs=floor(secs);
				set(handles.totaltime,'string', ['Time left: ' sprintf('%2.2d', hrs) 'h ' sprintf('%2.2d', mins) 'm ' sprintf('%2.2d', secs) 's']);
				try
					drawnow limitrate

				catch
					drawnow
				end
			else
				fprintf('.');
			end
			%multipass validation, smoothing
			utable_orig=utable;
			vtable_orig=vtable;
			[utable,vtable] = PIVlab_postproc (utable,vtable,[],[], [], 1,4, 1,1.5);
			if GUI_avail==1
				cancel=getappdata(hgui, 'cancel');
				if cancel == 1
					break
					%disp('user cancelled');
				end
				if skippy ==0
					if verLessThan('matlab','8.4')
						delete (findobj(getappdata(0,'hgui'),'type', 'hggroup'))
					else
						delete (findobj(getappdata(0,'hgui'),'type', 'quiver'))
					end
					hold on;
					vecscale=str2double(get(handles.vectorscale,'string'));
					%Problem: wenn colorbar an, zï¿½hlt das auch als aexes...
					colorbar('off')
					quiver ((findobj(getappdata(0,'hgui'),'type', 'axes')),xtable(isnan(utable)==0)+xroi-interrogationarea/2,ytable(isnan(utable)==0)+yroi-interrogationarea/2,utable(isnan(utable)==0)*vecscale,vtable(isnan(utable)==0)*vecscale,'Color', [1-(from_total / total_analyses_amount) (from_total / total_analyses_amount) 0.15],'autoscale','off')

					%                    quiver ((findobj(getappdata(0,'hgui'),'type', 'axes')),xtable(isnan(utable)==0)+xroi-interrogationarea/2,ytable(isnan(utable)==0)+yroi-interrogationarea/2,utable_orig(isnan(utable)==0)*vecscale,vtable_orig(isnan(utable)==0)*vecscale,'Color', [0.15 0.7 0.15],'autoscale','off')
					%quiver ((findobj(getappdata(0,'hgui'),'type', 'axes')),xtable(isnan(utable)==1)+xroi-interrogationarea/2,ytable(isnan(utable)==1)+yroi-interrogationarea/2,utable_orig(isnan(utable)==1)*vecscale,vtable_orig(isnan(utable)==1)*vecscale,'Color',[0.7 0.15 0.15], 'autoscale','off')
					drawnow
					hold off
				end
			end
			%replace nans
			utable=inpaint_nans(utable,4);
			vtable=inpaint_nans(vtable,4);
			%smooth predictor
			try
				if multipass<passes-1
					utable = smoothn(utable,0.6); %stronger smoothing for first passes
					vtable = smoothn(vtable,0.6);
				else
					utable = smoothn(utable); %weaker smoothing for last pass
					vtable = smoothn(vtable);
				end
			catch
				%old matlab versions: gaussian kernel
				h=fspecial('gaussian',5,1);
				utable=imfilter(utable,h,'replicate');
				vtable=imfilter(vtable,h,'replicate');
			end
			if multipass==1
				interrogationarea=round(int2/2)*2;
			end
			if multipass==2
				interrogationarea=round(int3/2)*2;
			end
			if multipass==3
				interrogationarea=round(int4/2)*2;
			end
			step=interrogationarea/2;

			%bildkoordinaten neu errechnen:
			image1_roi = gen_image1_roi;
			image2_roi = gen_image2_roi;
			%get mask from mask list
			ximask={};
			yimask={};
			if size(maskiererx,2)>=ensemble_i1
				for j=1:size(maskiererx,1)
					if isempty(maskiererx{j,ensemble_i1})==0
						ximask{j,1}=maskiererx{j,ensemble_i1}; %#ok<*AGROW>
						yimask{j,1}=maskierery{j,ensemble_i1};
					else
						break
					end
				end
				if size(ximask,1)>0
					mask_inpt=[ximask yimask];
				else
					mask_inpt=[];
				end
			else
				mask_inpt=[];
			end
			if numel(mask_inpt)>0
				cellmask=mask_inpt;
				mask=zeros(size(image1_roi));
				for i=1:size(cellmask,1)
					masklayerx=cellmask{i,1};
					masklayery=cellmask{i,2};
					mask = mask + poly2mask(masklayerx-xroi,masklayery-yroi,size(image1_roi,1),size(image1_roi,2)); %kleineres eingangsbild und maske geshiftet
				end
			else
				mask=zeros(size(image1_roi));
			end
			mask(mask>1)=1;
			gen_mask = mask;
			miniy=1+(ceil(interrogationarea/2));
			minix=1+(ceil(interrogationarea/2));
			maxiy=step*(floor(size(image1_roi,1)/step))-(interrogationarea-1)+(ceil(interrogationarea/2)); %statt size deltax von ROI nehmen
			maxix=step*(floor(size(image1_roi,2)/step))-(interrogationarea-1)+(ceil(interrogationarea/2));

			numelementsy=floor((maxiy-miniy)/step+1);
			numelementsx=floor((maxix-minix)/step+1);

			LAy=miniy;
			LAx=minix;
			LUy=size(image1_roi,1)-maxiy;
			LUx=size(image1_roi,2)-maxix;
			shift4centery=round((LUy-LAy)/2);
			shift4centerx=round((LUx-LAx)/2);
			if shift4centery<0 %shift4center will be negative if in the unshifted case the left border is bigger than the right border. the vectormatrix is hence not centered on the image. the matrix cannot be shifted more towards the left border because then image2_crop would have a negative index. The only way to center the matrix would be to remove a column of vectors on the right side. but then we weould have less data....
				shift4centery=0;
			end
			if shift4centerx<0 %shift4center will be negative if in the unshifted case the left border is bigger than the right border. the vectormatrix is hence not centered on the image. the matrix cannot be shifted more towards the left border because then image2_crop would have a negative index. The only way to center the matrix would be to remove a column of vectors on the right side. but then we weould have less data....
				shift4centerx=0;
			end
			miniy=miniy+shift4centery;
			minix=minix+shift4centerx;
			maxix=maxix+shift4centerx;
			maxiy=maxiy+shift4centery;

			image1_roi=padarray(image1_roi,[ceil(interrogationarea/2) ceil(interrogationarea/2)], min(min(image1_roi)));
			image2_roi=padarray(image2_roi,[ceil(interrogationarea/2) ceil(interrogationarea/2)], min(min(image1_roi)));
			mask=padarray(mask,[ceil(interrogationarea/2) ceil(interrogationarea/2)],0);
			if (rem(interrogationarea,2) == 0) %for the subpixel displacement measurement
				SubPixOffset=1;
			else
				SubPixOffset=0.5;
			end

			xtable_old=xtable;
			ytable_old=ytable;
			typevector=ones(numelementsy,numelementsx);
			xtable = repmat((minix:step:maxix), numelementsy, 1) + interrogationarea/2;
			ytable = repmat((miniy:step:maxiy)', 1, numelementsx) + interrogationarea/2;

			%xtable alt und neu geben koordinaten wo die vektoren herkommen.
			%d.h. u und v auf die gewï¿½nschte grï¿½ï¿½e bringen+interpolieren

			utable=interp2(xtable_old,ytable_old,utable,xtable,ytable,'*spline');
			vtable=interp2(xtable_old,ytable_old,vtable,xtable,ytable,'*spline');

			utable_1= padarray(utable, [1,1], 'replicate');
			vtable_1= padarray(vtable, [1,1], 'replicate');

			%add 1 line around image for border regions... linear extrap

			firstlinex=xtable(1,:);
			firstlinex_intp=interp1(1:1:size(firstlinex,2),firstlinex,0:1:size(firstlinex,2)+1,'linear','extrap');
			xtable_1=repmat(firstlinex_intp,size(xtable,1)+2,1);

			firstliney=ytable(:,1);
			firstliney_intp=interp1(1:1:size(firstliney,1),firstliney,0:1:size(firstliney,1)+1,'linear','extrap')';
			ytable_1=repmat(firstliney_intp,1,size(ytable,2)+2);

			X=xtable_1; %original locations of vectors in whole image
			Y=ytable_1;
			U=utable_1; %interesting portion of u
			V=vtable_1; % "" of v

			X1=X(1,1):1:X(1,end)-1;
			Y1=(Y(1,1):1:Y(end,1)-1)';
			X1=repmat(X1,size(Y1, 1),1);
			Y1=repmat(Y1,1,size(X1, 2));

			U1 = interp2(X,Y,U,X1,Y1,'*linear');
			V1 = interp2(X,Y,V,X1,Y1,'*linear');

			image2_crop_i1 = interp2(1:size(image2_roi,2),(1:size(image2_roi,1))',double(image2_roi),X1+U1,Y1+V1,imdeform); %linear is 3x faster and looks ok...

			xb = find(X1(1,:) == xtable_1(1,1));
			yb = find(Y1(:,1) == ytable_1(1,1));

			% divide images by small pictures
			% new index for image1_roi
			s0 = (repmat((miniy:step:maxiy)'-1, 1,numelementsx) + repmat(((minix:step:maxix)-1)*size(image1_roi, 1), numelementsy,1))';
			s0 = permute(s0(:), [2 3 1]);
			s1 = repmat((1:interrogationarea)',1,interrogationarea) + repmat(((1:interrogationarea)-1)*size(image1_roi, 1),interrogationarea,1);
			ss1 = repmat(s1, [1, 1, size(s0,3)]) + repmat(s0, [interrogationarea, interrogationarea, 1]);
			% new index for image2_crop_i1
			s0 = (repmat(yb-step+step*(1:numelementsy)'-1, 1,numelementsx) + repmat((xb-step+step*(1:numelementsx)-1)*size(image2_crop_i1, 1), numelementsy,1))';
			s0 = permute(s0(:), [2 3 1]) - s0(1);
			s2 = repmat((1:2*step)',1,2*step) + repmat(((1:2*step)-1)*size(image2_crop_i1, 1),2*step,1);
			ss2 = repmat(s2, [1, 1, size(s0,3)]) + repmat(s0, [interrogationarea, interrogationarea, 1]);
			image1_cut = image1_roi(ss1);
			image2_cut = image2_crop_i1(ss2);
			if do_pad==1 && multipass==passes-1
				%subtract mean to avoid high frequencies at border of correlation:
				try
					image1_cut=image1_cut-mean(image1_cut,[1 2]);
					image2_cut=image2_cut-mean(image2_cut,[1 2]);
				catch
					for oldmatlab=1:size(image1_cut,3);
						image1_cut(:,:,oldmatlab)=image1_cut(:,:,oldmatlab)-mean(mean(image1_cut(:,:,oldmatlab)));
						image2_cut(:,:,oldmatlab)=image2_cut(:,:,oldmatlab)-mean(mean(image2_cut(:,:,oldmatlab)));
					end
				end
				% padding (faster than padarray) to get the linear correlation:
				image1_cut=[image1_cut zeros(interrogationarea,interrogationarea-1,size(image1_cut,3)); zeros(interrogationarea-1,2*interrogationarea-1,size(image1_cut,3))];
				image2_cut=[image2_cut zeros(interrogationarea,interrogationarea-1,size(image2_cut,3)); zeros(interrogationarea-1,2*interrogationarea-1,size(image2_cut,3))];
			end
			%do fft2:
			result_conv = fftshift(fftshift(real(ifft2(conj(fft2(image1_cut)).*fft2(image2_cut))), 1), 2);
			if do_pad==1 && multipass==passes-1
				%cropping of correlation matrix:
				result_conv =result_conv((interrogationarea/2):(3*interrogationarea/2)-1,(interrogationarea/2):(3*interrogationarea/2)-1,:);
			end

			%% repeated correlation
			if repeat == 1 && multipass==passes-1
				ms=round(step/4); %multishift parameter so groß wie viertel int window

				%Shift left bot
				image2_crop_i1 = interp2(1:size(image2_roi,2),(1:size(image2_roi,1))',double(image2_roi),X1+U1-ms,Y1+V1+ms,imdeform); %linear is 3x faster and looks ok...
				xb = find(X1(1,:) == xtable_1(1,1));
				yb = find(Y1(:,1) == ytable_1(1,1));
				s0 = (repmat((miniy+ms:step:maxiy+ms)'-1, 1,numelementsx) + repmat(((minix-ms:step:maxix-ms)-1)*size(image1_roi, 1), numelementsy,1))';
				s0 = permute(s0(:), [2 3 1]);
				s1 = repmat((1:interrogationarea)',1,interrogationarea) + repmat(((1:interrogationarea)-1)*size(image1_roi, 1),interrogationarea,1);
				ss1 = repmat(s1, [1, 1, size(s0,3)]) + repmat(s0, [interrogationarea, interrogationarea, 1]);
				s0 = (repmat(yb-step+step*(1:numelementsy)'-1, 1,numelementsx) + repmat((xb-step+step*(1:numelementsx)-1)*size(image2_crop_i1, 1), numelementsy,1))';
				s0 = permute(s0(:), [2 3 1]) - s0(1);
				s2 = repmat((1:2*step)',1,2*step) + repmat(((1:2*step)-1)*size(image2_crop_i1, 1),2*step,1);
				ss2 = repmat(s2, [1, 1, size(s0,3)]) + repmat(s0, [interrogationarea, interrogationarea, 1]);
				image1_cut = image1_roi(ss1);
				image2_cut = image2_crop_i1(ss2);
				if do_pad==1 && multipass==passes-1
					%subtract mean to avoid high frequencies at border of correlation:
					try
						image1_cut=image1_cut-mean(image1_cut,[1 2]);
						image2_cut=image2_cut-mean(image2_cut,[1 2]);
					catch
						for oldmatlab=1:size(image1_cut,3);
							image1_cut(:,:,oldmatlab)=image1_cut(:,:,oldmatlab)-mean(mean(image1_cut(:,:,oldmatlab)));
							image2_cut(:,:,oldmatlab)=image2_cut(:,:,oldmatlab)-mean(mean(image2_cut(:,:,oldmatlab)));
						end
					end
					% padding (faster than padarray) to get the linear correlation:
					image1_cut=[image1_cut zeros(interrogationarea,interrogationarea-1,size(image1_cut,3)); zeros(interrogationarea-1,2*interrogationarea-1,size(image1_cut,3))];
					image2_cut=[image2_cut zeros(interrogationarea,interrogationarea-1,size(image2_cut,3)); zeros(interrogationarea-1,2*interrogationarea-1,size(image2_cut,3))];
				end
				result_convB = fftshift(fftshift(real(ifft2(conj(fft2(image1_cut)).*fft2(image2_cut))), 1), 2);
				if do_pad==1 && multipass==passes-1
					%cropping of correlation matrix:
					result_convB =result_convB((interrogationarea/2):(3*interrogationarea/2)-1,(interrogationarea/2):(3*interrogationarea/2)-1,:);
				end
				%Shift right bot
				image2_crop_i1 = interp2(1:size(image2_roi,2),(1:size(image2_roi,1))',double(image2_roi),X1+U1+ms,Y1+V1+ms,imdeform); %linear is 3x faster and looks ok...
				xb = find(X1(1,:) == xtable_1(1,1));
				yb = find(Y1(:,1) == ytable_1(1,1));
				s0 = (repmat((miniy+ms:step:maxiy+ms)'-1, 1,numelementsx) + repmat(((minix+ms:step:maxix+ms)-1)*size(image1_roi, 1), numelementsy,1))';
				s0 = permute(s0(:), [2 3 1]);
				s1 = repmat((1:interrogationarea)',1,interrogationarea) + repmat(((1:interrogationarea)-1)*size(image1_roi, 1),interrogationarea,1);
				ss1 = repmat(s1, [1, 1, size(s0,3)]) + repmat(s0, [interrogationarea, interrogationarea, 1]);
				s0 = (repmat(yb-step+step*(1:numelementsy)'-1, 1,numelementsx) + repmat((xb-step+step*(1:numelementsx)-1)*size(image2_crop_i1, 1), numelementsy,1))';
				s0 = permute(s0(:), [2 3 1]) - s0(1);
				s2 = repmat((1:2*step)',1,2*step) + repmat(((1:2*step)-1)*size(image2_crop_i1, 1),2*step,1);
				ss2 = repmat(s2, [1, 1, size(s0,3)]) + repmat(s0, [interrogationarea, interrogationarea, 1]);
				image1_cut = image1_roi(ss1);
				image2_cut = image2_crop_i1(ss2);
				if do_pad==1 && multipass==passes-1
					%subtract mean to avoid high frequencies at border of correlation:
					try
						image1_cut=image1_cut-mean(image1_cut,[1 2]);
						image2_cut=image2_cut-mean(image2_cut,[1 2]);
					catch
						for oldmatlab=1:size(image1_cut,3);
							image1_cut(:,:,oldmatlab)=image1_cut(:,:,oldmatlab)-mean(mean(image1_cut(:,:,oldmatlab)));
							image2_cut(:,:,oldmatlab)=image2_cut(:,:,oldmatlab)-mean(mean(image2_cut(:,:,oldmatlab)));
						end
					end
					% padding (faster than padarray) to get the linear correlation:
					image1_cut=[image1_cut zeros(interrogationarea,interrogationarea-1,size(image1_cut,3)); zeros(interrogationarea-1,2*interrogationarea-1,size(image1_cut,3))];
					image2_cut=[image2_cut zeros(interrogationarea,interrogationarea-1,size(image2_cut,3)); zeros(interrogationarea-1,2*interrogationarea-1,size(image2_cut,3))];
				end
				result_convC = fftshift(fftshift(real(ifft2(conj(fft2(image1_cut)).*fft2(image2_cut))), 1), 2);
				if do_pad==1 && multipass==passes-1
					%cropping of correlation matrix:
					result_convC =result_convC((interrogationarea/2):(3*interrogationarea/2)-1,(interrogationarea/2):(3*interrogationarea/2)-1,:);
				end
				%Shift left top
				image2_crop_i1 = interp2(1:size(image2_roi,2),(1:size(image2_roi,1))',double(image2_roi),X1+U1-ms,Y1+V1-ms,imdeform); %linear is 3x faster and looks ok...
				xb = find(X1(1,:) == xtable_1(1,1));
				yb = find(Y1(:,1) == ytable_1(1,1));
				s0 = (repmat((miniy-ms:step:maxiy-ms)'-1, 1,numelementsx) + repmat(((minix-ms:step:maxix-ms)-1)*size(image1_roi, 1), numelementsy,1))';
				s0 = permute(s0(:), [2 3 1]);
				s1 = repmat((1:interrogationarea)',1,interrogationarea) + repmat(((1:interrogationarea)-1)*size(image1_roi, 1),interrogationarea,1);
				ss1 = repmat(s1, [1, 1, size(s0,3)]) + repmat(s0, [interrogationarea, interrogationarea, 1]);
				s0 = (repmat(yb-step+step*(1:numelementsy)'-1, 1,numelementsx) + repmat((xb-step+step*(1:numelementsx)-1)*size(image2_crop_i1, 1), numelementsy,1))';
				s0 = permute(s0(:), [2 3 1]) - s0(1);
				s2 = repmat((1:2*step)',1,2*step) + repmat(((1:2*step)-1)*size(image2_crop_i1, 1),2*step,1);
				ss2 = repmat(s2, [1, 1, size(s0,3)]) + repmat(s0, [interrogationarea, interrogationarea, 1]);
				image1_cut = image1_roi(ss1);
				image2_cut = image2_crop_i1(ss2);
				if do_pad==1 && multipass==passes-1
					%subtract mean to avoid high frequencies at border of correlation:
					try
						image1_cut=image1_cut-mean(image1_cut,[1 2]);
						image2_cut=image2_cut-mean(image2_cut,[1 2]);
					catch
						for oldmatlab=1:size(image1_cut,3)
							image1_cut(:,:,oldmatlab)=image1_cut(:,:,oldmatlab)-mean(mean(image1_cut(:,:,oldmatlab)));
							image2_cut(:,:,oldmatlab)=image2_cut(:,:,oldmatlab)-mean(mean(image2_cut(:,:,oldmatlab)));
						end
					end
					% padding (faster than padarray) to get the linear correlation:
					image1_cut=[image1_cut zeros(interrogationarea,interrogationarea-1,size(image1_cut,3)); zeros(interrogationarea-1,2*interrogationarea-1,size(image1_cut,3))];
					image2_cut=[image2_cut zeros(interrogationarea,interrogationarea-1,size(image2_cut,3)); zeros(interrogationarea-1,2*interrogationarea-1,size(image2_cut,3))];
				end
				result_convD = fftshift(fftshift(real(ifft2(conj(fft2(image1_cut)).*fft2(image2_cut))), 1), 2);
				if do_pad==1 && multipass==passes-1
					%cropping of correlation matrix:
					result_convD =result_convD((interrogationarea/2):(3*interrogationarea/2)-1,(interrogationarea/2):(3*interrogationarea/2)-1,:);
				end
				%Shift right top
				image2_crop_i1 = interp2(1:size(image2_roi,2),(1:size(image2_roi,1))',double(image2_roi),X1+U1+ms,Y1+V1-ms,imdeform); %linear is 3x faster and looks ok...
				xb = find(X1(1,:) == xtable_1(1,1));
				yb = find(Y1(:,1) == ytable_1(1,1));
				s0 = (repmat((miniy-ms:step:maxiy-ms)'-1, 1,numelementsx) + repmat(((minix+ms:step:maxix+ms)-1)*size(image1_roi, 1), numelementsy,1))';
				s0 = permute(s0(:), [2 3 1]);
				s1 = repmat((1:interrogationarea)',1,interrogationarea) + repmat(((1:interrogationarea)-1)*size(image1_roi, 1),interrogationarea,1);
				ss1 = repmat(s1, [1, 1, size(s0,3)]) + repmat(s0, [interrogationarea, interrogationarea, 1]);
				s0 = (repmat(yb-step+step*(1:numelementsy)'-1, 1,numelementsx) + repmat((xb-step+step*(1:numelementsx)-1)*size(image2_crop_i1, 1), numelementsy,1))';
				s0 = permute(s0(:), [2 3 1]) - s0(1);
				s2 = repmat((1:2*step)',1,2*step) + repmat(((1:2*step)-1)*size(image2_crop_i1, 1),2*step,1);
				ss2 = repmat(s2, [1, 1, size(s0,3)]) + repmat(s0, [interrogationarea, interrogationarea, 1]);
				image1_cut = image1_roi(ss1);
				image2_cut = image2_crop_i1(ss2);
				if do_pad==1 && multipass==passes-1
					%subtract mean to avoid high frequencies at border of correlation:
					try
						image1_cut=image1_cut-mean(image1_cut,[1 2]);
						image2_cut=image2_cut-mean(image2_cut,[1 2]);
					catch
						for oldmatlab=1:size(image1_cut,3)
							image1_cut(:,:,oldmatlab)=image1_cut(:,:,oldmatlab)-mean(mean(image1_cut(:,:,oldmatlab)));
							image2_cut(:,:,oldmatlab)=image2_cut(:,:,oldmatlab)-mean(mean(image2_cut(:,:,oldmatlab)));
						end
					end
					% padding (faster than padarray) to get the linear correlation:
					image1_cut=[image1_cut zeros(interrogationarea,interrogationarea-1,size(image1_cut,3)); zeros(interrogationarea-1,2*interrogationarea-1,size(image1_cut,3))];
					image2_cut=[image2_cut zeros(interrogationarea,interrogationarea-1,size(image2_cut,3)); zeros(interrogationarea-1,2*interrogationarea-1,size(image2_cut,3))];
				end
				result_convE = fftshift(fftshift(real(ifft2(conj(fft2(image1_cut)).*fft2(image2_cut))), 1), 2);
				if do_pad==1 && multipass==passes-1
					%cropping of correlation matrix:
					result_convE =result_convE((interrogationarea/2):(3*interrogationarea/2)-1,(interrogationarea/2):(3*interrogationarea/2)-1,:);
				end
				result_conv=result_conv.*result_convB.*result_convC.*result_convD.*result_convE;
			end

			if mask_auto == 1
				%limit peak search arena....
				emptymatrix=zeros(size(result_conv,1),size(result_conv,2),size(result_conv,3));
				%emptymatrix=emptymatrix+0.1;
				if interrogationarea > 8 % masking central peak will not work for extrmely small interrogation areas. And it also doesn't make sense.
					sizeones=4;
					%h = fspecial('gaussian', sizeones*2+1,1);
					h=fspecial('disk',4);
					h=h/max(max(h));
					%h=repmat(h,1,1,size(result_conv,3));
					h=repmat(h,[1,1,size(result_conv,3)]);
					emptymatrix((interrogationarea/2)+SubPixOffset-sizeones:(interrogationarea/2)+SubPixOffset+sizeones,(interrogationarea/2)+SubPixOffset-sizeones:(interrogationarea/2)+SubPixOffset+sizeones,:)=h;
					result_conv = result_conv .* emptymatrix;
				else
					disp('All interrogation areas must be larger than 8 pixels for disabling auto correlation successfully.')
				end
			end

			%apply mask ---
			ii = find(mask(ss1(round(interrogationarea/2+1), round(interrogationarea/2+1), :)));
			result_conv(:,:, ii) = 0;
			%add alle result_conv
			try
				result_conv_ensemble=result_conv_ensemble+result_conv;
			catch % older matlab releases
				result_conv_ensemble = zeros(size(result_conv));
				result_conv_ensemble=result_conv_ensemble+result_conv;
			end

			if multipass==passes-1 %correlation strength only in last pass

				if ensemble_i1==1 %first image pair
					correlation_map=zeros(size(typevector));
					corr_map_cnt=0;
				end
				%Correlation strength
				for cor_i=1:size(image1_cut,3)
					correlation_map(cor_i)=correlation_map(cor_i)+corr2(image1_cut(:,:,cor_i),image2_cut(:,:,cor_i));
				end
				corr_map_cnt=corr_map_cnt+1;
			end
		end
		[xtable,ytable,utable2, vtable2] = peakfinding (result_conv_ensemble, [], interrogationarea,minix,step,maxix,miniy,maxiy,SubPixOffset,ss1,subpixfinder);
		utable = utable+utable2;
		vtable = vtable+vtable2;
	end
	if cancel == 0
		%mask only if all frames are masked
		%apply mask
		nrx=0;
		nrxreal=0;
		nry=0;
		average_mask=padarray(average_mask,[ceil(interrogationarea/2) ceil(interrogationarea/2)],0);
		for jmask = miniy:step:maxiy %vertical loop
			nry=nry+1;
			for imask = minix:step:maxix % horizontal loop
				nrx=nrx+1;%used to determine the pos of the vector in resulting matrix
				if nrxreal < numelementsx
					nrxreal=nrxreal+1;
				else
					nrxreal=1;
				end
				%fehlerzeile:
				if average_mask(round(jmask+interrogationarea/2),round(imask+interrogationarea/2)) >= amount_input_imgs/2
					typevector(nry,nrxreal)=0;
				end
			end
		end
		xtable=xtable-ceil(interrogationarea/2);
		ytable=ytable-ceil(interrogationarea/2);

		xtable=xtable+xroi;
		ytable=ytable+yroi;
	end
	%% Write correlation matrices to the workspace
	%{
try
    counter=evalin('base','counter');
    counter=counter+1;
    assignin('base','counter',counter);
    all_matrices=evalin('base','all_matrices');
    all_matrices{end+1}=result_conv_ensemble;
    assignin('base','all_matrices',all_matrices);
    disp('appended matrix')
catch
    assignin('base','counter',1);
    all_matrices{1}=result_conv_ensemble;
    assignin('base','all_matrices',all_matrices);
    disp('created new matrix')
end
	%}
	correlation_map = permute(reshape(correlation_map, [size(xtable')]), [2 1 3])/corr_map_cnt;
	%clear Correlation map in masked area
	correlation_map(typevector==0) = 0;
end

function [xtable,ytable,utable, vtable] = peakfinding (result_conv_ensemble, mask, interrogationarea,minix,step,maxix,miniy,maxiy,SubPixOffset,ss1,subpixfinder)
minres = permute(repmat(squeeze(min(min(result_conv_ensemble))), [1, size(result_conv_ensemble, 1), size(result_conv_ensemble, 2)]), [2 3 1]);
deltares = permute(repmat(squeeze(max(max(result_conv_ensemble))-min(min(result_conv_ensemble))),[ 1, size(result_conv_ensemble, 1), size(result_conv_ensemble, 2)]), [2 3 1]);
result_conv_ensemble = ((result_conv_ensemble-minres)./deltares)*255;

%apply mask ---
if isempty (mask)==0
	ii = find(mask(ss1(round(interrogationarea/2+1), round(interrogationarea/2+1), :)));
	result_conv_ensemble(:,:, ii) = 0;
end

[y, x, z] = ind2sub(size(result_conv_ensemble), find(result_conv_ensemble==255));

% we need only one peak from each couple pictures
[z1, zi] = sort(z);
dz1 = [z1(1); diff(z1)];
i0 = find(dz1~=0);
x1 = x(zi(i0));
y1 = y(zi(i0));
z1 = z(zi(i0));

xtable = repmat((minix:step:maxix)+interrogationarea/2, length(miniy:step:maxiy), 1);
ytable = repmat(((miniy:step:maxiy)+interrogationarea/2)', 1, length(minix:step:maxix));

if subpixfinder==1
	[vector] = SUBPIXGAUSS (result_conv_ensemble,interrogationarea, x1, y1, z1, SubPixOffset);
elseif subpixfinder==2
	[vector] = SUBPIX2DGAUSS (result_conv_ensemble,interrogationarea, x1, y1, z1, SubPixOffset);
end
vector = permute(reshape(vector, [size(xtable') 2]), [2 1 3]);

utable = vector(:,:,1);
vtable = vector(:,:,2);

function [vector] = SUBPIXGAUSS(result_conv, interrogationarea, x, y, z, SubPixOffset)
%was hat peak nr.1 für einen Durchmesser?
%figure;imagesc((1-im2bw(uint8(result_conv(:,:,155)),0.9)).*result_conv(:,:,101))
xi = find(~((x <= (size(result_conv,2)-1)) & (y <= (size(result_conv,1)-1)) & (x >= 2) & (y >= 2)));
x(xi) = [];
y(xi) = [];
z(xi) = [];
xmax = size(result_conv, 2);
vector = NaN(size(result_conv,3), 2);
if(numel(x)~=0)
	ip = sub2ind(size(result_conv), y, x, z);
	%the following 8 lines are copyright (c) 1998, Uri Shavit, Roi Gurka, Alex Liberzon, Technion ï¿½ Israel Institute of Technology
	%http://urapiv.wordpress.com
	f0 = log(result_conv(ip));
	f1 = log(result_conv(ip-1));
	f2 = log(result_conv(ip+1));
	peaky = y + (f1-f2)./(2*f1-4*f0+2*f2);
	f0 = log(result_conv(ip));
	f1 = log(result_conv(ip-xmax));
	f2 = log(result_conv(ip+xmax));
	peakx = x + (f1-f2)./(2*f1-4*f0+2*f2);

	SubpixelX=peakx-(interrogationarea/2)-SubPixOffset;
	SubpixelY=peaky-(interrogationarea/2)-SubPixOffset;
	vector(z, :) = [SubpixelX, SubpixelY];
end

function [vector] = SUBPIX2DGAUSS(result_conv, interrogationarea, x, y, z, SubPixOffset)
xi = find(~((x <= (size(result_conv,2)-1)) & (y <= (size(result_conv,1)-1)) & (x >= 2) & (y >= 2)));
x(xi) = [];
y(xi) = [];
z(xi) = [];
xmax = size(result_conv, 2);
vector = NaN(size(result_conv,3), 2);
if(numel(x)~=0)
	c10 = zeros(3,3, length(z));
	c01 = c10;
	c11 = c10;
	c20 = c10;
	c02 = c10;
	ip = sub2ind(size(result_conv), y, x, z);

	for i = -1:1
		for j = -1:1
			%following 15 lines based on
			%H. Nobach ï¿½ M. Honkanen (2005)
			%Two-dimensional Gaussian regression for sub-pixel displacement
			%estimation in particle image velocimetry or particle position
			%estimation in particle tracking velocimetry
			%Experiments in Fluids (2005) 38: 511ï¿½515
			c10(j+2,i+2, :) = i*log(result_conv(ip+xmax*i+j));
			c01(j+2,i+2, :) = j*log(result_conv(ip+xmax*i+j));
			c11(j+2,i+2, :) = i*j*log(result_conv(ip+xmax*i+j));
			c20(j+2,i+2, :) = (3*i^2-2)*log(result_conv(ip+xmax*i+j));
			c02(j+2,i+2, :) = (3*j^2-2)*log(result_conv(ip+xmax*i+j));
			%c00(j+2,i+2)=(5-3*i^2-3*j^2)*log(result_conv_norm(maxY+j, maxX+i));
		end
	end
	c10 = (1/6)*sum(sum(c10));
	c01 = (1/6)*sum(sum(c01));
	c11 = (1/4)*sum(sum(c11));
	c20 = (1/6)*sum(sum(c20));
	c02 = (1/6)*sum(sum(c02));
	%c00=(1/9)*sum(sum(c00));

	deltax = squeeze((c11.*c01-2*c10.*c02)./(4*c20.*c02-c11.^2));
	deltay = squeeze((c11.*c10-2*c01.*c20)./(4*c20.*c02-c11.^2));
	peakx = x+deltax;
	peaky = y+deltay;

	SubpixelX = peakx-(interrogationarea/2)-SubPixOffset;
	SubpixelY = peaky-(interrogationarea/2)-SubPixOffset;

	vector(z, :) = [SubpixelX, SubpixelY];
end


classdef Drawable < handle

% Copyright (C) 2013, Georgia Tech Research Corporation
% see the LICENSE file included with this software

    properties
        surfaces
        parent
    end

    properties (Access = protected)
        pose
    end

    methods
        function obj = Drawable(parent, pose)
           obj.pose = pose;
           obj.parent = parent;
           obj.surfaces = mcodekit.list.dl_list();
        end
    end

    methods (Access = protected)

        function surface = add_surface(obj, geometry, color)
            surface = obj.add_surface_with_depth(geometry, color, 1);
        end

        function surface = add_surface_with_depth(obj, geometry, color, depth)
            surface_g = geometry;
            T = obj.pose.get_transformation_matrix();
            geometry_t = geometry*T';
            geometry_t(:,3) = depth;
            surface_h = patch('Parent', obj.parent, ...
                              'Vertices', geometry_t, ...
                              'Faces', 1:size(geometry,1), ...
                              'FaceColor', 'flat', ...
                              'FaceVertexCData', color);
            surface = simiam.ui.Surface2D(surface_h, surface_g);
            surface.set_surface_depth(depth);
            surface.transform_surface(T);
            obj.surfaces.append_key(surface);
        end

        function draw_surfaces(obj)
            T = obj.pose.get_transformation_matrix();

            token_k = obj.surfaces.head_;
            while(~isempty(token_k))
                token_k.key_.transform_surface(T);
                token_k = token_k.next_;
            end
        end

%         function transform_surfaces(obj, T)
%             i = obj.surfaces.get_iterator();
%             while(i.has_next())
%                 surface = i.next();
%                 surface.transform(T);
%             end
%         end

        function update_pose(obj, pose)
            [x, y, theta] = pose.unpack();
            obj.pose.set_pose([x, y, theta]);
%             obj.transform_surfaces(pose.get_transformation_matrix());
            obj.draw_surfaces();
        end

    end
end


% DEMSVARGPLVMGENERIC A generic demo for the MRD method.
%
% COPYRIGHT: Andreas C. Damianou, 2012
%
% SEEALO: MRDEmbed.m
%
% VARGPLVM

%------
% This is a generic demo for svargplvm. It only requires a cell-array
% Yall to be a priori created. Each cell should contain one dataset.
% This demo will use default options and configurations for the model.
% These can be changed by investigating the fields of globalOpt structure,
% which are set during 'svargplvm_init'.

%{
%eg:
clear
dataSetNames = 'toy'; toyDataCreate = 'fols'; svargplvmPrepareData
baseKern = {{'linard2','white'},{'linard2','white'}};
latentDimPerModel = 4;
init_X = 'separately';
initVardistIters = 200;
itNo = 200;
demSvargplvmGeneric
%}

% % Fix seeds
% randn('seed', 1e5);
% rand('seed', 1e5);

if ~exist('Yall', 'var')
    error('# This demo requires that a cell-array Yall is a priori created. This array should contain one dataset per cell.')
end
if ~exist('trainModel', 'var'), trainModel = true; end

M = length(Yall);

% This script initialises the options structure 'globalOpt'.
svargplvm_init;

% Don't use more inducing points than data
globalOpt.indPoints = min(globalOpt.indPoints, size(Yall{1},1));

%-- Load datasets
for i=1:M
    Y = Yall{i};
    dims{i} = size(Y,2);
    if i == 1
        Nall = size(Y,1);
    else
        if size(Y,1) ~= Nall
            error('The number of observations in each dataset must be the same!');
        end
    end
    indTr = globalOpt.indTr;
    if indTr == -1
        indTr = 1:Nall;
    end
    if ~exist('Yts')
        indTs = setdiff(1:size(Y,1), indTr);
        Yts{i} = Y(indTs,:);
    end
    Ytr{i} = Y(indTr,:);
end
clear('Y','Yall')

%--- Create model
if ~exist('options','var')
    options = svargplvmOptions(Ytr, globalOpt);
else
    warning('options field exists already!');
end

if ~isempty(globalOpt.dynamicsConstrainType)
    if exist('optionsDyn', 'var')
        warning('optionsDyn field exists already!');
    else
        if exist('timeStampsTraining', 'var')
            t = timeStampsTraining;
        else
            t = linspace(0, 2*pi, Nall+1)'; t = t(1:end-1, 1);
        end
        timeStampsTraining = t(indTr,1); %timeStampsTest = t(indTs,1);
        optionsDyn.type = 'vargpTime';
        optionsDyn.inverseWidth=30;
        optionsDyn.initX = globalOpt.initX;
        optionsDyn.constrainType = globalOpt.dynamicsConstrainType;
        if exist('timeStampsTraining', 'var')
            optionsDyn.t = timeStampsTraining;
        end
        if exist('labelsTrain', 'var') && ~isempty(labelsTrain)
            optionsDyn.labels = labelsTrain;
        end
    end
else
    optionsDyn= [];
end

model = svargplvmModelCreate(Ytr, globalOpt, options, optionsDyn);
if exist('diaryFile'), model.diaryFile = diaryFile; end

if ~isfield(globalOpt, 'saveName') || isempty(globalOpt.saveName)
    model.saveName = vargplvmWriteResult([], model.type, globalOpt.dataSetName, globalOpt.experimentNo, [], globalOpt.saveModelDir);
end
model.globalOpt = globalOpt;
model.options = options;

%-- Define what level of parallelism to use (w.r.t submodels or/and w.r.t
% datapoints).
%{
fprintf('# Parallel computations w.r.t the submodels!\n');
model.parallel = 1;
model = svargplvmPropagateField(model,'parallel', 1);
%
fprintf('# Parallel computations w.r.t the datapoints!\n');
model.vardist.parallel = 1;
for i=1:model.numModels
    model.comp{i}.vardist.parallel = 1;
end
%}

% Force kernel computations
params = svargplvmExtractParam(model);
model = svargplvmExpandParam(model, params);

if ~isempty(globalOpt.dynamicsConstrainType)
    fprintf('# Median of vardist. covars: %d \n',median(median(model.vardist.covars)));
    fprintf('# Min of vardist. covars: %d \n',min(min(model.vardist.covars)));
    fprintf('# Max of vardist. covars: %d \n',max(max(model.vardist.covars)));
end

%%

if trainModel
    model = svargplvmOptimiseModel(model);
    svargplvmShowScales(model)
end

return

%% PREDICTIONS

% obsMod = 1 means that the 1st modality is considered to be observed and
% the other modality is considered to be the unobserved one, during test
% time.
obsMod = 1; % one of the involved sub-models (the one for which we have the data)
infMod = setdiff(1:2, obsMod);

[sharedDims, privateDims] = svargplvmFindSharedDims(model);

% We can either use a totally new test set (a matrix Yts must be created
% where e.g. Yts{1} and Yts{2} are the two test modalities) or using the
% training set. In the later case, we solve the correspondance problem, ie
% for a given y we find the K most similar z's in the other modality (in
% the code, K = numberOfNN). See the Yale faces example.
fprintf('\n# PREDICTIONS: \n\n');
if ~exist('testOnTraining')
    testOnTraining=0;
end

numberOfNN = 5;

%--------------------%
svargplvmPredictions %---- Script returning: ZpredMuAll and mini(the indices for NN)
%--------------------%


% Select a region of interest for a given dataset at multiple resolution
% levels.
function imageDataset = selectROI(imageDataset, factors, ROI)

    for binningFactorIdx = 1:length(factors)

        s = factors(binningFactorIdx);

        if factors(binningFactorIdx) == 1
            % Extract the given ROI form the ground truth data.
            imageDataset.groundTruth = imageDataset.groundTruth(ROI(2):(ROI(2) + ROI(4) - 1), ROI(1):ROI(1) + ROI(3) - 1, :);
        else
            frames = imageDataset.(['Bin', num2str( factors(binningFactorIdx) )]);
            % Re-calculate ROI for the current binning factor.
            width = ceil(ROI(3) / s);
            hight = ceil(ROI(4) / s);
            x0 = ceil(ROI(1) / s);
            y0 = ceil(ROI(2) / s);
            imageDataset.(['Bin', num2str( factors(binningFactorIdx) )]) = frames(y0:(y0 + hight - 1), x0:(x0 + width - 1), :);
        end

    end


function [triggerLinesGood, triggerCounts, triggersList, fs] = sqdgettriggers(sqdfile, triggerLinesPotential, triggerHighThresh, triggerLowThresh)

%SQDGETTRIGGERS Detects trigger lines and triggers on those lines from an MEG sqd file.
%
%    [triggerLines, triggerCounts, triggersList, fs] = SQDGETTRIGGERS(sqdfile, triggerLinesPotential, triggerHighThresh, triggerLowThresh);
%
%    OUTPUT variables:
%    triggerLines: which lines were actually used as trigger lines
%    triggerCounts: how many triggers were detected on each trigger line
%    triggersList: a cell array (each cell corresponds to a
%       different trigger line) in which each cell is a list of the trigger
%       events. The trigger events are labeled by sample number not time. To
%       convert into time, divide the sample numbers by the sample
%       frequency.
%    fs: the sample frequency, in Hz.
%
%    INPUT variables:
%    sqdfile: the MEG file holding the trigger (and MEG) data
%    triggerLinesPotential: a list of which lines should be inspected for
%       triggers. The default is [160:191], i.e. all channels not containing
%       magnetic field data. This function is much more efficient, though, if
%       the triggerLinesPotential is the list of channels actually used as
%       trigger lines. Because of the way the sqd file is read, however, the
%       fastest method is to set triggerLinesPotential to be list of all
%       channels from the lowest used to the highest used.
%    triggerHighThresh (rarely needed): the threshold, in Volts, above
%       which a trigger line goes high. This value is nominally slightly
%       larger than 5 V, so the default value is 5 V.
%    triggerHighThresh (rarely needed): the threshold, in Volts, below
%       which a trigger line is considered to be low. This
%       value is nominally 0 V, so the default value is 0.2 V.

%
%    Version 0.9 beta 2
%    9 January 2010
%
%    by Jonathan Z. Simon

% Create triggerLinesPotential if not supplied or if equal to []. The
%    The default is all high channels, starting at 160, i.e. 160:191.
%    The numbering convention is that the first MEG channel is 0 (not 1).
if ~exist('triggerLinesPotential','var')
    triggerLinesPotential = [];
end
if isempty(triggerLinesPotential)
    triggerLinesPotential = 160:191;
end

% Create triggerHighThresh if not supplied or if equal to [].
if ~exist('triggerHighThresh','var')
    triggerHighThresh = [];
end
if isempty(triggerHighThresh)
    triggerHighThresh = 5; % mV
end

% Create triggerLowThresh if not supplied or if equal to [].
if ~exist('triggerLowThresh','var')
    triggerLowThresh = [];
end
if isempty(triggerLowThresh)
    triggerLowThresh = 0.2; % mV
end

triggerHighThresh_mV = triggerHighThresh*1000; % mV
triggerLowThresh_mV = triggerLowThresh*1000; % mV
clear triggerHighThresh triggerLowThresh

info = sqdread(sqdfile,'info');

fs = info.SampleRate; % Hz
triggerData = sqdread(sqdfile,'Channels',triggerLinesPotential);  % mV

% First find channels whose maximum is at least the "high" threshold and
% whose minimum is at most the "low" threshold.
triggerLinesTest = ( (max(triggerData) > triggerHighThresh_mV) & (min(triggerData) < triggerLowThresh_mV) );
triggerDataProbable = triggerData(:,triggerLinesTest);
triggerLinesProbable = triggerLinesPotential(triggerLinesTest);
clear triggerData

% (Not sure this is necessary.)
% Next, make sure that the time spent at rest is at least 100 times more
% than the time spent at the set value.
triggersNearHigh = mean(triggerDataProbable > triggerHighThresh_mV);
triggersNearLow = mean(triggerDataProbable < triggerLowThresh_mV);

triggerLinesHealthyHighRest =  (triggersNearHigh > 25 * triggersNearLow);
triggerDataHighRestGood = triggerDataProbable(:,triggerLinesHealthyHighRest);
triggerLinesHighRestGood = triggerLinesProbable(triggerLinesHealthyHighRest);
triggerLinesHighRestGoodCount = length(triggerLinesHighRestGood);

triggerLinesHealthyLowRest =  (triggersNearLow > 25 * triggersNearHigh);
triggerDataLowRestGood = triggerDataProbable(:,triggerLinesHealthyLowRest);
triggerLinesLowRestGood = triggerLinesProbable(triggerLinesHealthyLowRest);
triggerLinesLowRestGoodCount = length(triggerLinesLowRestGood);

if triggerLinesHighRestGoodCount > triggerLinesLowRestGoodCount
    triggerDataGood = triggerDataHighRestGood;
    triggerLinesGood = triggerLinesHighRestGood;
    triggerLinesGoodCount = triggerLinesHighRestGoodCount;
else
    triggerDataGood = triggerDataLowRestGood;
    triggerLinesGood = triggerLinesLowRestGood;
    triggerLinesGoodCount = triggerLinesLowRestGoodCount;
end

clear triggerDataProbable

% Inititialize outputs that hold trigger info
triggerCounts = nan(triggerLinesGoodCount,1);
triggersList = cell(triggerLinesGoodCount,1);

for iTrigger = 1:triggerLinesGoodCount
    if triggerLinesHighRestGoodCount > triggerLinesLowRestGoodCount
        triggerSet = find(triggerDataGood(:,iTrigger) < triggerLowThresh_mV);
    else
        triggerSet = find(triggerDataGood(:,iTrigger) > triggerHighThresh_mV);
    end
    % the next line uses find and diff to discard samples of triggerSet
    % that immediately follow any other values that cross
    % the "set" threshold.
    triggerSamples = (triggerSet([1; find(diff(triggerSet) > 1)+1]));
    triggerCounts(iTrigger) = length(triggerSamples);
    triggersList{iTrigger} = triggerSamples;
end

end


function varargout = symamd(X,variablesonly)
%SYMAMD (overloaded)

if nargin < 2
    variablesonly = 0;
end
 if isa(X,'blkvar')
    X = sdpvar(X);
 end

if variablesonly
    Z = X.basis(:,2:end);
else
    Z = X.basis;
end

Z = reshape(sum(abs(Z),2),X.dim(1),X.dim(2));
Z = Z~=0;
varargout{1}=symamd(Z);


function obj = updateSlice(obj, dataIndex)

    %-------------------------------------------------------------------------%

    %-INITIALIZATIONS-%

    axIndex = obj.getAxisIndex(obj.State.Plot(dataIndex).AssociatedAxis);
    plotData = get(obj.State.Plot(dataIndex).Handle);
    axisData = get(plotData.Parent);
    figureData = get(obj.State.Figure.Handle);
    [xSource, ~] = findSourceAxis(obj,axIndex);

    %-update scene-%
    updateScene(obj, dataIndex)

    %-get trace data-%
    xData = plotData.XData;
    yData = plotData.YData;
    zData = plotData.ZData;
    cData = plotData.CData;

    xDataSurf = zeros(2*(size(xData)-1));
    yDataSurf = zeros(2*(size(xData)-1));
    zDataSurf = zeros(2*(size(xData)-1));
    cDataSurf = zeros(2*(size(xData)-1));

    for n = 1:size(xData,2)-1
        n2 = 2*(n-1) + 1;

        for m = 1:size(xData,1)-1
            m2 = 2*(m-1) + 1;

            xDataSurf(m2:m2+1,n2:n2+1) = xData(m:m+1,n:n+1);
            yDataSurf(m2:m2+1,n2:n2+1) = yData(m:m+1,n:n+1);
            zDataSurf(m2:m2+1,n2:n2+1) = zData(m:m+1,n:n+1);

            if strcmp(plotData.FaceColor, 'flat')
                cDataSurf(m2:m2+1,n2:n2+1) = ones(2,2)*cData(m,n);
            elseif strcmp(plotData.FaceColor, 'interp')
                cDataSurf(m2:m2+1,n2:n2+1) = cData(m:m+1,n:n+1);
            end

        end
    end

    %-------------------------------------------------------------------------%

    %-set trace-%
    obj.data{dataIndex}.type = 'surface';
    obj.data{dataIndex}.name = plotData.DisplayName;
    obj.data{dataIndex}.visible = strcmp(plotData.Visible,'on');
    obj.data{dataIndex}.scene = sprintf('scene%d', xSource);
    obj.data{dataIndex}.showscale = false;
    obj.data{dataIndex}.surfacecolor = cDataSurf;

    %-------------------------------------------------------------------------%

    %-set trace data-%
    obj.data{dataIndex}.x = xDataSurf;
    obj.data{dataIndex}.y = yDataSurf;
    obj.data{dataIndex}.z = zDataSurf;

    %-------------------------------------------------------------------------%

    %-update face color-%
    updateSurfaceFaceColor(obj, dataIndex, cDataSurf);

    %-update edge color-%
    if isnumeric(plotData.EdgeColor)
        updateSurfaceEdgeColor(obj, dataIndex);
    end

    %-------------------------------------------------------------------------%
end

function updateScene(obj, dataIndex)

    %-------------------------------------------------------------------------%

    %-INITIALIZATIONS-%
    axIndex = obj.getAxisIndex(obj.State.Plot(dataIndex).AssociatedAxis);
    plotData = get(obj.State.Plot(dataIndex).Handle);
    axisData = get(plotData.Parent);
    [xSource, ~] = findSourceAxis(obj, axIndex);
    scene = eval( sprintf('obj.layout.scene%d', xSource) );

    aspectRatio = axisData.PlotBoxAspectRatio;
    cameraPosition = axisData.CameraPosition;
    dataAspectRatio = axisData.DataAspectRatio;
    cameraUpVector = axisData.CameraUpVector;
    cameraEye = cameraPosition./dataAspectRatio;
    normFac = 0.625*abs(min(cameraEye));

    %-------------------------------------------------------------------------%

    %-aspect ratio-%
    scene.aspectratio.x = 1.15*aspectRatio(1);
    scene.aspectratio.y = 1.0*aspectRatio(2);
    scene.aspectratio.z = 0.9*aspectRatio(3);

    %-camera eye-%
    scene.camera.eye.x = cameraEye(1) / normFac;
    scene.camera.eye.y = cameraEye(2) / normFac;
    scene.camera.eye.z = cameraEye(3) / normFac;

    %-camera up-%
    scene.camera.up.x = cameraUpVector(1);
    scene.camera.up.y = cameraUpVector(2);
    scene.camera.up.z = cameraUpVector(3);

    %-camera projection-%
    % scene.camera.projection.type = axisData.Projection;

    %-------------------------------------------------------------------------%

    %-scene axis configuration-%
    scene.xaxis.range = axisData.XLim;
    scene.yaxis.range = axisData.YLim;
    scene.zaxis.range = axisData.ZLim;

    scene.xaxis.zeroline = false;
    scene.yaxis.zeroline = false;
    scene.zaxis.zeroline = false;

    scene.xaxis.showline = true;
    scene.yaxis.showline = true;
    scene.zaxis.showline = true;

    scene.xaxis.ticklabelposition = 'outside';
    scene.yaxis.ticklabelposition = 'outside';
    scene.zaxis.ticklabelposition = 'outside';

    scene.xaxis.title = axisData.XLabel.String;
    scene.yaxis.title = axisData.YLabel.String;
    scene.zaxis.title = axisData.ZLabel.String;

    %-tick labels-%
    scene.xaxis.tickvals = axisData.XTick;
    scene.xaxis.ticktext = axisData.XTickLabel;
    scene.yaxis.tickvals = axisData.YTick;
    scene.yaxis.ticktext = axisData.YTickLabel;
    scene.zaxis.tickvals = axisData.ZTick;
    scene.zaxis.ticktext = axisData.ZTickLabel;

    scene.xaxis.tickcolor = 'rgba(0,0,0,1)';
    scene.yaxis.tickcolor = 'rgba(0,0,0,1)';
    scene.zaxis.tickcolor = 'rgba(0,0,0,1)';
    scene.xaxis.tickfont.size = axisData.FontSize;
    scene.yaxis.tickfont.size = axisData.FontSize;
    scene.zaxis.tickfont.size = axisData.FontSize;
    scene.xaxis.tickfont.family = matlab2plotlyfont(axisData.FontName);
    scene.yaxis.tickfont.family = matlab2plotlyfont(axisData.FontName);
    scene.zaxis.tickfont.family = matlab2plotlyfont(axisData.FontName);

    %-grid-%
    if strcmp(axisData.XGrid, 'off'), scene.xaxis.showgrid = false; end
    if strcmp(axisData.YGrid, 'off'), scene.yaxis.showgrid = false; end
    if strcmp(axisData.ZGrid, 'off'), scene.zaxis.showgrid = false; end

    %-------------------------------------------------------------------------%

    %-SET SCENE TO LAYOUT-%
    obj.layout = setfield(obj.layout, sprintf('scene%d', xSource), scene);

    %-------------------------------------------------------------------------%
end

function updateSurfaceEdgeColor(obj, dataIndex)

    %-------------------------------------------------------------------------%

    %-INITIALIZATIONS-%

    axIndex = obj.getAxisIndex(obj.State.Plot(dataIndex).AssociatedAxis);
    plotData = get(obj.State.Plot(dataIndex).Handle);
    axisData = get(plotData.Parent);

    xData = plotData.XData;
    yData = plotData.YData;
    zData = plotData.ZData;
    cData = plotData.CData;
    edgeColor = plotData.EdgeColor;
    cData = plotData.CData;
    cLim = axisData.CLim;
    colorMap = axisData.Colormap;

    xConst = ( xData(:) - min(xData(:)) ) <= 1e-6;
    yConst = ( yData(:) - min(yData(:)) ) <= 1e-6;

    %-------------------------------------------------------------------------%

    %-edge lines in x direction-%
    xContourSize = mean(diff(xData(1,:)));
    xContourStard = min(xData(1,:));
    xContourEnd = max(xData(1,:));

    obj.data{dataIndex}.contours.x.show = true;
    obj.data{dataIndex}.contours.x.start = xContourStard;
    obj.data{dataIndex}.contours.x.end = xContourEnd;
    obj.data{dataIndex}.contours.x.size = xContourSize;

    %-edge lines in y direction-%
    yContourSize = mean(diff(yData(:,1)));
    yContourStard = min(yData(:,1));
    yContourEnd = max(yData(:,1));

    obj.data{dataIndex}.contours.y.show = true;
    obj.data{dataIndex}.contours.y.start = yContourStard;
    obj.data{dataIndex}.contours.y.end = yContourEnd;
    obj.data{dataIndex}.contours.y.size = yContourSize;

    %-edge lines in z direction-%

    if all(xConst) || all(yConst)
        zContourSize = mean(diff(zData(1,:)));
        zContourStard = min(zData(1,:));
        zContourEnd = max(zData(1,:));

        obj.data{dataIndex}.contours.z.show = true;
        obj.data{dataIndex}.contours.z.start = zContourStard;
        obj.data{dataIndex}.contours.z.end = zContourEnd;
        obj.data{dataIndex}.contours.z.size = zContourSize;
    end

    %-------------------------------------------------------------------------%

    %-coloring-%
    numColor = 255 * edgeColor;
    stringColor = getStringColor(numColor);

    obj.data{dataIndex}.contours.x.color = stringColor;
    obj.data{dataIndex}.contours.y.color = stringColor;
    obj.data{dataIndex}.contours.z.color = stringColor;

    %-------------------------------------------------------------------------%
end

function updateSurfaceFaceColor(obj, dataIndex, surfaceColor)

    %-------------------------------------------------------------------------%

    %-INITIALIZATIONS-%

    axIndex = obj.getAxisIndex(obj.State.Plot(dataIndex).AssociatedAxis);
    plotData = get(obj.State.Plot(dataIndex).Handle);
    axisData = get(plotData.Parent);

    faceColor = plotData.FaceColor;
    cLim = axisData.CLim;
    colorMap = axisData.Colormap;

    obj.data{dataIndex}.cauto = false;
    obj.data{dataIndex}.autocolorscale = false;

    %-------------------------------------------------------------------------%

    if isnumeric(faceColor)
        numColor = 255 * faceColor;
        stringColor = getStringColor(numColor);

        colorScale{1} = {0, stringColor};
        colorScale{2} = {1, stringColor};
        obj.data{dataIndex}.colorscale = colorScale;

    elseif ismember(faceColor, {'flat', 'interp'})

        nColors = size(colorMap, 1);

        for c = 1:nColors
            stringColor = getStringColor(255*colorMap(c,:));
            colorScale{c} = {(c-1)/(nColors-1), stringColor};
        end

        obj.data{dataIndex}.cmin = cLim(1);
        obj.data{dataIndex}.cmax = cLim(2);

    end

    obj.data{dataIndex}.surfacecolor = surfaceColor;
    obj.data{dataIndex}.colorscale = colorScale;

    %-------------------------------------------------------------------------%
end

function stringColor = getStringColor(numColor)

    stringColor = sprintf('rgb(%f,%f,%f)', numColor);
end


classdef PTKAirwayRadiusApproximation < PTKPlugin
    % PTKAirwayRadiusApproximation. Plugin to approximate radius of branches in
    %     the airway tree
    %
    %     This is a plugin for the Pulmonary Toolkit. Plugins can be run using
    %     the gui, or through the interfaces provided by the Pulmonary Toolkit.
    %     See PTKPlugin.m for more information on how to run plugins.
    %
    %     Plugins should not be run directly from your code.
    %
    %     PTKAirwayRadiusApproximation uses a distance transform to estimate the
    %     radius of each branch in the airway tree. The results are shown as an
    %     output image.
    %
    %
    %     Licence
    %     -------
    %     Part of the TD Pulmonary Toolkit. https://github.com/tomdoel/pulmonarytoolkit
    %     Author: Tom Doel, 2012.  www.tomdoel.com
    %     Distributed under the GNU GPL v3 licence. Please see website for details.
    %

    properties
        ButtonText = 'Airway radius <BR>approximation'
        ToolTip = 'Shows airways coloured by their radius approximation'
        Category = 'Airways'

        AllowResultsToBeCached = true
        AlwaysRunPlugin = false
        PluginType = 'ReplaceOverlay'
        HidePluginInDisplay = false
        FlattenPreviewImage = true
        PTKVersion = '1'
        ButtonWidth = 6
        ButtonHeight = 2
        GeneratePreview = true
        Visibility = 'Developer'
    end

    methods (Static)
        function results = RunPlugin(dataset, reporting)
            results = dataset.GetTemplateImage(PTKContext.LungROI);
            airway_results = dataset.GetResult('PTKAirways');
            results = PTKAirwayRadiusApproximation.GetRadiusApproximationFromAirwayTree(airway_results.AirwayTree, results, reporting);
        end
    end

    methods (Static, Access = private)

        function results = GetRadiusApproximationFromAirwayTree(airway_tree, template, reporting)
            airway_segmented_image = PTKGetImageFromAirwayResults(airway_tree, template, false, reporting);
            dt_image = airway_segmented_image.RawImage;
            dt_image = dt_image == 0;
            dt_image = bwdist(dt_image);

            segments_to_do = airway_tree;
            min_voxel_size_mm = min(airway_segmented_image.VoxelSize);

            segmented_image = zeros(template.ImageSize, 'single');

            while ~isempty(segments_to_do)
                segment = segments_to_do(end);
                segments_to_do(end) = [];
                airway_points_local = template.GlobalToLocalIndices(segment.GetAllAirwayPoints);
                max_radius = max(dt_image(airway_points_local))*min_voxel_size_mm;
                segmented_image(airway_points_local) = max_radius;
                segments_to_do = [segments_to_do segment.Children];
            end

            results = airway_segmented_image.BlankCopy;
            results.ChangeRawImage(segmented_image);
            results.ImageType = PTKImageType.Scaled;
        end
    end
end


function mesh = prepare_mesh_tetrahedral(cfg, mri)

% PREPARE_MESH_TETRAHEDRAL
%
% See also PREPARE_MESH_MANUAL, PREPARE_MESH_HEADSHAPE,
% PREPARE_MESH_HEXAHEDRAL, PREPARE_MESH_SEGMENTATION

% Copyrights (C) 2016, Robert Oostenveld
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% for the documentation and details.
%
%    FieldTrip is free software: you can redistribute it and/or modify
%    it under the terms of the GNU General Public License as published by
%    the Free Software Foundation, either version 3 of the License, or
%    (at your option) any later version.
%
%    FieldTrip is distributed in the hope that it will be useful,
%    but WITHOUT ANY WARRANTY; without even the implied warranty of
%    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%    GNU General Public License for more details.
%
%    You should have received a copy of the GNU General Public License
%    along with FieldTrip. If not, see <http://www.gnu.org/licenses/>.
%
% $Id$

% ensure that the input is consistent with what this function expects
mri = ft_checkdata(mri, 'datatype', {'volume', 'segmentation'}, 'hasunit', 'yes');

% get the default options
cfg.tissue = ft_getopt(cfg, 'tissue');

if isempty(cfg.tissue)
  mri = ft_datatype_segmentation(mri, 'segmentationstyle', 'indexed');
  fn = fieldnames(mri);
  for i = 1:numel(fn)
    if (numel(mri.(fn{i})) == prod(mri.dim)) && (~strcmp(fn{i}, 'inside'))
      segfield = fn{i};
    end
  end
  cfg.tissue = setdiff(unique(mri.(segfield)(:)), 0);
end

if ischar(cfg.tissue)
  % it should either be something like {'brain', 'skull', 'scalp'}, or something like [1 2 3]
  cfg.tissue = {cfg.tissue};
end

if iscell(cfg.tissue)
  % the code below assumes that it is a probabilistic representation
  if any(strcmp(cfg.tissue, 'brain'))
    mri = ft_datatype_segmentation(mri, 'segmentationstyle', 'probabilistic', 'hasbrain', 'yes');
  else
    mri = ft_datatype_segmentation(mri, 'segmentationstyle', 'probabilistic');
  end
  % combine all tissue types
  seg = false(mri.dim);
  for i=1:numel(cfg.tissue)
    seg = seg | mri.(cfg.tissue{i});
  end
else
  % the code below assumes that it is an indexed representation
  mri = ft_datatype_segmentation(mri, 'segmentationstyle', 'indexed');
  % combine all tissue types
  seg = (mri.seg>0);
end

% this requires the external iso2mesh toolbox
ft_hastoolbox('iso2mesh', 1);

[node, elem, face] = vol2mesh(seg, 1:mri.dim(1), 1:mri.dim(2), 1:mri.dim(3), 2, 2, 0,'cgalsurf');

mesh = keepfields(mri, {'coordsys', 'unit'});
mesh.pos = ft_warp_apply(mri.transform, node);
mesh.tet = elem(:,1:4);


function [err, commonSize, numElements] = statsizechk(nparams,varargin)
%STATSIZECHK Check for compatible array sizes.
%   [ERR,COMMONSIZE,NUMELEMENTS] = STATSIZECHK(NPARAMS,A,B,...,M,N,...) or
%   [ERR,COMMONSIZE,NUMELEMENTS] = STATSIZECHK(NPARAMS,A,B,...,[M,N,...])
%   in effect computes size( A + B + ... + zeros(M,N,...) ), and catches
%   any size mismatches.  NPARAMS is the number of array input arguments.

%   Copyright 1993-2004 The MathWorks, Inc.
%   $Revision: 1.1.6.2 $  $Date: 2004/01/24 09:36:35 $
%
%   Mex file.

% try
%     tmp = 0;
%     for argnum = 1:nparams
%         tmp = tmp + varargin{argnum};
%     end
%     if nargin > nparams+1
%         tmp = tmp + zeros(varargin{nparams+1:end});
%     end
%     err = 0;
%     commonSize = size(tmp);
%     numElements = numel(tmp);
%
% catch
%     err = 1;
%     commonSize = [];
%     numElements = 0;
% end


function plot_att(matlab_time,matlab_att, mcu_time,mcu_att, sins_time,sins_att, bl_time,bl_att)
%姿态与航向估计曲线
    for i=2:2:nargin
        if i==2
%             matlab_time = matlab_time/60;
            figure('name', '姿态与航向估计曲线');
            subplot(3,1,1);
            plot(matlab_time, matlab_att(:,1), 'b', 'linewidth', 1.5); hold on; grid on;
            xlim([matlab_time(1) matlab_time(end)]);
            ylim([-20 20]);
            ylabel('Pitch(°)'); legend('MATLAB', 'Orientation','horizontal');
            subplot(3,1,2);
            plot(matlab_time, matlab_att(:,2), 'b', 'linewidth', 1.5); hold on; grid on;
            xlim([matlab_time(1) matlab_time(end)]);
            ylim([-20 20]);
            ylabel('Roll(°)'); legend('MATLAB', 'Orientation','horizontal');
            subplot(3,1,3);
            plot(matlab_time, matlab_att(:,3), 'b', 'linewidth', 1.5); hold on; grid on;
            legend('MATLAB', 'Orientation','horizontal');
            xlim([matlab_time(1) matlab_time(end)]);
            ylim([-30 420]);
            yticks(0:45:360);
            xlabel('时间(s)'); ylabel('Yaw(°)');
        elseif i==4
%             mcu_time = mcu_time/60;
            subplot(3,1,1);
            plot(mcu_time, mcu_att(:,1), 'm', 'linewidth', 1.5);
            legend('MATLAB', 'MCU', 'Orientation','horizontal');
            subplot(3,1,2);
            plot(mcu_time, mcu_att(:,2), 'm', 'linewidth', 1.5);
            legend('MATLAB', 'MCU', 'Orientation','horizontal');
            subplot(3,1,3);
            plot(mcu_time, mcu_att(:,3), 'm', 'linewidth', 1.5);
            legend('MATLAB', 'MCU', 'Orientation','horizontal');
        elseif i==6
%             sins_time = sins_time/60;
            subplot(3,1,1);
            plot(sins_time, sins_att(:,1), 'r', 'linewidth', 1.5);
            legend('MATLAB', 'MCU', '纯惯性', 'Orientation','horizontal');
            subplot(3,1,2);
            plot(sins_time, sins_att(:,2), 'r', 'linewidth', 1.5);
            legend('MATLAB', 'MCU', '纯惯性', 'Orientation','horizontal');
            subplot(3,1,3);
            plot(sins_time, sins_att(:,3), 'r', 'linewidth', 1.5);
            legend('MATLAB', 'MCU', '纯惯性', 'Orientation','horizontal');
        elseif i==8
%             bl_time = bl_time/60;
            subplot(3,1,1);
            plot(bl_time, bl_att(:,1), 'g', 'linewidth', 1.5);
            legend('MATLAB', 'MCU', '纯惯性', '双天线','Orientation','horizontal');
            subplot(3,1,3);
            plot(bl_time, bl_att(:,2), 'g', 'linewidth', 1.5);
            legend('MATLAB', 'MCU', '纯惯性', '双天线','Orientation','horizontal');
        end
    end

    sgtitle('姿态与航向估计曲线');
    set(gcf, 'Units', 'normalized', 'Position', [0.025, 0.05, 0.95, 0.85]);
end


function colornames_view(palette,order)
% View the COLORNAMES palettes in an interactive figure. Sort colors by name/color space.
%
% (c) 2014-2019 Stephen Cobeldick
%
%%% Syntax:
%  colornames_view
%  colornames_view(palette)
%  colornames_view(palette,sortorder)
%
% Create a figure displaying all of the colors from any palette supported
% by the function COLORNAMES. The palette and sort order can be selected
% by drop-down menu or by optional inputs. The colors can be sorted:
% - alphabetically by color name.
% - by color space parameters: Lab, LCh, XYZ, YUV, HSV, or RGB.
%
% The figure is resizeable (the colors flow to fit the axes) with a vertical
% scrollbar provided to view all of the colors (if required). A rudimentary
% zoom ability has also been implemented... but this is rather experimental!
%
% Note: Requires the function COLORNAMES and its associated MAT file (FEX 48155).
%
%% Input and Output Arguments %%
%
%%% Inputs (all inputs are optional):
%  palette   = CharRowVector, the name of a palette supported by COLORNAMES.
%  sortorder = CharRowVector, the color space sort parameters in the desired order,
%              eg: 'RGB', 'BRG', 'GRB', 'Lab', 'abL', etc, OR 'Alphabetical'.
%
%%% Outputs:
% none
%
% See also COLORNAMES COLORNAMES_CUBE COLORNAMES_DELTAE MAXDISTCOLOR COLORMAP

%% Figure Parameters %%
%
persistent fgh axh slh pah srh txh txs rgb coh prv
%
% Text lightness threshold:
thr = 0.54;
%
% Text margin, uicontrol and axes gap (pixels):
mrg = 5;
gap = 4;
sid = 20;
%
% Slider position:
yid = 0;
ymx = 0;
%
% Handle of outlined text:
prv = [];
%
pmt = 'Click on a colorname...';
%
%% Get COLORNAME Palettes %%
%
[fnm,csf] = colornames();
%
if nargin<1
	pnm = fnm{1+rem(round(now*1e7),numel(fnm))};
else
	assert(ischar(palette)&&isrow(palette),'First input <palette> must be a 1xN char.')
	idz = strcmpi(palette,fnm);
	assert(any(idz),'Palette ''%s'' is not supported. Call COLORNAMES() to list all palettes.',palette)
	pnm = fnm{idz};
end
%
%% Color Sorting List %%
%
% List of color spaces for sorting:
lst = {'Alphabetical','Lab','XYZ','LCh','YUV','HSV','RGB'};
[tsl,idt] = cellfun(@sort,lst,'UniformOutput',false);
% Get every permutation of the color spaces:
trs = cellfun(@(s)perms(s(end:-1:1)),lst(2:end),'UniformOutput',false);
trs = [lst(1);cellstr(vertcat(trs{:}))];
%
if nargin<2
	srt = lst{1};
else
	assert(ischar(order)&&isrow(order),'Second input <sort> must be a 1xN char.')
	idz = strcmpi(order,trs);
	assert(any(idz),'Second input must be one of:%s\b.',sprintf(' %s,',trs{:}))
	srt = trs{idz};
end
%
% Intial color sorting index:
idx = 1:numel(colornames(pnm));
%
%% Create a New Figure %%
%
if isempty(fgh)||~ishghandle(fgh)
	% Figure with zoom and pan functions:
	fgh = figure('HandleVisibility','callback', 'IntegerHandle','off',...
		'NumberTitle','off', 'Name','ColorNames View', 'Color','white',...
		'Toolbar','figure', 'Units','pixels', 'Tag',mfilename, 'Visible','on');
	%
	fgp = get(fgh,'Position');
	inh = uicontrol(fgh, 'Units','pixels', 'Style','text', 'HitTest','off',...
		'Visible','on',	'String','Initializing the figure... please wait.');
	inx = get(inh,'Extent');
	set(inh,'Position',[fgp(3:4)/2-inx(3:4)/2,inx(3:4)])
	%
	% Axes and scrolling slider:
	slh = uicontrol('Parent',fgh, 'Style','slider', 'Visible','off',...
		'Enable','on', 'Value',1, 'Min',0, 'Max',1,...
		'FontUnits','pixels', 'Units','pixels', 'Callback',@cnvSldClBk);
	axh = axes('Parent',fgh, 'Visible','off', 'Units','pixels',...
		'YDir','reverse', 'XTick',[], 'YTick',[], 'XLim',[0,1], 'YLim',[0,1]);
	% Palette and color sorting method drop-down menus:
	pah = uicontrol('Parent',fgh, 'Style','popupmenu', 'String',fnm,...
		'ToolTip','Color Scheme', 'Units','pixels',...
		'Visible','off', 'Callback',@cnvPalClBk);
	srh = uicontrol('Parent',fgh, 'Style','popupmenu', 'String',trs,...
		'ToolTip','Sort Colors', 'Units','pixels',...
		'Visible','off', 'Callback',@cnvSrtClBk);
	coh = uicontrol('Parent',fgh, 'Style','edit', 'String',pmt,...
		'ToolTip','RGB Value',   'Units', 'pixels', 'Visible','off',...
		'HorizontalAlignment','left', 'Enable','inactive');
else
	set(coh,'String',pmt)
end
set(pah,'Value',find(strcmpi(pnm,fnm)));
set(srh,'Value',find(strcmpi(srt,trs)));
%
fgo = get(fgh, 'Pointer');
set(fgh, 'Pointer','watch')
drawnow()
%
%% Callback Functions %%
%
	function cnvPalClBk(h,~) % Palette Menu CallBack
		% Select a new palette.
		pnm = fnm{get(h,'Value')};
		set(slh, 'Value',1)
		set(coh, 'String',pmt)
		set(fgh, 'Pointer','watch')
		drawnow()
		cnvTxtDraw()
		cnvSortBy()
		cnvResize()
		set(fgh, 'Pointer',fgo)
	end
%
	function cnvSrtClBk(h,~) % Sort-Order Menu CallBack
		% Select the color sorting method.
		srt = trs{get(h,'Value')};
		set(fgh, 'Pointer','watch')
		drawnow()
		cnvSortBy()
		cnvResize()
		set(fgh, 'Pointer',fgo)
	end
%
	function cnvSldClBk(h,~) % Slider CallBack
		% Scroll the axes by changing the axes limits.
		tmp = diff(get(axh,'Ylim'));
		set(axh, 'Ylim',[0,tmp] + (ymx-tmp)*(1-get(h,'Value')));
	end
%
	function cnvZoomClBk(~,~) % Zoom CallBack
		% Change the font and margin sizes.
		tmp = diff(get(axh,'Ylim'));
		set(txh, 'FontSize',txs/tmp);
		set(txh, 'Margin',mrg/tmp);
	end
%
	function cnvPanClBk(~,~) % Pan CallBack
		% Move the scroll-bar to match panning of the axes.
		tmp = get(axh,'Ylim');
		set(slh, 'Value',max(0,min(1,1-tmp(1)/(ymx-diff(tmp)))))
	end
%
%% Color Sorting %%
%
	function cnvSortBy()
		[tmp,ids] = sort(srt);
		idc = strcmp(tmp,tsl);
		ids = ids(idt{idc});
		switch lst{idc}
			case 'Alphabetical'
				idx = 1:numel(txh);
				return
			case 'RGB'
				mat = rgb;
			case 'HSV'
				mat = csf.rgb2hsv(rgb);
			case 'XYZ'
				mat = csf.rgb2xyz(rgb);
			case 'Lab'
				mat = csf.xyz2lab(csf.rgb2xyz(rgb));
			case 'LCh'
				mat = csf.lab2lch(csf.xyz2lab(csf.rgb2xyz(rgb)));
			case 'YUV' % BT.709
				mat = csf.invgamma(rgb) * [...
					+0.2126, -0.19991, +0.61500;...
					+0.7152, -0.33609, -0.55861;...
					+0.0722, +0.43600, -0.05639];
			otherwise
				error('Colorspace "%s" is not supported. How did this happen?',srt)
		end
		[~,idx] = sortrows(mat,ids);
	end
%
%% Re/Draw Text Strings %%
%
txf = @(s,b,c)text('Parent',axh, 'String',s, 'BackgroundColor',b,...
	'Color',c,'Margin',mrg, 'Units','data', 'Interpreter','none',...
	'VerticalAlignment','bottom', 'HorizontalAlignment','right',...
	'Clipping','on', 'ButtonDownFcn',{@txtClBk,s,b},'LineWidth',3);
%
	function txtClBk(hnd,~,s,bgd)
		try %#ok<TRYNC>
			set(prv, 'EdgeColor','none')
		end % setting one object is much faster than setting all objects.
		prv = hnd;
		%
		hxs = sprintf('%02X',round(bgd*255));
		dcs = sprintf(',%.5f',bgd);
		set(coh, 'String',sprintf('#%s [%s] %s',hxs,dcs(2:end),s));
		set(hnd, 'EdgeColor',max(0,min(1,1-bgd)))
		uistack(hnd,'top')
	end
%
	function cnvTxtDraw()
		% Delete any existing colors:
		delete(txh(ishghandle(txh)))
		% Get new colors:
		[cnc,rgb] = colornames(pnm);
		% Calculate the text color:
		baw = (rgb*[0.298936;0.587043;0.114021])<thr;
		% Draw new colors in the axes:
		txh = cellfun(txf,cnc,num2cell(rgb,2),num2cell(baw(:,[1,1,1]),2),'Uni',0);
		txh = reshape([txh{:}],[],1);
		txs = get(txh(1),'FontSize');
		prv = txh(1);
	end
%
%% Resize the Axes and UIControls, Move the Colors %%
%
	function cnvResize(~,~)
		%
		zoom(fgh,'out')
		%
		if nargin
			set(fgh, 'Pointer','watch')
			drawnow()
		end
		%
		ecv = get(prv, 'EdgeColor');
		set(prv, 'EdgeColor','none');
		%
		set(axh, 'Ylim',[0,1])
		set(txh, 'Units','pixels', 'FontSize',txs, 'Margin',mrg)
		txe = cell2mat(get(txh(:),'Extent'));
		top = get(slh,'FontSize')*2;
		fgp = get(fgh,'Position'); % [left bottom width height]
		hgt = round(fgp(4)-3*gap-top);
		wid = fgp(3)-3*gap-sid;
		pos = [gap,gap,wid,hgt];
		%
		% Calculate color lengths from text and margins:
		txw = 2*mrg+txe(idx,3);
		txc = cumsum(txw);
		% Preallocate position array:
		txm = mean(txw);
		out = zeros(ceil(1.1*[txc(end)/pos(3),pos(3)/txm]));
		% Split colors into lines that fit the axes width:
		idb = 1;
		idr = 0;
		tmp = 0;
		while idb<=numel(txc)
			idr = idr+1;
			idp = max([idb,find((txc-tmp)<=pos(3),1,'last')]);
			out(idr,1:1+idp-idb) = txc(idb:idp)-tmp;
			tmp = txc(idp);
			idb = idp+1;
		end
		% Calculate X and Y positions for each color:
		[~,txy,txx] = find(out.');
		yid = txy(end);
		txy = txy*(2*mrg+max(txe(idx,4)));
		ymx = txy(end)/pos(4);
		%
		% Resize the scrollbar, adjust scroll steps:
		nwp = [2*gap+wid,gap,sid,hgt];
		if ymx>1
			set(slh, 'Position',nwp, 'Enable','on', 'Value',1,...
				'SliderStep',max(0,min(1,[0.5,2]/(yid*(ymx-1)/ymx))))
		else
			set(slh, 'Position',nwp, 'Enable','off')
		end
		% Resize the axes and drop-down menus:
		set(axh, 'Position',pos)
		uiw = (fgp(3)-gap)/4-gap;
		txw = 2*uiw+gap;
		lhs = gap+(0:2)*(uiw+gap);
		bot = fgp(4)-top-gap;
		set(pah, 'Position',[lhs(1),bot,uiw,top])
		set(srh, 'Position',[lhs(2),bot,uiw,top])
		set(coh, 'Position',[lhs(3),bot,txw,top])
		% Move text strings to the correct positions:
		arrayfun(@(h,x,y)set(h,'Position',[x,y]),txh(idx),txx-mrg,pos(4)-txy+mrg);
		set(txh, 'Units','data')
		%
		set(prv, 'EdgeColor',ecv);
		%
		if nargin
			set(fgh, 'Pointer',fgo)
		end
		drawnow()
	end
%
%% Initialize the Figure %%
%
cnvTxtDraw()
cnvSortBy()
cnvResize()
set([pah,srh,coh,slh], 'Visible','on')
set(fgh, 'Pointer',fgo, 'ResizeFcn',@cnvResize)
set(zoom(fgh), 'ActionPostCallback',@cnvZoomClBk);
set(pan(fgh),  'ActionPostCallback',@cnvPanClBk);
try %#ok<TRYNC>
	delete(inh)
end
%
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%colornames_view


% This file is part of TREEQSM.
%
% TREEQSM is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% TREEQSM is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with TREEQSM.  If not, see <http://www.gnu.org/licenses/>.

function pmdistance = point_model_distance(P,cylinder)

% ---------------------------------------------------------------------
% POINT_MODEL_DISTANCE.M    Computes the distances of the points to the
%                               cylinder model
%
% Version 2.1.1
% Latest update     8 Oct 2021
%
% Copyright (C) 2015-2021 Pasi Raumonen
% ---------------------------------------------------------------------

% Changes from version 2.1.0 to 2.1.1, 8 Oct 2021:
% 1) Changed the determinationa NE, the number of empty edge layers, so
%     that is now limited in size, before it is given as input for
%     cubical_partition function.

% Changes from version 2.0.0 to 2.1.0, 26 Nov 2019:
% 1) Bug fix: Corrected the computation of the output at the end of the
%    code so that trees without branches are computed correctly.

% Cylinder data
Rad = cylinder.radius;
Len = cylinder.length;
Sta = cylinder.start;
Axe = cylinder.axis;
BOrd = cylinder.BranchOrder;

% Select randomly 25 % or max one million points for the distance comput.
np0 = size(P,1);
a = min(0.25*np0,1000000);
I = logical(round(0.5/(1-a/np0)*rand(np0,1)));
P = P(I,:);

% Partition the points into cubes
L = 2*median(Len);
NE = max(3,min(10,ceil(max(Len)/L)))+3;
[Partition,~,Info] = cubical_partition(P,L,NE);
Min = Info(1:3);
EL = Info(7);
NE = Info(8);

% Calculates the cube-coordinates of the starting points
CC = floor([Sta(:,1)-Min(1) Sta(:,2)-Min(2) Sta(:,3)-Min(3)]/EL)+NE+1;

% Compute the number of cubes needed for each starting point
N = ceil(Len/L);

% Correct N so that cube indexes are not too small or large
I = CC(:,1) < N+1;
N(I) = CC(I,1)-1;
I = CC(:,2) < N+1;
N(I) = CC(I,2)-1;
I = CC(:,3) < N+1;
N(I) = CC(I,3)-1;
I = CC(:,1)+N+1 > Info(4);
N(I) = Info(4)-CC(I,1)-1;
I = CC(:,2)+N+1 > Info(5);
N(I) = Info(5)-CC(I,2)-1;
I = CC(:,3)+N+1 > Info(6);
N(I) = Info(6)-CC(I,3)-1;

% Calculate the distances to the cylinders
n = size(Rad,1);
np = size(P,1);
Dist = zeros(np,2); % Distance and the closest cylinder of each points
Dist(:,1) = 2; % Large distance initially
Points = zeros(ceil(np/10),1,'int32'); % Auxiliary variable
Data = cell(n,1);
for i = 1:n
  Par = Partition(CC(i,1)-N(i):CC(i,1)+N(i),CC(i,2)-N(i):CC(i,2)+N(i),...
    CC(i,3)-N(i):CC(i,3)+N(i));
  if N(i) > 1
    S = cellfun('length',Par);
    I = S > 0;
    S = S(I);
    Par = Par(I);
    stop = cumsum(S);
    start = [0; stop]+1;
    for k = 1:length(stop)
      Points(start(k):stop(k)) = Par{k}(:);
    end
    points = Points(1:stop(k));
  else
    points = vertcat(Par{:});
  end
  [d,~,h] = distances_to_line(P(points,:),Axe(i,:),Sta(i,:));
  d = abs(d-Rad(i));
  Data{i} = [d h double(points)];
  I = d < Dist(points,1);
  J = h >= 0;
  K = h <= Len(i);
  L = d < 0.5;
  M = I&J&K&L;
  points = points(M);
  Dist(points,1) = d(M);
  Dist(points,2) = i;
end

% Calculate the distances to the cylinders for points not yet calculated
% because they are not "on side of cylinder
for i = 1:n
  if ~isempty(Data{i})
    d = Data{i}(:,1);
    h = Data{i}(:,2);
    points = Data{i}(:,3);
    I = d < Dist(points,1);
    J = h >= -0.1 & h <= 0;
    K = h <= Len(i)+0.1 & h >= Len(i);
    L = d < 0.5;
    M = I&(J|K)&L;
    points = points(M);
    Dist(points,1) = d(M);
    Dist(points,2) = i;
  end
end

% Select only the shortest 95% of distances for each cylinder
N = zeros(n,1);
O = zeros(np,1);
for i = 1:np
  if Dist(i,2) > 0
    N(Dist(i,2)) = N(Dist(i,2))+1;
    O(i) = N(Dist(i,2));
  end
end
Cyl = cell(n,1);
for i = 1:n
  Cyl{i} = zeros(N(i),1);
end
for i = 1:np
  if Dist(i,2) > 0
    Cyl{Dist(i,2)}(O(i)) = i;
  end
end
DistCyl = zeros(n,1); % Average point distance to each cylinder
for i = 1:n
  I = Cyl{i};
  m = length(I);
  if m > 19 % select the smallest 95% of distances
    d = sort(Dist(I,1));
    DistCyl(i) = mean(d(1:floor(0.95*m)));
  elseif m > 0
    DistCyl(i) = mean(Dist(I,1));
  end
end

% Define the output
pmdistance.CylDist = single(DistCyl);
pmdistance.median = median(DistCyl(:,1));
pmdistance.mean = mean(DistCyl(:,1));
pmdistance.max = max(DistCyl(:,1));
pmdistance.std = std(DistCyl(:,1));

T = BOrd == 0;
B1 = BOrd == 1;
B2 = BOrd == 2;
B = DistCyl(~T,1);
T = DistCyl(T,1);
B1 = DistCyl(B1,1);
B2 = DistCyl(B2,1);

pmdistance.TrunkMedian = median(T);
pmdistance.TrunkMean = mean(T);
pmdistance.TrunkMax = max(T);
pmdistance.TrunkStd = std(T);

if ~isempty(B)
  pmdistance.BranchMedian = median(B);
  pmdistance.BranchMean = mean(B);
  pmdistance.BranchMax = max(B);
  pmdistance.BranchStd = std(B);
else
  pmdistance.BranchMedian = 0;
  pmdistance.BranchMean = 0;
  pmdistance.BranchMax = 0;
  pmdistance.BranchStd = 0;
end

if ~isempty(B1)
  pmdistance.Branch1Median = median(B1);
  pmdistance.Branch1Mean = mean(B1);
  pmdistance.Branch1Max = max(B1);
  pmdistance.Branch1Std = std(B1);
else
  pmdistance.Branch1Median = 0;
  pmdistance.Branch1Mean = 0;
  pmdistance.Branch1Max = 0;
  pmdistance.Branch1Std = 0;
end

if ~isempty(B2)
  pmdistance.Branch2Median = median(B2);
  pmdistance.Branch2Mean = mean(B2);
  pmdistance.Branch2Max = max(B2);
  pmdistance.Branch2Std = std(B2);
else
  pmdistance.Branch2Median = 0;
  pmdistance.Branch2Mean = 0;
  pmdistance.Branch2Max = 0;
  pmdistance.Branch2Std = 0;
end


function [imdef, grad] = imdeform3_and_grad(imfix, T, varargin) %, interp_type, out_type, out_val, pix_resolution)
% deform image
    interp_type = 0;
    out_type = 0;
    out_val = 0;
    pix_resolution = [1,1,1];

    if nargin >= 3
        if ~isempty(varargin{1})
            interp_type = varargin{1};
        end
    end
    if nargin >= 4
        if ~isempty(varargin{2})
            out_type = varargin{2};
        end
    end
    if nargin >= 5
        if ~isempty(varargin{3})
            out_val = varargin{3};
        end
    end
    if nargin >= 6
        if ~isempty(varargin{4})
            pix_resolution = varargin{4};
            T = conv_2d_T_from_phys_to_pix(T, pix_resolution);
        end
    end

    if size(imfix, 1) ~= size(T, 1) || size(imfix, 2) ~= size(T, 2) ||...
            size(imfix, 3) ~= size(T, 3) || size(T, 4) ~= 3
        error('Dimensions dont match');
    end

    if isa(imfix, 'single') && isa(T, 'single')
        [imdef, grad] = mex_3d_volume_warp_and_grad_float(imfix, T, interp_type, out_type, out_val);
    elseif isa(imfix, 'double') && isa(T, 'double')
        [imdef, grad] = mex_3d_volume_warp_and_grad_double(imfix, T, interp_type, out_type, out_val);
    else
        error('Variables class mismatch')
    end
end