From efcbcf194335d9b292ed5e0de16137c7d3949aae Mon Sep 17 00:00:00 2001
From: Monica J Emerson <monj@dtu.dk>
Date: Mon, 22 Feb 2021 09:12:10 +0100
Subject: [PATCH] Added code

---
 code/InSegtFibre_2D.m                         | 221 +++++
 code/InsegtFibre_3D.m                         | 254 ++++++
 code/InsegtFibre_orientations.m               | 138 +++
 code/InsegtFibre_validate3DTracks.m           |  68 ++
 code/functions/calc_eltsdict.m                |   8 +
 code/functions/calcu_psize.m                  |  15 +
 code/functions/imshow3D.m                     | 291 +++++++
 code/functions/loadVolumeRoI.m                |  42 +
 code/functions/num_dictAtoms.m                |   8 +
 code/functions/selectFoV.m                    |  29 +
 code/functions/track_slicer.m                 | 109 +++
 code/scripts/addpaths_inSegtFibre.m           |  12 +
 code/scripts/create_dict.m                    |  31 +
 code/scripts/indicate_dataFolder.m            |  19 +
 code/scripts/input_depthRoI.m                 |  19 +
 code/scripts/load_multiple_trackSets.m        |  15 +
 code/scripts/setup_dict.m                     |  15 +
 .../code/batch_processing_script.m            |  39 +
 .../code/functions/biadjacency_matrix.cpp     | 103 +++
 .../code/functions/biadjacency_matrix.mexa64  | Bin 0 -> 13773 bytes
 .../functions/biadjacency_matrix.mexmaci64    | Bin 0 -> 13924 bytes
 .../code/functions/biadjacency_matrix.mexw64  | Bin 0 -> 18432 bytes
 .../code/functions/build_dictionary.m         |  23 +
 .../code/functions/build_km_tree.cpp          | 421 +++++++++
 .../code/functions/build_km_tree.mexa64       | Bin 0 -> 19188 bytes
 .../code/functions/build_km_tree.mexmaci64    | Bin 0 -> 23416 bytes
 .../code/functions/build_km_tree.mexw64       | Bin 0 -> 26112 bytes
 .../code/functions/build_km_tree_xcorr.cpp    | 427 ++++++++++
 .../code/functions/build_km_tree_xcorr.mexa64 | Bin 0 -> 19157 bytes
 .../functions/build_km_tree_xcorr.mexmaci64   | Bin 0 -> 23344 bytes
 .../code/functions/build_km_tree_xcorr.mexw64 | Bin 0 -> 27136 bytes
 .../code/functions/compile_mex_functions.m    |   8 +
 .../code/functions/compute_mappings.m         |  21 +
 .../code/functions/image_texture_gui.m        | 805 ++++++++++++++++++
 .../code/functions/linkaxesicon.png           | Bin 0 -> 568 bytes
 .../code/functions/normalize_image.m          |   9 +
 .../functions/probability_search_km_tree.cpp  | 305 +++++++
 .../probability_search_km_tree.mexa64         | Bin 0 -> 18140 bytes
 .../probability_search_km_tree.mexmaci64      | Bin 0 -> 14168 bytes
 .../probability_search_km_tree.mexw64         | Bin 0 -> 20992 bytes
 .../code/functions/process_image.m            |  16 +
 .../code/functions/search_km_tree.cpp         | 239 ++++++
 .../code/functions/search_km_tree.mexa64      | Bin 0 -> 13522 bytes
 .../code/functions/search_km_tree.mexmaci64   | Bin 0 -> 13604 bytes
 .../code/functions/search_km_tree.mexw64      | Bin 0 -> 16896 bytes
 .../code/functions/search_km_tree_xcorr.cpp   | 239 ++++++
 .../functions/search_km_tree_xcorr.mexa64     | Bin 0 -> 13546 bytes
 .../functions/search_km_tree_xcorr.mexmaci64  | Bin 0 -> 13628 bytes
 .../functions/search_km_tree_xcorr.mexw64     | Bin 0 -> 17408 bytes
 .../functions/segmentation_correction_gui.m   | 406 +++++++++
 .../code/functions/update_dictionary.m        |   9 +
 code/texture_gui/code/reusing_labels_script.m |  23 +
 code/texture_gui/code/test.m                  |  31 +
 .../code/texture_gui_uses_script.m            |  29 +
 54 files changed, 4447 insertions(+)
 create mode 100755 code/InSegtFibre_2D.m
 create mode 100755 code/InsegtFibre_3D.m
 create mode 100755 code/InsegtFibre_orientations.m
 create mode 100755 code/InsegtFibre_validate3DTracks.m
 create mode 100755 code/functions/calc_eltsdict.m
 create mode 100755 code/functions/calcu_psize.m
 create mode 100755 code/functions/imshow3D.m
 create mode 100755 code/functions/loadVolumeRoI.m
 create mode 100755 code/functions/num_dictAtoms.m
 create mode 100755 code/functions/selectFoV.m
 create mode 100755 code/functions/track_slicer.m
 create mode 100755 code/scripts/addpaths_inSegtFibre.m
 create mode 100755 code/scripts/create_dict.m
 create mode 100755 code/scripts/indicate_dataFolder.m
 create mode 100644 code/scripts/input_depthRoI.m
 create mode 100755 code/scripts/load_multiple_trackSets.m
 create mode 100755 code/scripts/setup_dict.m
 create mode 100755 code/texture_gui/code/batch_processing_script.m
 create mode 100755 code/texture_gui/code/functions/biadjacency_matrix.cpp
 create mode 100755 code/texture_gui/code/functions/biadjacency_matrix.mexa64
 create mode 100755 code/texture_gui/code/functions/biadjacency_matrix.mexmaci64
 create mode 100755 code/texture_gui/code/functions/biadjacency_matrix.mexw64
 create mode 100755 code/texture_gui/code/functions/build_dictionary.m
 create mode 100755 code/texture_gui/code/functions/build_km_tree.cpp
 create mode 100755 code/texture_gui/code/functions/build_km_tree.mexa64
 create mode 100755 code/texture_gui/code/functions/build_km_tree.mexmaci64
 create mode 100755 code/texture_gui/code/functions/build_km_tree.mexw64
 create mode 100755 code/texture_gui/code/functions/build_km_tree_xcorr.cpp
 create mode 100755 code/texture_gui/code/functions/build_km_tree_xcorr.mexa64
 create mode 100755 code/texture_gui/code/functions/build_km_tree_xcorr.mexmaci64
 create mode 100755 code/texture_gui/code/functions/build_km_tree_xcorr.mexw64
 create mode 100755 code/texture_gui/code/functions/compile_mex_functions.m
 create mode 100755 code/texture_gui/code/functions/compute_mappings.m
 create mode 100755 code/texture_gui/code/functions/image_texture_gui.m
 create mode 100755 code/texture_gui/code/functions/linkaxesicon.png
 create mode 100755 code/texture_gui/code/functions/normalize_image.m
 create mode 100755 code/texture_gui/code/functions/probability_search_km_tree.cpp
 create mode 100755 code/texture_gui/code/functions/probability_search_km_tree.mexa64
 create mode 100755 code/texture_gui/code/functions/probability_search_km_tree.mexmaci64
 create mode 100755 code/texture_gui/code/functions/probability_search_km_tree.mexw64
 create mode 100755 code/texture_gui/code/functions/process_image.m
 create mode 100755 code/texture_gui/code/functions/search_km_tree.cpp
 create mode 100755 code/texture_gui/code/functions/search_km_tree.mexa64
 create mode 100755 code/texture_gui/code/functions/search_km_tree.mexmaci64
 create mode 100755 code/texture_gui/code/functions/search_km_tree.mexw64
 create mode 100755 code/texture_gui/code/functions/search_km_tree_xcorr.cpp
 create mode 100755 code/texture_gui/code/functions/search_km_tree_xcorr.mexa64
 create mode 100755 code/texture_gui/code/functions/search_km_tree_xcorr.mexmaci64
 create mode 100755 code/texture_gui/code/functions/search_km_tree_xcorr.mexw64
 create mode 100755 code/texture_gui/code/functions/segmentation_correction_gui.m
 create mode 100755 code/texture_gui/code/functions/update_dictionary.m
 create mode 100755 code/texture_gui/code/reusing_labels_script.m
 create mode 100755 code/texture_gui/code/test.m
 create mode 100755 code/texture_gui/code/texture_gui_uses_script.m

diff --git a/code/InSegtFibre_2D.m b/code/InSegtFibre_2D.m
new file mode 100755
index 0000000..bf5ee95
--- /dev/null
+++ b/code/InSegtFibre_2D.m
@@ -0,0 +1,221 @@
+% InSegtFibre_2D
+% Written by Monica Jane Emerson, April 2018.
+% MIT license
+
+%% Step 0: Add paths of GUI and other functions and scripts used in Insegt Fibre
+close all,
+clear all,
+addpath(genpath('./texture_gui'))
+addpath('./scripts')
+addpath('./functions')
+
+disp('Step 0 completed')
+
+%% Step 1: Load and visualise the four 2D images
+%the path of the 2Ddata folder in your computer
+str_datafolder = '../data/2Ddata/'; %default value
+
+%Visualise all four datasets
+contents_datafolder = dir(str_datafolder);
+num_datasets = length(contents_datafolder)-2; 
+
+figure
+ for k= 1:num_datasets
+    %read image
+    im = imread([str_datafolder,contents_datafolder(k+2).name]); 
+    %create subtitle for image
+    subtitle = [num2str(k),'. ',contents_datafolder(k+2).name(1:end-4)];
+    ind = find(subtitle=='_');
+    subtitle(ind) = ' ';
+    %plot image
+    subplot(2,2,k), imagesc(im), axis image, colormap gray, title(subtitle)
+ end
+ 
+h = msgbox('Inspect the quality of the four different scans');
+waitfor(h)
+
+disp('Step 1 completed')
+
+%% Step 2: Select data-set and region of interest (RoI)
+close all
+%USER INPUT: select dataset
+x = inputdlg('Choose a data-set (1, 2, 3 or 4?): ','User input',[1,20],{num2str(4)});
+
+%read the 2D image chosen by the user 
+dataset = str2double(x{1}); 
+im = imread([str_datafolder,contents_datafolder(dataset+2).name]);
+
+%print the name of the selected data-set
+disp(['Selected data-set: ', contents_datafolder(dataset+2).name(1:end-4)]);
+
+%USER INPUT: select RoI
+h = msgbox('Crop a region of interest containing 100-1000 fibres.'); 
+waitfor(h)
+im_crop = imcrop(im);
+
+%visualise the selected RoI
+if isempty(im_crop)
+   h = msgbox('There was an error in the cropping. Run the section again.'); 
+   waitfor(h)
+else
+    figure, imagesc(im_crop), axis image, colormap gray, 
+    title('Region of Interest for training the dictionary')
+end
+
+disp('Step 2 completed')
+
+%% Step 3: Set default parameters and the patch size at the scale of the fibres
+close all
+%USER INPUT: Parameters that give the scale of the fibres in pixels
+prompt_px = ['Pixel size [', char(181),'m]: '];
+prompt_diam = ['Diameter size [', char(181),'m]: '];
+x = str2double(inputdlg({prompt_px, prompt_diam},'User input',[1,30],{num2str(0.96),num2str(7)}));
+
+%compute patch size as the closest odd integer to the fibre diameter
+%measured in pixels diam/pixel_size
+patch_size = calcu_psize(x(2)/x(1));
+
+%check that the patch size is in the optimal range to ensure precision and
+%speed
+if ((x(2)/x(1)) < 7)
+    factor = 9/(x(2)/x(1));
+    patch_size = calcu_psize(factor*x(2)/x(1));
+    msg = ['We will upscale your images with a factor ',...
+        num2str(factor,'%0.2f'),' to obtain better precision. The patch size is now ',...
+        num2str(patch_size),'.'];
+    h = msgbox(msg);
+    waitfor(h)
+elseif ((x(2)/x(1)) >= 17)
+     factor = 11/(x(2)/x(1));
+    patch_size = calcu_psize(factor*x(2)/x(1));
+    msg = ['We will downscale your images with a factor ',...
+        num2str(factor),' to obtain reduce the computational time. The patch size is now ',...
+        num2str(patch_size),'.'];
+    h = msgbox(msg);
+    waitfor(h)
+else
+    factor = 1;
+end
+
+%set patch size
+dictopt.patch_size = patch_size; 
+%set the default ditionary parameters
+dictopt.method = 'euclidean';
+dictopt.branching_factor = 3; %it should at least be 3
+dictopt.number_layers = 5; %at least 5. The higher the more accurate, but also slower and more computationally heavy
+num_dict_elts = calc_eltsdict(dictopt.branching_factor,dictopt.number_layers);
+dictopt.number_training_patches = 5000; %at least an order of magnitude more than the number of dictionary elements
+dictopt.normalization = false; %set to true if the global intensity of the slices varies along the depth of the volume
+
+disp('Step 3 completed')
+
+%% Step 4: Run InSegt
+%display the important dictionary parameters
+fprintf('\nImportant Dictionary Parameters:\n');
+disp(['patch size: ', num2str(dictopt.patch_size)]);
+disp(['number dictionary elements: ', num2str(calc_eltsdict(dictopt.branching_factor,dictopt.number_layers))]);
+
+%resize cropped region of interest with factor
+im_train = imresize(im_crop, factor);
+%open the GUI with 2 labels for pixel annotation (fibre centre region or not)
+image_texture_gui(im_train,dictopt,2)
+
+disp('Step 4 completed')
+
+%% Step 5: Obtain the centre coordinates from the hard segmentation
+close all
+%USER INPUT: label used for the centre regions
+label = 2; %1 (blue) or 2 (pink)
+
+%calculate the centroids of the connected centre regions
+c = regionprops(gui_S==label,'centroid');
+centrePoints = cat(1,c.Centroid);
+
+%show fibre centre coordinates over slice
+figure(1), subplot(1,2,1), imagesc(im_crop), axis image, colormap gray, 
+hold on, h = imagesc(ind2rgb(imresize(gui_S==label,1/factor), cool(2))); set(h, 'AlphaData',0.5);
+
+figure(1), subplot(1,2,2), imagesc(im_crop), axis image, colormap gray
+hold on, plot(centrePoints(:,1)*1/factor,centrePoints(:,2)*1/factor,'r*');
+
+disp('Step 5 completed')
+
+%% Step 6: Save the dictionary to process other regions of the scan
+close all
+%train the dictionary with the small RoI
+dictionary = build_dictionary(im_train,dictopt); %create the dictionary of intensities
+image_texture_gui(im_train,dictionary,2) %learn the dictionary of probabilities by annotating in the GUI 
+dictionary = update_dictionary(dictionary,gui_dictprob); %update dictionary to include the learnt probalilities
+
+%USER INPUT: select a RoI to process with the learnt dictionary
+h = msgbox('Crop a region of interest, it can be as big as you like.'); 
+waitfor(h)
+im_p = imcrop(im);
+if isempty(im_crop)
+   h = msgbox('There was an error in the cropping. Run the section again from the cropping.'); 
+   waitfor(h)
+else
+    figure, imagesc(im_p), axis image, colormap gray, 
+    title('Region of Interest for finding fibre centres')
+end
+
+%apply the dictionary to process the larger RoI
+im_process = imresize(im_p,factor);
+[S,allP] = process_image(im_process,dictionary);
+    
+%calculate the centroids of the connected centre regions
+label = 2; %1 (blue) or 2 (pink)
+c = regionprops(S==label,'centroid');
+centrePoints = cat(1,c.Centroid);
+
+%Centre regions and coordinates over the image to evaluate the accuracy of the segmentation
+figure, imagesc(im_process), axis image, colormap gray, 
+hold on, h = imagesc(ind2rgb(S, cool(2))); set(h, 'AlphaData',0.5);
+hold on, plot(centrePoints(:,1),centrePoints(:,2),'y.');
+title('Segmented centre regions and fibre detections over the processed image');
+    
+if factor ~=1
+    figure, imagesc(im_p), axis image, colormap gray, 
+    hold on, plot(centrePoints(:,1)*1/factor,centrePoints(:,2)*1/factor,'y.');
+    title('Centre detections over the original resolution')
+end
+    
+disp('Step 6 completed')
+
+%% Step 7: Tune the threshold applied to the probability map
+close all
+%visualise the propabilistic segmentation of fibre centre regions
+figure(1), imagesc(allP(:,:,2)), axis image off, colormap gray, title('Centre class probability map'), colorbar
+
+y = 'yes';
+while strcmp(y,'yes') 
+    %USER INPUT: threshold value for the probability map 
+    x = inputdlg('Choose threshold: ','User input',[1,20],{num2str(0.5)});
+
+    %Centre regions over the image to evaluate the accuracy of the segmentation
+    figure, imagesc(im_process), axis image, colormap gray, 
+    hold on, h = imagesc(ind2rgb(allP(:,:,2)>str2double(x{1}), cool(2))); set(h, 'AlphaData',0.5);
+    
+    %USER INPUT: do you want to try another threshold?? 
+    y = questdlg('Do you want to try another thresold?: ','User input','yes','no','yes');
+end
+
+disp('Step 7 completed')
+
+%% Step 8: Save your manual input to add additional markings later on
+close all
+%annotate a little in the GUI and save your manual input
+h = msgbox(['Annotate a little in the GUI and press [S] before closing the GUI (then close by pressing export [E]). Choose to save',...
+    ' your annotations in the folder "InsegtFibre_workshopDTU/data/saved_data/trainingData".']); 
+waitfor(h)
+image_texture_gui(im_train,dictopt,2)  
+%save the training region, over which you placed the markings
+save('../data/saved_data/trainingData/training_image.mat','im_train');
+
+%Call the GUI with a saved labelling
+load('../data/saved_data/trainingData/training_image.mat');
+[filename,pathname] = uigetfile('*_labels_indexed.png', 'Choose label image', '../data/saved_data/trainingData/');  
+labelling = imread([pathname,filename]); %read labelling
+image_texture_gui(im_train,dictopt,2,labelling) %call the GUI with the saved labelling
+
+disp('Step 8 completed')
diff --git a/code/InsegtFibre_3D.m b/code/InsegtFibre_3D.m
new file mode 100755
index 0000000..33dc837
--- /dev/null
+++ b/code/InsegtFibre_3D.m
@@ -0,0 +1,254 @@
+% InSegtFibre_3D
+% Written by Monica Jane Emerson, May 2018.
+% MIT license
+
+%% Step 0: Add paths of Insegt GUI, other functions and scripts, and prepare workspace
+close all,
+clear all,
+addpath(genpath('./texture_gui'))
+addpath('./scripts')
+addpath('./functions')
+
+disp('Step 0 completed')
+
+%% Step 1: Locate folder with the CT data
+close all
+indicate_dataFolder
+
+disp('Step 1 completed')
+
+%% Step 2: Load and visualise the data
+close all
+[V,depth] = loadVolumeRoI(path_volumeFolder);
+figure, imshow3D(V) %visualise the loaded RoI
+
+disp('Step 2 completed')
+
+%% Step 3: Compute a dictionary model from the CT scan 
+close all
+setup_dict %set the parameters of the dictionary model
+create_dict %learn the dictionary model from training data
+
+disp('Step 3 completed')
+
+%% Step 4: Obtain the centre-class probabilistic segmentation for a slice
+close all
+% USER INPUT: Load a saved dictionary
+[filename,pathname] = uigetfile('*.mat','Choose dictionary','../data/saved_data/dictionaries/dictionary');
+load([pathname,filename]);
+
+% USER INPUT: Choose slice
+prompt = ['Choose a slice to segment: [1,', num2str(size(V,3)),']:'];
+x = inputdlg(prompt,'User input',[1,30],{num2str(round(size(V,3)/4))}); 
+sliceAnalys = str2double(x{1});
+h = msgbox('Segmenting image...');
+[~,allP] = process_image(V(:,:,sliceAnalys),dictionary);
+delete(h)
+Pcentre = allP(:,:,2);
+
+%Visualise for each pixel its probabily of belonging to a fibre centre region
+h = figure(1), %h.Units = 'normalized'; h.Position = [0 0 1 1]; 
+subplot(1,2,1), imagesc(Pcentre), axis image, colormap gray,  colorbar, 
+title('Probability of belonging to the central region of a fibre') 
+figure(1), subplot(1,3,3), histogram(Pcentre(:)), 
+ylabel('Count of probabilities'), xlabel('Range of probabilities') 
+
+disp('Step 4 completed')
+
+%% Step 5: Obtain the fibre centres by thresholding the probabilistic segmentation
+% USER INPUT: threshold value for the probability map 
+thresh = inputdlg('Choose threshold: ','User input',[1,20],{num2str(0.50)});
+
+%Threshold probability map
+areas_th = Pcentre > str2double(thresh{1}); 
+
+%Calculate centroids
+concomp = logical(areas_th);
+c = regionprops(concomp,'centroid');
+centrePoints_2D = cat(1,c.Centroid);
+    
+%Visualisations to evaluate the chosen threshold
+figure(2), subplot(1,2,1), imagesc(V(:,:,sliceAnalys)), axis image, colormap gray, 
+hold on, h = imagesc(ind2rgb(areas_th, cool(2))), set(h, 'AlphaData',0.5);
+figure(2), subplot(1,2,2), imagesc(V(:,:,sliceAnalys)), axis image, colormap gray
+hold on, plot(centrePoints_2D(:,1),centrePoints_2D(:,2),'r*');
+
+disp('Step 5 completed')
+
+%% Step 6: Detect fibre centres in the batch of slices forming the volume
+close all
+clear centrePoints, clear allP, clear c
+% USER INPUT: Load a saved dictionary
+[filename,pathname] = uigetfile('*.mat','Choose dictionary','../data/saved_data/dictionaries/dictionary_');
+load([pathname,filename]);
+
+% USER INPUT: threshold value for the probability map 
+thresh = inputdlg('Choose threshold: ','User input',[1,20],{num2str(0.5)});
+ 
+%Initialise variables
+step = 1; 
+slices = 1:step:size(V,3);
+
+%Start timer
+tstart = tic; 
+h = waitbar(0,'Processing volume...');
+
+for l = 1:numel(slices)
+    %Compute the probabilistic segmentation
+    [~,allP] = process_image(V(:,:,slices(l)),dictionary);
+    %Save probability map
+    P(:,:,l) = allP(:,:,2);
+    %Compute the connected components of the thresholded probabilities
+    c = regionprops(bwlabel(allP(:,:,2) > str2num(thresh{1})),'centroid');
+    %Store the coordinates of the centre points
+    centrePoints{l} = cat(1,c.Centroid);
+    %Update the data processing wait bar
+    waitbar(l/numel(slices),h)
+end
+
+%disp processing time
+t_load = toc(tstart);
+f = msgbox(['time to process volume: ' , num2str(t_load), 's']);
+close(h)
+waitfor(f)
+
+%Compute the number of detected fibres per slice
+clear len
+close all
+for l = 1:length(centrePoints)
+    len(l) = size(centrePoints{l},1);
+end
+aux = str2double(depth);
+figure(1), plot([aux(1):aux(3):aux(2)],len,'.'), axis tight, title('Nr. fibres per slice'), 
+xlabel('slice number (1 is the top of the sample)')
+ylabel('number of detected fibres')
+
+%Visualise the detections in 3D
+if ~exist('vx_size')
+    vx_size = str2double(inputdlg(['Pixel size [', char(181),'m]: '],'User input',[1,30],{num2str(1.1)}));
+end
+
+for l = 1:step:length(centrePoints)
+    figure(2), hold on, plot3(centrePoints{l}(:,1)*vx_size,centrePoints{l}(:,2)*vx_size,l*ones(size(centrePoints{l}(:,1)))*vx_size,'r.','MarkerSize',1)
+end
+h = figure(2), axis tight, view(3), axis equal
+xlabel('x axis [\mum]'),ylabel('y axis [\mum]'), zlabel('z axis [\mum]')
+aux = cellstr(num2str(vx_size*linspace(str2double(depth{1}),str2double(depth{2}),length(h.Children.ZTickLabel)+1)','%.f'));
+h.Children.ZTickLabel = aux(2:end);
+
+% USER INPUT: Save 3D detections
+uisave('centrePoints','../data/saved_data/centreCoordinates/centreCoords_?.mat')
+
+disp('Step 6 completed')
+
+%% Step 7: Compute the 3D fibre trajectories via tracking
+% USER INPUT: Load the saved 3D detections
+[filename,pathname] = uigetfile('*.mat','Choose the set of 3D coordinates to track','../data/saved_data/centreCoordinates');
+load([pathname,filename]);
+
+% USER INPUT: How many pixels is a fibre allowed to move from one slice to the
+% next? (function of the step, the diameter and the pixel size).
+x = inputdlg('How many pixels is a fibre allowed to move from one slice to the next? (a function of the step, the diameter and the pixel size): ','User input',[1,65],{num2str(5)}); 
+dist = str2num(x{1});
+
+% USER INPUT: Should the tracking start with the detections of the bottom 
+% or the top slice?
+if ~exist('depth')
+    depth = input_depthRoI(num_slices);
+end
+top = 'Top of the volume (slice 1)';
+bottom = ['Bottom of the volume (slice ', depth{2},')'];
+direct = questdlg('Where shall we start the fibres?','Tracking direction',top, bottom,bottom);
+
+if strcmp(direct,bottom)
+    m = length(centrePoints);
+else 
+    m = 1;
+end
+
+%Initialise variables
+thisCt = centrePoints{m}; %we start tracking from the bottom of the volume (end slice)
+f_x = nan(size(thisCt,1),length(centrePoints));
+f_y = nan(size(thisCt,1),length(centrePoints));
+f_x(:,1) = centrePoints{m}(:,1);
+f_y(:,1) = centrePoints{m}(:,2);
+
+%Starting time
+tstart = tic;
+
+%Track the coordinates in the z direction
+for l = 2:length(centrePoints)
+    % coordinates of next slice
+    if strcmp(direct,bottom)
+        ctNext = centrePoints{end-l+1};
+    else
+        ctNext = centrePoints{l};
+    end
+    
+    % build kd-tree
+    tree_down = KDTreeSearcher(ctNext);
+    % search the kd-tree
+    [id_down, d_down] = knnsearch(tree_down,thisCt,'K',1);
+    % build kd-tree
+    tree_up = KDTreeSearcher(thisCt);
+    % search the kd-tree
+    [id_up, d_up] = knnsearch(tree_up,ctNext,'K',1);
+    
+    % keep matches that are bidirectional
+    id_top = unique(id_up(id_down));
+    id_bottom = id_down(unique(id_up(id_down)));
+    
+    % keep matches that are closer than a distance
+    idMatch = find(d_down(id_top) < dist);
+    id_top_th = id_top(idMatch);
+    id_bottom_th = id_bottom(idMatch);
+    
+    if strcmp(direct,bottom)
+        f_x(id_top_th,l) = centrePoints{end-l+1}(id_bottom_th,1);
+        f_y(id_top_th,l) = centrePoints{end-l+1}(id_bottom_th,2);
+    else
+        f_x(id_top_th,l) = centrePoints{l}(id_bottom_th,1);
+        f_y(id_top_th,l) = centrePoints{l}(id_bottom_th,2);
+    end
+    
+    %points to be matched with the next slice
+    thisCt(id_top_th,:) = ctNext(id_bottom_th,:);
+end
+t_load = toc(tstart);
+disp(['time to track coordinates along the volume: ' , num2str(t_load), 's']);
+
+%Save track coordinates in the structure 'fibres'
+fibres.x = f_x;
+fibres.y = f_y;
+
+%Visualise fibre tracks
+% USER INPUT: How many fibres would you like to visualise (in percentage)?
+questions = {'What percentage of the tracked fibres would you like to visualise (%)?: '};
+x = inputdlg(questions,'User input',[1,40],{num2str(10)}); %ask for patch size
+
+perc = str2double(x{1})/100;
+fib_ind = randperm(size(fibres.x,1),round(perc*size(fibres.x,1))); %indices of fibre to plot
+z = [1:size(fibres.x,2)]; %z-values
+
+if ~exist('vx_size')
+    vx_size = str2double(inputdlg(['Pixel size [', char(181),'m]: '],'User input',[1,30],{num2str(1.1)}));
+end
+figure(3),clf
+for l= 1:numel(fib_ind)
+	h = figure(3);
+    hold on, plot3(fibres.x(fib_ind(l),:)*vx_size,fibres.y(fib_ind(l),:)*vx_size,z*vx_size,'LineWidth',1), 
+end
+axis tight, axis equal, view(3), 
+xlabel('x axis [\mum]'),ylabel('y axis [\mum]'), zlabel('z axis [\mum]')
+aux = cellstr(num2str(vx_size*linspace(str2double(depth{1}),str2double(depth{2}),length(h.Children.ZTickLabel)+1)','%.f'));
+h.Children.ZTickLabel = aux(2:end);
+
+% USER INPUT: Save fibre tracks
+if strcmp(direct,bottom)
+    direction = [depth{2},'to',depth{1}];
+else
+    direction = [depth{1},'to',depth{2}];
+end
+uisave('fibres',['../data/saved_data/fibreTracks/fibreTracks_dataSetX_',direction,'step',depth{3},'.mat'])
+
+    
\ No newline at end of file
diff --git a/code/InsegtFibre_orientations.m b/code/InsegtFibre_orientations.m
new file mode 100755
index 0000000..86cbcc3
--- /dev/null
+++ b/code/InsegtFibre_orientations.m
@@ -0,0 +1,138 @@
+% InSegtFibre_orientations
+% Written by Monica Jane Emerson, May 2019.
+% MIT license
+
+%% Prepare workspace
+close all
+clear all
+addpath('./scripts')
+addpath('./functions')
+
+%% Read tracks, z-values (analysed slices) and voxel size 
+[filename_tracks,pathname_tracks] = uigetfile('*.mat','Choose tracks','../data/saved_data/fibreTracks');
+fibres = getfield(load([pathname_tracks,filename_tracks]),'fibres');
+
+depth = input_depthRoI; %get z coordinates (start, end and step)
+z_axis = [str2double(depth{1}):str2double(depth{3}):str2double(depth{2})];
+
+vx_size = str2double(inputdlg(['What is the pixel size of your scan [', char(181),'m]: '],'Pixel/voxel size',[1,45],{num2str(1.1)}));
+
+%% Display tracks
+h1 = figure(1);
+for l= 1:size(fibres.x,1)
+    figure(1), hold on, 
+    plot3(fibres.x(l,:)*vx_size,fibres.y(l,:)*vx_size,z_axis*vx_size,'k','LineWidth',1), 
+end
+figure(1), axis tight, axis equal, view(2), view(3) 
+xlabel('x axis [\mum]'),ylabel('y axis [\mum]'), zlabel('z axis [\mum]')
+
+%% Display locations of missed detections
+missed_det = isnan(fibres.x');
+figure(2), imagesc(missed_det), axis image, axis xy
+title('Missed fibre centres')
+ylabel('z axis [slices]'),xlabel('fibre ID'),
+
+%% Select fibres for the orientation plot
+%Indices of fibres that miss start and/or end detection
+%(will be excluded from the orientation plot)
+exc_fibres = find((missed_det(1,:)|missed_det(end,:))==1);
+
+%Indices of the fibre kept for the orientation plot
+keep_fibres = 1:size(fibres.x,1);
+keep_fibres(exc_fibres) = []; 
+
+display(['The orientation can been computed for ',num2str(length(keep_fibres)/size(fibres.x,1)*100,'%.2f') ,'% of the tracked fibres']);
+
+%% Compute orientation (inclination and it's direction, azimuth)
+%displacement between end and start points
+disp_x = fibres.x(keep_fibres,end)-fibres.x(keep_fibres,1);
+disp_y = fibres.y(keep_fibres,end)-fibres.y(keep_fibres,1);
+disp_r = sqrt(disp_x.^2 + disp_y.^2);
+
+%inclination and azimuth angles
+inclination = atan2(disp_r,(size(fibres.x,2)-1)*ones(length(keep_fibres),1));
+azimuth = atan2(disp_y,disp_x);
+
+display('The orientations (inclination and azimuth angles) have been computed');
+
+%% Histograms of orientation angles
+close all
+%Inclination
+max_inc = str2double(inputdlg('What is the maximum misalignment angle you expect [0°, 90°]?','Max. Inclination',[1,35],{num2str(15)}));
+bins_inc = [0:max_inc];
+int_inc = [0:0.1:max_inc];
+
+h_inc = hist(inclination*180/pi,bins_inc)/length(inclination);
+h_inc_int = interp1(bins_inc,h_inc,int_inc);
+h1 = figure(1),hold on, plot(int_inc,smooth(h_inc_int))
+ylim([0,max(smooth(h_inc_int))]), xlim([0,max_inc]),h1.Children.XTick = linspace(0,max_inc,10);
+xlabel('Inclination \phi [\circ] of the fibres'), ylabel('Relative frequency')
+title('Amount of fibre misalignment with respect to the scanning z-axis'),
+
+%Azimuth
+max_az = 360;
+bins_az = [-max_az/2:24:max_az/2];
+int_az = [-max_az/2:2.4:max_az/2];
+
+h_az = hist(azimuth*180/pi,bins_az)/length(azimuth);
+h_az_int = interp1(bins_az,h_az,int_az);
+h2 = figure(2),hold on, plot(int_az,smooth(h_az_int))
+xlim([-max_az/2,max_az/2]), h2.Children.XTick = [-180,-90,0,90,180];
+ylim([0,max(smooth(h_az_int))])
+xlabel('Azimuth \theta [\circ] of the fibres'), ylabel('Relative frequency')
+title('Direction of misalignment with respect to scanning x-axis'),
+
+%% Colour-code fibre tracks according to orientation angles
+%Azimuth (direction of misalingment)
+cmap_az = circshift(colormap(hsv),32);
+h3 = figure(3);
+for l= 1:length(keep_fibres)
+    colouring = cmap_az(round(azimuth(l)/(2*pi)*63+1+63/2),:);
+    figure(3), hold on, plot3(fibres.x(keep_fibres(l),:)*vx_size,fibres.y(keep_fibres(l),:)*vx_size,z_axis*vx_size,'LineWidth',1,'Color',colouring), 
+end
+figure(3), axis tight, axis equal, view(2), 
+xlabel('x axis [\mum]'),ylabel('y axis [\mum]'), zlabel('z axis [\mum]')
+colormap(cmap_az), colorbar, caxis([-180,180]), h3.Children(1).Ticks = -180:30:180;
+for k = 1:length(h3.Children(1).Ticks)
+    h3.Children(1).TickLabels(k) = {[h3.Children(1).TickLabels{k},'°']};
+end
+
+%Inclination (amount of misalignment)
+cmap_inc = linspace(0,1,32)'*[1,1,1];
+sat_angle = max_inc/3;
+sat = sat_angle*pi/180;
+h4 = figure(4);
+for l= 1:length(keep_fibres)
+    if inclination(l) < sat
+            colouring = [1,1,1]*inclination(l)/sat;
+        else
+            colouring = [1,1,1];
+        end
+    figure(4), hold on, plot3(fibres.x(keep_fibres(l),:)*vx_size,fibres.y(keep_fibres(l),:)*vx_size,z_axis*vx_size,'LineWidth',1,'Color',colouring), 
+end
+figure(4), axis tight, axis equal, view(2), 
+xlabel('x axis [\mum]'),ylabel('y axis [\mum]'), zlabel('z axis [\mum]')
+colormap(cmap_inc), 
+colorbar, caxis([0,sat_angle]), h.Children(1).Ticks = linspace(0,sat_angle,5); 
+h4.Children(1).TickLabels(end) = {['>',num2str(sat_angle)]};
+for k = 1:length(h.Children(1).Ticks)
+    h4.Children(1).TickLabels(k) = {[h4.Children(1).TickLabels{k},'°']};
+end
+
+%Azimuth weighed by inclination (amount of misalignment)
+h5 = figure(5);
+for l= 1:length(keep_fibres)
+    if inclination(l) < sat
+            colouring = cmap_az(round(azimuth(l)/(2*pi)*63+1+63/2),:)*inclination(l)/sat;
+        else
+            colouring = cmap_az(round(azimuth(l)/(2*pi)*63+1+63/2),:);
+        end
+    figure(5), hold on, plot3(fibres.x(keep_fibres(l),:)*vx_size,fibres.y(keep_fibres(l),:)*vx_size,z_axis*vx_size,'LineWidth',1,'Color',colouring), 
+end
+figure(5), axis tight, axis equal, view(2), 
+xlabel('x axis [\mum]'),ylabel('y axis [\mum]'), zlabel('z axis [\mum]')
+colormap(cmap_az), colorbar, caxis([-180,180]), h5.Children(1).Ticks = -180:30:180;
+for k = 1:length(h.Children(1).Ticks)
+    h5.Children(1).TickLabels(k) = {[h5.Children(1).TickLabels{k},'°']};
+end
+
diff --git a/code/InsegtFibre_validate3DTracks.m b/code/InsegtFibre_validate3DTracks.m
new file mode 100755
index 0000000..29ae8d1
--- /dev/null
+++ b/code/InsegtFibre_validate3DTracks.m
@@ -0,0 +1,68 @@
+% VALIDATION_3DFIBREDETECTION
+% Written by Monica Jane Emerson, April 2019.
+% MIT license
+
+%% Add paths of Insegt, functions and scripts, and prepare workspace
+close all, clear all,
+addpath('./scripts')
+addpath('./functions')
+
+%% Get the measured fibre tracks in the format required by the validation GUI
+% USER INPUT: Load the fibre tracks to validate
+[filename_tracks,pathname_tracks] = uigetfile('*.mat','Choose the fibre tracks to validate','saved_data/fibreTracks');
+load([pathname_tracks,filename_tracks]);
+
+%USER INPUT: Deregister the tracks if necessary
+x = questdlg('Have the tracks undergone a transformation (rotation and/or translation) since they were measured from the CT scan?','2D de-registration','Yes','No','No');
+if strcmp(x,'Yes')
+    [filename,pathname] = uigetfile('*.mat','Load the transformation matrix','saved_data/2Dregistration/');
+    t = load([pathname,filename],'tform');  
+    %USER INPUT: Offset between registration FoV and analysis FoV
+    offset = str2double(inputdlg('Offset between the FoV used for the analysis and the FoV used for the 2D registration','Offset registration-analysis',[1,50],{num2str(100)}));
+    aux = [fibres.x(:) + offset*ones(size(fibres.x(:))),fibres.y(:) + offset*ones(size(fibres.x(:))),ones(size(fibres.y(:)))]*t.tform.tdata.Tinv;
+    fibres.x = reshape(aux(:,1), size(fibres.x)) - offset*ones(size(fibres.x));
+    fibres.y = reshape(aux(:,2), size(fibres.x)) - offset*ones(size(fibres.x));
+end
+
+for l = 1:size(fibres.x,2) 
+    centers{l} = [fibres.x(:,l),fibres.y(:,l),[1:size(fibres.x,1)]']; 
+end;
+
+%% Get the analysed volume of interest (VoI) in the format read by the validaiton GUI
+close all
+% USER INPUT: Option to open a volume of interest saved as a tif file
+x = questdlg('Is the analysed volume of interest saved as one .tif file, with the slices ordered in the direction of tracking?','Load analysed volume','Yes','No','Yes');
+
+if strcmp(x,'No')
+    indicate_dataFolder;
+    [V,depth] = loadVolumeRoI(path_volumeFolder);
+    % USER INPUT: Tracking direction
+    top = ['Top to bottom (from slice ',depth{1},')'];
+    bottom = ['Bottom to top (from slice ',depth{2},')'];
+    direct = questdlg('In which direction did you track the coordinates?','Tracking direction',top, bottom, bottom);
+    % USER INPUT: Give a name to the .tif Volume of Interest
+    if strcmp(direct,bottom)
+        direction = [depth{2},'to',depth{1},'step',depth{3}];
+    else
+        direction = [depth{1},'to',depth{2},'step',depth{3}];
+    end
+    name_tif = inputdlg('Name for the .tif file of your volume of interest (VoI): ','Name your VOI',[1,55],{['V_?_',direction,'.tif']});
+    filename_voi= name_tif{1};
+    pathname_voi = 'saved_data/volumeOfInterest/';
+    if strcmp(direct,bottom) 
+        imwrite(V(:,:,end),[pathname_voi,filename_voi]);
+        for l= 2:size(V,3)
+            imwrite(V(:,:,end-l+1),[pathname_voi,filename_voi], 'WriteMode','append');
+        end 
+    else
+        imwrite(V(:,:,1),[pathname_voi,filename_voi]);
+        for l= 2:size(V,3)
+            imwrite(V(:,:,l),[pathname_voi,filename_voi], 'WriteMode','append');
+        end 
+    end
+else
+    [filename_voi,pathname_voi] = uigetfile('*.tif','Choose volume of interest','saved_data/volumeOfInterest/VOI_v');
+end
+
+%% Validate all fibres
+track_slicer([pathname_voi,filename_voi],centers)
diff --git a/code/functions/calc_eltsdict.m b/code/functions/calc_eltsdict.m
new file mode 100755
index 0000000..6edad49
--- /dev/null
+++ b/code/functions/calc_eltsdict.m
@@ -0,0 +1,8 @@
+function [num] = calc_eltsdict(k,n)
+%CALC_ELTSDICT Summary of this function goes here
+% Written by Monica Jane Emerson, April 2018, MIT License
+vect = [1:n];
+series = k.^(vect-1);
+num = k*sum(series);
+end
+
diff --git a/code/functions/calcu_psize.m b/code/functions/calcu_psize.m
new file mode 100755
index 0000000..76ee312
--- /dev/null
+++ b/code/functions/calcu_psize.m
@@ -0,0 +1,15 @@
+function [patch_size] = calcu_psize(pixPerDiam)
+%CALCU_PSIZE Loads a selected region of interest from a volume.
+%   Details...
+%by Monica Jane Emerson, April 2019, MIT License
+if mod(round(pixPerDiam),2)==0
+    if (round(pixPerDiam)-pixPerDiam)<0
+        patch_size = round(pixPerDiam)+1;
+    else
+        patch_size = round(pixPerDiam)-1;
+    end   
+else
+    patch_size = round(pixPerDiam);
+end
+end
+
diff --git a/code/functions/imshow3D.m b/code/functions/imshow3D.m
new file mode 100755
index 0000000..15f49c4
--- /dev/null
+++ b/code/functions/imshow3D.m
@@ -0,0 +1,291 @@
+function  imshow3D( Img, disprange )
+%IMSHOW3D displays 3D grayscale images in slice by slice fashion with mouse
+%based slice browsing and window and level adjustment control.
+%
+% Usage:
+% imshow3D ( Image )
+% imshow3D ( Image , [] )
+% imshow3D ( Image , [LOW HIGH] )
+%   
+%    Image:      3D image MxNxK (K slices of MxN images) 
+%    [LOW HIGH]: display range that controls the display intensity range of
+%                a grayscale image (default: the widest available range)
+%
+% Use the scroll bar or mouse scroll wheel to switch between slices. To
+% adjust window and level values keep the mouse right button pressed and
+% drag the mouse up and down (for level adjustment) or right and left (for
+% window adjustment). 
+% 
+% "Auto W/L" button adjust the window and level automatically 
+%
+% While "Fine Tune" check box is checked the window/level adjustment gets
+% 16 times less sensitive to mouse movement, to make it easier to control
+% display intensity rang.
+%
+% Note: The sensitivity of mouse based window and level adjustment is set
+% based on the user defined display intensity range; the wider the range
+% the more sensitivity to mouse drag.
+% 
+% 
+%   Example
+%   --------
+%       % Display an image (MRI example)
+%       load mri 
+%       Image = squeeze(D); 
+%       figure, 
+%       imshow3D(Image) 
+%
+%       % Display the image, adjust the display range
+%       figure,
+%       imshow3D(Image,[20 100]);
+%
+%   See also IMSHOW.
+
+%
+% - Maysam Shahedi (mshahedi@gmail.com)
+% - Released: 1.0.0   Date: 2013/04/15
+% - Revision: 1.1.0   Date: 2013/04/19
+% 
+
+sno = size(Img,3);  % number of slices
+S = round(sno/2);
+
+global InitialCoord;
+
+MinV = 0;
+MaxV = max(Img(:));
+LevV = (double( MaxV) + double(MinV)) / 2;
+Win = double(MaxV) - double(MinV);
+WLAdjCoe = (Win + 1)/1024;
+FineTuneC = [1 1/16];    % Regular/Fine-tune mode coefficients
+
+if isa(Img,'uint8')
+    MaxV = uint8(Inf);
+    MinV = uint8(-Inf);
+    LevV = (double( MaxV) + double(MinV)) / 2;
+    Win = double(MaxV) - double(MinV);
+    WLAdjCoe = (Win + 1)/1024;
+elseif isa(Img,'uint16')
+    MaxV = uint16(Inf);
+    MinV = uint16(-Inf);
+    LevV = (double( MaxV) + double(MinV)) / 2;
+    Win = double(MaxV) - double(MinV);
+    WLAdjCoe = (Win + 1)/1024;
+elseif isa(Img,'uint32')
+    MaxV = uint32(Inf);
+    MinV = uint32(-Inf);
+    LevV = (double( MaxV) + double(MinV)) / 2;
+    Win = double(MaxV) - double(MinV);
+    WLAdjCoe = (Win + 1)/1024;
+elseif isa(Img,'uint64')
+    MaxV = uint64(Inf);
+    MinV = uint64(-Inf);
+    LevV = (double( MaxV) + double(MinV)) / 2;
+    Win = double(MaxV) - double(MinV);
+    WLAdjCoe = (Win + 1)/1024;
+elseif isa(Img,'int8')
+    MaxV = int8(Inf);
+    MinV = int8(-Inf);
+    LevV = (double( MaxV) + double(MinV)) / 2;
+    Win = double(MaxV) - double(MinV);
+    WLAdjCoe = (Win + 1)/1024;
+elseif isa(Img,'int16')
+    MaxV = int16(Inf);
+    MinV = int16(-Inf);
+    LevV = (double( MaxV) + double(MinV)) / 2;
+    Win = double(MaxV) - double(MinV);
+    WLAdjCoe = (Win + 1)/1024;
+elseif isa(Img,'int32')
+    MaxV = int32(Inf);
+    MinV = int32(-Inf);
+    LevV = (double( MaxV) + double(MinV)) / 2;
+    Win = double(MaxV) - double(MinV);
+    WLAdjCoe = (Win + 1)/1024;
+elseif isa(Img,'int64')
+    MaxV = int64(Inf);
+    MinV = int64(-Inf);
+    LevV = (double( MaxV) + double(MinV)) / 2;
+    Win = double(MaxV) - double(MinV);
+    WLAdjCoe = (Win + 1)/1024;
+elseif isa(Img,'logical')
+    MaxV = 0;
+    MinV = 1;
+    LevV =0.5;
+    Win = 1;
+    WLAdjCoe = 0.1;
+end    
+
+SFntSz = 9;
+LFntSz = 10;
+WFntSz = 10;
+LVFntSz = 9;
+WVFntSz = 9;
+BtnSz = 10;
+ChBxSz = 10;
+
+if (nargin < 2)
+    [Rmin Rmax] = WL2R(Win, LevV);
+elseif numel(disprange) == 0
+    [Rmin Rmax] = WL2R(Win, LevV);
+else
+    LevV = (double(disprange(2)) + double(disprange(1))) / 2;
+    Win = double(disprange(2)) - double(disprange(1));
+    WLAdjCoe = (Win + 1)/1024;
+    [Rmin Rmax] = WL2R(Win, LevV);
+end
+
+axes('position',[0,0.2,1,0.8]), imshow(Img(:,:,S), [Rmin Rmax])
+
+FigPos = get(gcf,'Position');
+S_Pos = [50 45 uint16(FigPos(3)-100)+1 20];
+Stxt_Pos = [50 65 uint16(FigPos(3)-100)+1 15];
+Wtxt_Pos = [50 20 60 20];
+Wval_Pos = [110 20 60 20];
+Ltxt_Pos = [175 20 45 20];
+Lval_Pos = [220 20 60 20];
+BtnStPnt = uint16(FigPos(3)-250)+1;
+if BtnStPnt < 300
+    BtnStPnt = 300;
+end
+Btn_Pos = [BtnStPnt 20 100 20];
+ChBx_Pos = [BtnStPnt+110 20 100 20];
+
+if sno > 1
+    shand = uicontrol('Style', 'slider','Min',1,'Max',sno,'Value',S,'SliderStep',[1/(sno-1) 10/(sno-1)],'Position', S_Pos,'Callback', {@SliceSlider, Img});
+    stxthand = uicontrol('Style', 'text','Position', Stxt_Pos,'String',sprintf('Slice# %d / %d',S, sno), 'BackgroundColor', [0.8 0.8 0.8], 'FontSize', SFntSz);
+else
+    stxthand = uicontrol('Style', 'text','Position', Stxt_Pos,'String','2D image', 'BackgroundColor', [0.8 0.8 0.8], 'FontSize', SFntSz);
+end    
+ltxthand = uicontrol('Style', 'text','Position', Ltxt_Pos,'String','Level: ', 'BackgroundColor', [0.8 0.8 0.8], 'FontSize', LFntSz);
+wtxthand = uicontrol('Style', 'text','Position', Wtxt_Pos,'String','Window: ', 'BackgroundColor', [0.8 0.8 0.8], 'FontSize', WFntSz);
+lvalhand = uicontrol('Style', 'edit','Position', Lval_Pos,'String',sprintf('%6.0f',LevV), 'BackgroundColor', [1 1 1], 'FontSize', LVFntSz,'Callback', @WinLevChanged);
+wvalhand = uicontrol('Style', 'edit','Position', Wval_Pos,'String',sprintf('%6.0f',Win), 'BackgroundColor', [1 1 1], 'FontSize', WVFntSz,'Callback', @WinLevChanged);
+Btnhand = uicontrol('Style', 'pushbutton','Position', Btn_Pos,'String','Auto W/L', 'FontSize', BtnSz, 'Callback' , @AutoAdjust);
+ChBxhand = uicontrol('Style', 'checkbox','Position', ChBx_Pos,'String','Fine Tune', 'BackgroundColor', [0.8 0.8 0.8], 'FontSize', ChBxSz);
+
+set (gcf, 'WindowScrollWheelFcn', @mouseScroll);
+set (gcf, 'ButtonDownFcn', @mouseClick);
+set(get(gca,'Children'),'ButtonDownFcn', @mouseClick);
+set(gcf,'WindowButtonUpFcn', @mouseRelease)
+set(gcf,'ResizeFcn', @figureResized)
+
+
+% -=< Figure resize callback function >=-
+    function figureResized(object, eventdata)
+        FigPos = get(gcf,'Position');
+        S_Pos = [50 45 uint16(FigPos(3)-100)+1 20];
+        Stxt_Pos = [50 65 uint16(FigPos(3)-100)+1 15];
+        BtnStPnt = uint16(FigPos(3)-250)+1;
+        if BtnStPnt < 300
+            BtnStPnt = 300;
+        end
+        Btn_Pos = [BtnStPnt 20 100 20];
+        ChBx_Pos = [BtnStPnt+110 20 100 20];
+        if sno > 1
+            set(shand,'Position', S_Pos);
+        end
+        set(stxthand,'Position', Stxt_Pos);
+        set(ltxthand,'Position', Ltxt_Pos);
+        set(wtxthand,'Position', Wtxt_Pos);
+        set(lvalhand,'Position', Lval_Pos);
+        set(wvalhand,'Position', Wval_Pos);
+        set(Btnhand,'Position', Btn_Pos);
+        set(ChBxhand,'Position', ChBx_Pos);
+    end
+
+% -=< Slice slider callback function >=-
+    function SliceSlider (hObj,event, Img)
+        S = round(get(hObj,'Value'));
+        set(get(gca,'children'),'cdata',Img(:,:,S))
+        caxis([Rmin Rmax])
+        if sno > 1
+            set(stxthand, 'String', sprintf('Slice# %d / %d',S, sno));
+        else
+            set(stxthand, 'String', '2D image');
+        end
+    end
+
+% -=< Mouse scroll wheel callback function >=-
+    function mouseScroll (object, eventdata)
+        UPDN = eventdata.VerticalScrollCount;
+        S = S - UPDN;
+        if (S < 1)
+            S = 1;
+        elseif (S > sno)
+            S = sno;
+        end
+        if sno > 1
+            set(shand,'Value',S);
+            set(stxthand, 'String', sprintf('Slice# %d / %d',S, sno));
+        else
+            set(stxthand, 'String', '2D image');
+        end
+        set(get(gca,'children'),'cdata',Img(:,:,S))
+    end
+
+% -=< Mouse button released callback function >=-
+    function mouseRelease (object,eventdata)
+        set(gcf, 'WindowButtonMotionFcn', '')
+    end
+
+% -=< Mouse click callback function >=-
+    function mouseClick (object, eventdata)
+        MouseStat = get(gcbf, 'SelectionType');
+        if (MouseStat(1) == 'a')        %   RIGHT CLICK
+            InitialCoord = get(0,'PointerLocation');
+            set(gcf, 'WindowButtonMotionFcn', @WinLevAdj);
+        end
+    end
+
+% -=< Window and level mouse adjustment >=-
+    function WinLevAdj(varargin)
+        PosDiff = get(0,'PointerLocation') - InitialCoord;
+
+        Win = Win + PosDiff(1) * WLAdjCoe * FineTuneC(get(ChBxhand,'Value')+1);
+        LevV = LevV - PosDiff(2) * WLAdjCoe * FineTuneC(get(ChBxhand,'Value')+1);
+        if (Win < 1)
+            Win = 1;
+        end
+
+        [Rmin, Rmax] = WL2R(Win,LevV);
+        caxis([Rmin, Rmax])
+        set(lvalhand, 'String', sprintf('%6.0f',LevV));
+        set(wvalhand, 'String', sprintf('%6.0f',Win));
+        InitialCoord = get(0,'PointerLocation');
+    end
+
+% -=< Window and level text adjustment >=-
+    function WinLevChanged(varargin)
+
+        LevV = str2double(get(lvalhand, 'string'));
+        Win = str2double(get(wvalhand, 'string'));
+        if (Win < 1)
+            Win = 1;
+        end
+
+        [Rmin, Rmax] = WL2R(Win,LevV);
+        caxis([Rmin, Rmax])
+    end
+
+% -=< Window and level to range conversion >=-
+    function [Rmn Rmx] = WL2R(W,L)
+        Rmn = L - (W/2);
+        Rmx = L + (W/2);
+        if (Rmn >= Rmx)
+            Rmx = Rmn + 1;
+        end
+    end
+
+% -=< Window and level auto adjustment callback function >=-
+    function AutoAdjust(object,eventdata)
+        Win = double(max(Img(:))-min(Img(:)));
+        Win (Win < 1) = 1;
+        LevV = double(min(Img(:)) + (Win/2));
+        [Rmin, Rmax] = WL2R(Win,LevV);
+        caxis([Rmin, Rmax])
+        set(lvalhand, 'String', sprintf('%6.0f',LevV));
+        set(wvalhand, 'String', sprintf('%6.0f',Win));
+    end
+
+end
+% -=< Maysam Shahedi (mshahedi@gmail.com), April 19, 2013>=-
\ No newline at end of file
diff --git a/code/functions/loadVolumeRoI.m b/code/functions/loadVolumeRoI.m
new file mode 100755
index 0000000..4263133
--- /dev/null
+++ b/code/functions/loadVolumeRoI.m
@@ -0,0 +1,42 @@
+function [V,depth] = loadVolumeRoI(path)
+%LOADVOLUMEROI Loads a selected region of interest from a volume.
+%   Details...
+%by Monica Jane Emerson, March 2019, MIT License
+
+contents_datafolder = dir(path);
+path_firstSlice = [path,contents_datafolder(3).name];
+
+%select FoV in the cross-sectional direction
+[rect,~] = selectFoV(path_firstSlice);
+
+%select slices
+num_slices = length(contents_datafolder)-2; %depth of the volume
+zmin = ['Lower limit in the depth direction [1, ',num2str(num_slices),']:'];
+zmax = ['Upper limit in the depth direction [1, ',num2str(num_slices),']:'];
+zstep = ['Step (1 to take every slice):'];
+prompt = {zmin,zmax,zstep};
+depth = inputdlg(prompt,'RoI in the depth direction', [1,50], {'1',num2str(num_slices),'1'});
+slices = [str2double(depth{1}):str2double(depth{3}):str2double(depth{2})];
+
+V = zeros([rect(4)-rect(2)+1,rect(3)-rect(1)+1,numel(slices)]); %volume preallocation (for speed)
+
+tstart = tic;
+h = waitbar(0,'Loading volume...', 'CreateCancelBtn','setappdata(gcbf,''canceling'',1)');
+ for k= 1:numel(slices)
+    im = imread([path,contents_datafolder(slices(k)+2).name]);
+    V(:,:,k) = double(im(rect(2):rect(4),rect(1):rect(3)))/2^16;
+    
+    %Processing data wait bar
+    waitbar(k/numel(slices),h)
+    if getappdata(h,'canceling')
+        break
+    end
+    if k == numel(slices) 
+        delete(h)
+        t_load = toc(tstart);
+        f = msgbox(['time to load volume: ' , num2str(t_load), 's']);
+    end
+ end
+
+end
+
diff --git a/code/functions/num_dictAtoms.m b/code/functions/num_dictAtoms.m
new file mode 100755
index 0000000..968a080
--- /dev/null
+++ b/code/functions/num_dictAtoms.m
@@ -0,0 +1,8 @@
+function [num] = num_dictAtoms(k,n)
+%NUM_DICTATOMS Summary of this function goes here
+%by Monica Jane Emerson, April 2018, MIT License
+vect = [1:n];
+series = k.^(vect-1);
+num = k*sum(series);
+end
+
diff --git a/code/functions/selectFoV.m b/code/functions/selectFoV.m
new file mode 100755
index 0000000..8b3af9a
--- /dev/null
+++ b/code/functions/selectFoV.m
@@ -0,0 +1,29 @@
+function [rect,im_rect] = selectFoV(slice_path)
+%SELECTFOV is a user-friendly function to select a region of interest from a 2D image.
+%   The user can choose to select interactively the region of interest (RoI) 
+%   interactively with imcrop, or specify the coordinates of the RoI.
+% by Monica Jane Emerson, March 2019, MIT License
+
+%USER INPUT: SLICE_PATH, The location of the slice to crop the RoI from.
+% Other user input given through interaction with windows.
+
+autoManual = questdlg('How would you like to select the region of interest (RoI)?','Select analysis region','Interactively','I know the coordinates','Interactively');
+im = imread(slice_path);
+
+if strcmp(autoManual,'Interactively')
+    [~,rect] = imcrop(im);
+    rect = round(rect);
+    rect(3:4) = rect(1:2) + rect(3:4) - [1,1];
+else
+    xmin = ['Lower limit for the x value [1, ',num2str(size(im,2)),']:'];
+    xmax = ['Upper limit for the x value [1, ',num2str(size(im,2)),']:'];
+    ymin = ['Lower limit for the y value [1, ',num2str(size(im,1)),']:'];
+    ymax = ['Upper limit for the y value [1, ',num2str(size(im,1)),']:'];
+    prompt = {xmin,ymin,xmax,ymax};
+    dimRoI = inputdlg(prompt,'RoI in the cross-sectional direction', [1,60], {'200','200','1799','1799'});
+    rect = str2double(dimRoI);
+end
+    im_rect = double(im(rect(2):rect(4),rect(1):rect(3)))/2^16;
+
+end
+
diff --git a/code/functions/track_slicer.m b/code/functions/track_slicer.m
new file mode 100755
index 0000000..7500058
--- /dev/null
+++ b/code/functions/track_slicer.m
@@ -0,0 +1,109 @@
+function track_slicer(filename,centers,clim)
+%TRACK_SLICER   Slice trough data, centers and tracks.
+%   TRACK_SLICER(FILENAME,CENTERS,CLIM)
+%       FILENAME, name of the tiff stack with image data.
+%       CENTERS, detected fibre centers. If CENTERS contains track ids (as
+%           returned by fibre_tracking function) those will be shown as 
+%           numbers.
+%       CLIM, optional color limits.
+%   Author: vand@dtu.dk 2018
+
+if ~iscell(centers) % then tracks are given, and need to be converted
+    tracks = centers;
+    tracks = permute(tracks,[2,3,1]);
+    tracks(:,3,:) = repmat((1:size(tracks,1))',[1 1 size(tracks,3)]); % using slice number not z coordinate
+    centers = permute(mat2cell(tracks,size(tracks,1),size(tracks,2),ones(size(tracks,3),1)),[3 2 1]);
+end
+
+Z = length(imfinfo(filename));
+z = round(0.5*(Z+1));
+%update_drawing
+I = imread(filename,'Index',z);
+dim = [size(I),Z];
+if nargin<3 || isempty(clim)
+    clim = [min(I(:)),max(I(:))];
+end
+
+show_numbers = true;
+
+fig = figure('Units','Normalized','Position',[0.1 0.3 0.5 0.6],...
+    'KeyPressFcn',@key_press);
+imagesc(I,clim)
+hold on, colormap gray, axis image ij
+plot(centers{z}(:,1),centers{z}(:,2),'r.')
+title(['slice ',num2str(z),'/',num2str(Z)])
+drawnow
+
+% to capture zoom
+LIMITS = [0.5,dim(2)+0.5,0.5,dim(1)+0.5];
+zoom_handle = zoom(fig);
+pan_handle = pan(fig);
+set(zoom_handle,'ActionPostCallback',@adjust_limits,...
+    'ActionPreCallback',@force_keep_key_press);
+set(pan_handle,'ActionPostCallback',@adjust_limits,...
+    'ActionPreCallback',@force_keep_key_press);
+
+% if nargout>1
+%     uiwait(fig) % waits with assigning output until a figure is closed
+% end
+
+%%%%%%%%%% CALLBACK FUNCTIONS %%%%%%%%%%
+
+    function key_press(~,object)
+        % keyboard commands
+        key = object.Key;
+        switch key
+            case 'uparrow'
+                z = min(z+1,dim(3));
+            case 'downarrow'
+                z = max(z-1,1);
+            case 'rightarrow'
+                z = min(z+10,dim(3));
+            case 'leftarrow'
+                z = max(z-10,1);
+            case 'pageup'
+                z = min(z+50,dim(3));
+            case 'pagedown'
+                z = max(z-50,1);
+            case 'n'
+                show_numbers = ~show_numbers;
+        end
+        update_drawing
+    end
+
+%%%%%%%%%% HELPING FUNCTIONS %%%%%%%%%%
+
+    function update_drawing
+        I = imread(filename,'Index',z);
+        cla, imagesc(I,clim), hold on
+        if ~show_numbers || size(centers{z},2)<3 || (LIMITS(2)-LIMITS(1))*(LIMITS(4)-LIMITS(3))>300^2
+            plot(centers{z}(:,1),centers{z}(:,2),'r.')
+        else
+            present = (centers{z}(:,1)<LIMITS(2))&(centers{z}(:,1)>LIMITS(1))&...
+                (centers{z}(:,2)<LIMITS(4))&(centers{z}(:,2)>LIMITS(3));
+            text(centers{z}(present,1),centers{z}(present,2),num2cell(centers{z}(present,3)'),...
+                'HorizontalAlignment','center','VerticalAlignment','middle',...
+                'Color','r')
+        end
+        title(['slice ',num2str(z),'/',num2str(Z)])
+        drawnow
+    end
+
+    function adjust_limits(~,~)
+        % response to zooming and panning
+        LIMITS([1,2]) = get(gca,'XLim');
+        LIMITS([3,4]) = get(gca,'YLim');
+        if show_numbers
+            update_drawing
+        end
+    end
+
+    function force_keep_key_press(~,~)
+        % a hack to maintain my key_press while in zoom and pan mode
+        % http://undocumentedmatlab.com/blog/enabling-user-callbacks-during-zoom-pan
+        hManager = uigetmodemanager(fig);
+        [hManager.WindowListenerHandles.Enabled] = deal(false);
+        set(fig, 'KeyPressFcn', @key_press);
+    end
+
+end
diff --git a/code/scripts/addpaths_inSegtFibre.m b/code/scripts/addpaths_inSegtFibre.m
new file mode 100755
index 0000000..9e96bfd
--- /dev/null
+++ b/code/scripts/addpaths_inSegtFibre.m
@@ -0,0 +1,12 @@
+%ADDPATHS_INSEGTFIBRE Makes all the code of Insegt Fibre accesible
+%   Written by Monica Jane Emerson, March 2019, MIT License
+
+%USER INPUT: The path of the textureGUI folder in your computer
+x = inputdlg('Confirm the default path of the texture_GUI folder: ',...
+    'User input',[1,30],{'./texture_gui'});
+path_textureGUI = x{1}; 
+
+%Add the functions and Insegt software path 
+addpath(genpath(path_textureGUI))
+addpath('./scripts')
+addpath('./functions')
\ No newline at end of file
diff --git a/code/scripts/create_dict.m b/code/scripts/create_dict.m
new file mode 100755
index 0000000..5ef7e62
--- /dev/null
+++ b/code/scripts/create_dict.m
@@ -0,0 +1,31 @@
+%CREATE_DICT Updates the dictionary of intensities built by SETUP_DICT with
+%a training data-set that can be loaded or created from scratch.
+%   Written by Monica Jane Emerson, March 2019, MIT License
+
+%USER INPUT: Option to load a labelling that was saved
+x = questdlg('Would you like to load a labelling or create a new one?','Annotation of training data','New one','Load','New one');
+
+if strcmp(x,'Load') 
+    [filename,pathname] = uigetfile('*.mat','Choose training image','../data/saved_data/trainingData/imtrain.mat');
+    load([pathname,filename]);
+    [filename,pathname] = uigetfile('*labels_indexed.png','Choose label image','../data/saved_data/trainingData/');
+    labelling = imread([pathname,filename]);
+    
+    dictionary = build_dictionary(im_train,dictopt); %create the dictionary of intensities
+    image_texture_gui(im_train,dictionary,2,labelling)
+else
+    %select a small RoI for training, containing 100 fibres approx
+    prompt = ['Choose a slice for training: [1,', num2str(size(V,3)),']:'];
+    x = inputdlg(prompt,...
+    'User input',[1,30],{num2str(round(size(V,3)/2))});  %select slice
+    path_trainSlice = [path_volumeFolder,contents_datafolder(str2double(x{1})+2).name];
+    [~,im_train] = selectFoV(path_trainSlice);
+    uisave('im_train','../data/saved_data/trainingData/imtrain.mat')
+    
+    dictionary = build_dictionary(im_train,dictopt); %create the dictionary of intensities
+    image_texture_gui(im_train,dictionary,2) %learn the dictionary of probabilities by annotating in the GUI 
+end
+dictionary = update_dictionary(dictionary,gui_dictprob); %update dictionary to include the learnt probalilities
+
+%USER INPUT: Save dictionary to process the complete scan
+uisave('dictionary','../data/saved_data/dictionaries/dictionary_v.mat')
diff --git a/code/scripts/indicate_dataFolder.m b/code/scripts/indicate_dataFolder.m
new file mode 100755
index 0000000..1899d0f
--- /dev/null
+++ b/code/scripts/indicate_dataFolder.m
@@ -0,0 +1,19 @@
+%INDICATE_DATAFOLDER Allows the user to specify the location of their data,
+%and displays a slice to ensure that the right data is contained at the 
+%specified location.
+%   Written by Monica Jane Emerson, March 2019, MIT License
+
+%USER INPUT: Path to CT volume? 
+path_volumeFolder = uigetdir('../data/','Open the folder with your CT data');
+if ~strcmp(path_volumeFolder(end),'/')
+    path_volumeFolder = [path_volumeFolder,'/'];
+end
+
+%add the path and check the contents of the data folder
+addpath(genpath(path_volumeFolder))
+contents_datafolder = dir(path_volumeFolder);
+
+%display cross-section, first slice
+path_firstSlice = [path_volumeFolder,contents_datafolder(3).name];
+im = imread(path_firstSlice);
+figure, imagesc(im), axis image, colormap gray, title('First slice of the loaded data-set')
\ No newline at end of file
diff --git a/code/scripts/input_depthRoI.m b/code/scripts/input_depthRoI.m
new file mode 100644
index 0000000..a6c8c5d
--- /dev/null
+++ b/code/scripts/input_depthRoI.m
@@ -0,0 +1,19 @@
+function [ depth ] = input_depthRoI(varargin)
+%INPUT_DEPTHROI asks the user to specify the depth range to analyse
+%   Details...
+%by Monica Jane Emerson, May 2019, MIT License
+
+if nargin == 1
+    num_slices = varargin{1};
+else
+    num_slices = [];
+end
+
+zmin = ['Lower limit in the depth direction [1, ',num2str(num_slices),']:'];
+zmax = ['Upper limit in the depth direction [1, ',num2str(num_slices),']:'];
+zstep = ['Step (1 to take every slice):'];
+prompt = {zmin,zmax,zstep};
+depth = inputdlg(prompt,'RoI in the depth direction', [1,50], {'1',num2str(num_slices),'10'});
+
+end
+
diff --git a/code/scripts/load_multiple_trackSets.m b/code/scripts/load_multiple_trackSets.m
new file mode 100755
index 0000000..0a25847
--- /dev/null
+++ b/code/scripts/load_multiple_trackSets.m
@@ -0,0 +1,15 @@
+%LOAD_MULTIPLE_TRACKSETS is a user-friendly script to load tracks measured 
+%from multiple data-sets, e.g. acquired at progressive load steps.
+% by Monica Jane Emerson, March 2019, MIT License
+
+%% USER INPUT: Load several sets of tracks corresponding to different steps of a time-lapse data-set
+x = inputdlg('How many sets of tracks would you like to load [>=2]?','Nr. analysed matching volumes',[1,60],{num2str(2)});
+
+for l = 1:str2double(x{1})
+    [filename_tracks,pathname_tracks] = uigetfile('*.mat',['Choose tracks for data-set ',num2str(l)],'saved_data/fibreTracks');
+    aux = load([pathname_tracks,filename_tracks]);
+    tracks{l} = aux.fibres;
+end
+num_datasets = length(tracks);
+num_slices = size(tracks{1}.x,2);
+
diff --git a/code/scripts/setup_dict.m b/code/scripts/setup_dict.m
new file mode 100755
index 0000000..b6e8f81
--- /dev/null
+++ b/code/scripts/setup_dict.m
@@ -0,0 +1,15 @@
+%SETUP_DICT Set-ups the default parameters for the dictionary, andasks for the
+%data-dependent parameter (patch size)
+%   Written by Monica Jane Emerson, March 2019, MIT License
+
+%USER INPUT: select patch size, the closest odd integer to factor*diam/pixel_size 
+x = inputdlg('Choose patch size: ','User input',[1,20],{num2str(11)}); %ask for patch size
+dictopt.patch_size = str2double(x{1}); %save patch size
+
+%Set the default parameters and initialise dictionary
+dictopt.method = 'euclidean';
+dictopt.branching_factor = 3; %>=3
+dictopt.number_layers = 5; %>=5. The higher the more accurate, but also slower and more computationally heavy
+dictopt.number_training_patches = 15000; %at least 10*num_dictAtoms(branching_factor,number_layers)
+dictopt.normalization = false; %set to true if the global intensity of the slices varies along the depth of the volume
+
diff --git a/code/texture_gui/code/batch_processing_script.m b/code/texture_gui/code/batch_processing_script.m
new file mode 100755
index 0000000..9d87ea3
--- /dev/null
+++ b/code/texture_gui/code/batch_processing_script.m
@@ -0,0 +1,39 @@
+clear
+close all
+addpath functions
+
+% VERSION 1: WITHOUT CORRECTION
+% for batch processing dictionary is reused, and manual labeling might need
+% correction, so easiest is to build dictionary outside the gui to be able
+% to use it later
+im = double(imread('../data/slice1.png'))/255;
+
+dictopt.method = 'euclidean';
+dictopt.patch_size = 9;
+dictopt.branching_factor = 5;
+dictopt.number_layers = 4;
+dictopt.number_training_patches = 30000;
+dictopt.normalization = false;
+
+dictionary = build_dictionary(im,dictopt);
+
+% IMPORTANT:
+% once inside gui export dict_labels to workspace (E)
+image_texture_gui(im,dictionary,2)
+%%
+dictionary = update_dictionary(dictionary,gui_dictprob);
+%%
+figure, imagesc(gui_S), axis image, title('results from gui')
+
+figure
+for i=1:5
+    I = imread(['../data/slice',num2str(i),'.png']);
+    S = process_image(I,dictionary);
+    subplot(1,5,i)
+    imagesc(S), axis image, title(i), drawnow
+end
+
+%%
+
+% VERSION 2: WITH (OR WITHOUT) CORRECTION
+% TODO: freezeing (F) and correcting
diff --git a/code/texture_gui/code/functions/biadjacency_matrix.cpp b/code/texture_gui/code/functions/biadjacency_matrix.cpp
new file mode 100755
index 0000000..efb16ea
--- /dev/null
+++ b/code/texture_gui/code/functions/biadjacency_matrix.cpp
@@ -0,0 +1,103 @@
+/*=================================================================
+* syntax: B = biadjacency_matrix(A,M,K) OR B = biadjacency_matrix(A,M)
+*
+* BIADJACENCY_MATRIX  - build biadjacancy matrix from assignment image
+* 			
+* 			Input: 	- A: X-by-Y assignment image
+* 					- M: patch size (length of edge)
+*                   - K: number of dictionary patches, defaults to max(A(:))
+*
+* 			Output: - B: XY-by-MMK sparse biadjacency matrix 
+*
+* 			Author: Vedrana Andersen Dahl, vand@dtu.dk, december 2015.
+*=================================================================*/
+
+#include <math.h>
+#include <stdio.h>
+#include <vector>
+#include <algorithm>
+#include "mex.h"
+
+// struct containing i and j indices of a sparse matrix element
+struct ij
+{
+    int i,j;
+    ij(int i_, int j_) : i(i_), j(j_){}; // constructor
+    bool operator<(const ij second) const{ // leq operator needed for sorting
+        return (j<second.j) || ((j==second.j) && (i<second.i));
+    }    
+};
+
+// The gateway mex routine
+void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
+{
+    /* Check for proper number of input and output arguments */    
+    if ((nlhs != 1) || (nrhs != 2))
+        mexErrMsgTxt("Usage: B = BIADJANCENCY_MATRIX(A,M) OR "
+                "B = BIADJANCENCY_MATRIX(A,M,K).\n");
+        
+    /* Read input */
+    double *A = mxGetPr(prhs[0]); // assignment image
+    int X = mxGetM(prhs[0]); // image size X
+	int Y = mxGetN(prhs[0]); // image size Y
+    int M = (int)mxGetPr(prhs[1])[0]; // patch size
+    int K; // number dict patches
+    if (nrhs==3)
+        K = (int)mxGetPr(prhs[2])[0]; 
+    else{ // assumes number of dict patches is max(A)
+        K = 0;
+        for (int a=0; a<X*Y; a++)
+            if (A[a]>K)
+                K = A[a];
+    }
+    
+    /* Compute some useful sizes */
+    int c = (M-1)/2; // width of boundary having no assignment 
+    int n = X*Y; // number of image pixels
+    int m = M*M*K; // number of dict pixels
+    int s = (X-M+1)*(Y-M+1)*M*M; // number image-dict links (elements in B)
+    
+    /* Finding elements of B as row-column indices */
+    std::vector<ij> bij;
+    bij.reserve(s); 
+    int ic,i,j;   
+    for (int y=0+c; y<Y-c; y++){ // visiting patches centered around pixels
+        for (int x=0+c; x<X-c; x++){
+            ic = x+y*X; // central patch pixel
+            for (int dy=-c; dy<=c; dy++){ // visiting pixels around central
+                for (int dx=-c; dx<=c; dx++){
+                    i = (x+dx)+(y+dy)*X;
+                    j = (c+dx)+(c+dy)*M+(A[ic]-1)*M*M;
+                    bij.push_back(ij(i,j));
+                }
+            }
+        }
+    }
+    
+    /* Sorting elements in bij columnwise */
+    std::sort (bij.begin(), bij.end());    
+    
+    /* Placeholder for output */
+    plhs[0] = mxCreateSparseLogicalMatrix(n,m,s); // output mxArray, sparse logical matrix B
+    if (plhs[0]==NULL)
+        mexErrMsgTxt("Could not allocate enough memory!\n");
+    
+    /* Access fields of output mxArray via pointers  */
+    mwIndex *ir = mxGetIr(plhs[0]); // row index (0 indexed) 
+    mwIndex *jc = mxGetJc(plhs[0]); // cumulative number of elements per column 
+    mxLogical *pr = mxGetLogicals(plhs[0]); // element values (will be all true)
+        
+    /* Converting row-column indices into row-cumulative column  */
+    int k = 0; // for visiting elements of bij
+    jc[0] = 0; // first element of cumulative sum is 0
+    for (int bc=0; bc<m; bc++){ // all columns of B        
+        jc[bc+1] = jc[bc]; 
+        while (k<bij.size() && bij[k].j==bc){
+            jc[bc+1]++;
+            ir[k] = bij[k].i;
+            pr[k] = true;
+            k++;
+        }
+    }
+}
+ 
diff --git a/code/texture_gui/code/functions/biadjacency_matrix.mexa64 b/code/texture_gui/code/functions/biadjacency_matrix.mexa64
new file mode 100755
index 0000000000000000000000000000000000000000..703f486d9d5d8524e9e27c48c259071a086f90a1
GIT binary patch
literal 13773
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

literal 0
HcmV?d00001

diff --git a/code/texture_gui/code/functions/biadjacency_matrix.mexmaci64 b/code/texture_gui/code/functions/biadjacency_matrix.mexmaci64
new file mode 100755
index 0000000000000000000000000000000000000000..f40f6e00dc3e5bf9fbbabf158abccc084bfc6a93
GIT binary patch
literal 13924
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

literal 0
HcmV?d00001

diff --git a/code/texture_gui/code/functions/biadjacency_matrix.mexw64 b/code/texture_gui/code/functions/biadjacency_matrix.mexw64
new file mode 100755
index 0000000000000000000000000000000000000000..6985266719edbacda108ffd1a788c7c78c26a019
GIT binary patch
literal 18432
zcmeHudwf*Ywf~-ECJA{kK?ww(0}coVVj!sCfX+!~a1YGb6cUUUOhPh{*t|Lq2$)pp
zkjk(-mfx-YUE5C|SZwvv_E)L(TGT!!2|{=X0b31X75lI!#E*^0g`nvCzH6Uzh5_aF
z-p{>%+)qC}e9l>Wuf6u#Yp=cb+H36$zWcVZbjFw&Zz93iE<k#m^80r_CdS5I|H4@I
z?3kA)?=pE`o?O}36tuMm+SUZ>T5R=ot*vb#+bX{;5N@?Kwc1>tTV`u%Yw#E6<z?G-
z);k~GKjZW}Pi!#WkH2@@h7r`i{p%+m{C5c-fAAv-w?BAZ!XG|J?K38|Z8!rM{r>t5
z?*pEG=Z72i08ab$<FenhUq7M4A4#~hslJiMxO7GpZpIqEn#pc=uzQTQ5jMq^lQx#I
zDZtQ+r(!BT`LehX)7HvqjAcmF1;};+0cD0(F_y+^L8^5!z^CgPX28c-HM&l}o3ZW0
za~osN(m?Hu*=d1{XFFr_P#!2}>>3028E^#ckEY_Cj6Ed<PeooR7l-^EAyl84j1P%S
z^CqK6d2Ec;76%&YLUoM2F&+(0yc6(F!<+Ir(Ne6DNe!@CG(uNw0p66y$ymI&T_cop
z#9ZZ=ccc)Z2s&r+n$=AWLB?iM(?-0+uMBU><0QI3Fi;Pi)E#sv>0Bv9C^{vbzqt*B
zq)VxA;<tz@7ar%QM!3-Sk5b~%74|G14cYT~w9{Vbjg7A&O?bpPuXvq{V_cl_IR?6%
z*6TORDK8eTS4PW3<tt_``gzZg&2gkND?FxbzWJ4|bWdXcVqtz|anyX=Ctkl>=Y{^A
z{oy?H>>HI$vFd~;R-WMB;zhmu$f#HJdmJCo5LhQJtc!%}0JtCFJtu80M=#hfD4U;q
zpzBufK0pjSF$JA{5H6*E=Sy5<QY#lUBSA9~m{H$_;^Jto*4lS4`8e<4;zKV6bL_Wn
zejHQu#ynYGs?hEs?G#$Cce2&S{C&cNfjuJ4gXxO_(g4Znjk@glj{Tjtg)J^eyt4!{
zjQ5BmtG97cHp(L>A&{o6W1X4dJdku{d7|l1@$j3zX!`KA9?|1-90^?kdJcLOOTx1}
zj^6O!e9<&dqz57$4o7Heg*7SCA3R7B=4*54;YH_oPa>U*y@qPJ806h?>mzT;xsXa?
zbKSJQ$@zGMcW{&^4)Dl(X<qRP7q4>1*{-sbcGtkDTdWu`(=uVUZpSfNaAm%Epevmx
z_IreRU`f<G;1x%?zTn*PTIXJT!g(Iy8Xc9bv3s!QWhrYu=yAN>HP0*d5z}%}IcQd-
zDNQY(pF7xf{Ssjwq>h@Q_#m0S*3_@_@RDfm0Pj9-{rZALBB8Ia)D4fko8=L4TG65&
zuh`GU7~V6Q&LgAKt&hA12gnm~sWYeuR$mzTV<wL-u=Dg@NhU^k&pT!wTksN;1Y_)h
zsZTWX9@PdT&I*r%Ax`Ydfgw(WF-`PD)2IlV2^VdLQf!9_U9%R8+zGHqydV{6i^K}B
zBAX$*e!Vjzoa5;4BAW%HY`3`A42$7KuW^x$foV*aV-V&tR+&GhYm7&jJkc>6)*wva
zWHknK$@M6~h}N!~FrpRwtVAi&6tMJ)K~K-HO>rE@c-a^)!xJ^}Xtob{G2ktFQw|74
zctno44@~927&jxFH$S_J*nk?gD*06#qhip^@JwYs>$=e+V9MAj*&dM&4qg%WKy*d2
zkOPv;QRpmpqFX3(1ekHYHorL7SZRLfP4kn=5GI!>Ge&YbdLT>j{Isr{NHN4~3@KgX
zr7N@7P$niv+U5dF8rhxICzd9sG;oP3v3M9$5f#QrFu%<3KAO{RZB7^o%l4^(egrN4
z00Uvs<QPd`LIvHQHj_VvR$W`XcH2ELN~dCduE!%rq)EQ+E!xM$IZw~IbWh}*&HBjq
zv@J>gultPkkzb+evOd?(V_tiSSHOk6rhbELS2Ww_aj^$&UVEdq$;AP<P+s&hhv`P%
z9@UYR_7Xy;k8sh;i}rfO9v(R{${jsjd0ZS;m&;xA@i1H@w*1TLB3WNyFR?!7vNw9g
z0dLXaq;y|zL@VS>>%78Ux({Q=Wv|0({6pG%E9?~{S2gXzS}4R>(?^r~G9)^{iw;Yn
zBIoiuZRpJRy6iSgj%H_Yx&5O=LJpgPqo`{53DT!?*>Y$PlkSBA2eGHQcwbH>GMeAn
zOlMX#k8K$BLfN%m@xB*`63^K;mEUH8g}3M&4h3J#d<TbruJA&gkTs+9sE1sFIK-ow
zTUOX@>e*3DB=*p#CuY9WVBYnT7sm&*PqRX)8dIBh{}(QDz8BWpI6oDV)`mk9J_sJm
zBSy)sKrsF-Pb7|Y>ZM_^GO=s+K#QsmllR7!WpT#`!7@5%I5yF;^Tug$q;po-GQWJZ
za~c=r=(KFqCCUwZrJXT0Y@VOqiPPnE?l=|b^*UY)-pNId?pCeWGX*<I0pX0WMVX)7
zIRyr-u}JP5YuN1Q?;PWa^x}|tEpW&qj(Wv$xbI*U`eV;&^twZecixI2b2>{Ps7ow1
zw!0fFrb$LNkLV>{+|e7#@!<6HL>G@@+j5C}E$}n1<IT1A`(ovz`gx!37W~4L_I1u7
zNm*wR_Ml5FF}AM@15A}8U(X}MI2s2-@J;DFngi$KAq);pgb|W|cs|4rb$J~}L%AOE
zrWzd%xc%5oQo2ZA7D?n0*y79+g$pwcWl1|9hUl+_i)a+D<9H|+>V#*52jkInk61kF
zk*B%Nap-rS&>ny%K{MO|I7ZWlek+k7`#cZ!9c;(xiC#w=rNkFqj$wD(l=}@klEzKD
z0$mc=Avi|8MMofFrl;p*I-(Mv^{ykn?xUgWJVpIj4_|jYlnMU_?}KT_vpfj|4*SC@
z*&7VB&$$d7OXNNyjxvH9$Em+pDEVHPB<xXL1ZT3X6bB)uQI1%nJRhA)$hdj5l3bV9
zp0)fQY0OUIRU&yI)adYvQ{bs~V|S6q!M1A0zIEAaU0YoC>B;>~E(8(@ShmPfCqj~K
zTwKY;gIT=jLm8w%q$|Cm+z<)QLfr|bi(}?9Ql6Ok6HT^K(p(4Rb1L`OB=ttVfga3u
zI;I!S#B3tFr}yz)7>l0kxnp2$W}-k$W$Yl2<^CSb8Q*k{lAFLh9#d|FH(UpT2PA>$
zS09Jhp^eua4+DJzk{WQ2-w20r0?`<vGO$-Wi3k+`k|;1~6c|4_rq>atG5<;|F_V|%
zm<#2Q3(oXjA41y!Z8$`Qj@|(3FUoq+0FQi_6-50fvL5;HMq>0mjd*|~kiqanw_|i|
z-o}@U-8@>6U$qR&RjE`d%awb0tnqQa>D_*s?_T#`Y3Zyp+Mlw{=y=Q{jwxa^a?TXa
zP$HvgFz#61w=oU%yB3;zj@m^q>i#~JYf$#WfkoX2NpjRiNixF4k}P#O%BNh`nI*1h
z_$OqwQQzT6B0Y>1UXriQ(_0x@hRfWdM;ubDPap2y_vKr-SP9;JtCR8NDQkY#YQ@?b
z|G@fAe6{uF{<Rij+yl*Hrwp0GZw|u+to*(bTa@@#QST8rz!PE**zJwFUvyia-b1e|
z>i(s8RVjKk(W{8VO3|T2kM-#zAbOQv>pfupko#fEX`;S=<@LRo(p&s_X(lifSmHF;
z!rHM=#>Z1}4N_2Z1FbzGwV3Z=_2hZlMqU4k$+*S4u4seZrWBp#(ePd_s=n@Wyu(HK
zVQcI~gw=BJgHhiv6tP>1=(5`}!G*sCSFdpI#r}1R-?^gxhg^=gt+5Jpaf>&Uv&UW0
zl}|$@IR6!KAnIG=cD!Nz`gr1)-s`Q8d!z2(mdDIRlBav!U9p)rVA}7|dEpixN#b8)
zN0T1UK#yncip?!@r=M1eUQ&v7gGJQ+q>;azDzoP2_MNh>IDE=_?;(1r*B;XTDQk8A
zDeKIAO8Opb>*-NngvS73r`E`mWK3FZ#QN~JWNii75I^>O1UL0sI7n#+jyEmXHU;Z>
z(W|`Y!*tIJhMsXS5J6<rWc|vQAg(u7X5vMkXerBKeq=}z^dO6X``+uZmL2gp1^~2W
zsK-f3%RovejYFTmCBK%*h51c7UtlCd-6Yt5S(sDk^<NX_RT=qwS{Qgc(wKhQMXSE9
zB=#zaJ#NQ&;eJwi9^)|UBkQpvg>Q{;uXBm;Ph6tvA(vSBbfSmWJ^eke=z2{_hjp)0
z90!dq6VSzlAj<~!b|um4idH=&e7|rxj_4F$+x;;D37D9Yc*zw7A+Z3h+o5*ZVYx$_
z(GL5*7M7hTc*sWf9m})I+LvSv5rnpwaOb`?GUz;{7XLfA)_47q*ZW=s_qRL<M4M^p
zM7Yfp%^*ieF68@D;6m;L-Xq4U#j+g-(pYtdES{iZi7bvl6kjyg?iR;<-H9*PE8>U`
zR+V+ZA9#cl5d-r&4g}$(b6@p|-+PN*b<Mxm9G>n;FkX*?&zxPh$2`Zxh5IlibMC`D
z0kcAmT;Gp=ful+SXFQI^$lpxirx8$xf`*wT9W{51l7GEJQ-t|rEDYnCqh9DdvqyUB
z$+A%_f~Vd?o_d_D7a`34M0#qItVcePp8E9l(q+Is9#ZM%V4HRNvvxYrtkZvG-wwz(
z?Iw?`)F}5WE0q;B_kUq!-@(Mx@ir{T)C~C@1&_qklk)q9{2r3uxcvSYUy6sd0Q1=J
zWI8gVxTVA*T)`tBCBm6%F+A_EMa=}D)-RzIYZUrD4iDQG`i9n^uAiCMIrAeYO`+-Z
znGpHV6w2O(C1Tns_ngM(VE_u$arE>dTa-tT6+{R^tlxx-#)&i&o%EbXkAZE;7#Lx1
z=|1%)oLQT3q?X2qRP<GUV`gmYAfg4Q^OvT`!c}zH7s`G<liIe9VQjC(3lzzs{tcv?
z<DoU`3)vVYmX`ofi?i?<2SOmO0#L6d#7v1O`1m@Be-A+I&Xc;Cp>EOG*m$hqWv%@;
z)Lw)3y_UBYYIlUrIf<<Y)Y%ZjxjA9&z8hXk{Q#Wl3MDd+h3p6o)U|Rhp+YXMCjGt$
zd5~JY07nheKa_YSVfh-^X^NzHk8&d9E}eD`Wyz>7sjEWD3T@7<?+Z&c`jj5;jz45B
zjSp8O`lFUbz^LC$hb&u1p{aS1g$@$aP*Xk4_z}!1daa!(e}STN>tQtr@k)<6w;obs
zQc&wR`zU$T1#yxLbbBOYhHBhdISUaw&`pyO>-ofp_z)QuZffAB*A=VBFf%a-Pf~&<
z-~0>Id}5D4Ja9;T4j$z~(_?6gBurs=z(eZ3oD{k;s8pk)_PMau8^NRWC=pIWTe9K@
z!(^pa=V$Id9x`_);ATL+4t%>4Aq#~XHzfs`l_E&!$|M>~tdBdKQF<J)Yl)_d3!&sC
zxw>2sF0P$~o=Ds%&>g}ZQ`izKHw|Aw>wN%v_lmu^BNHztUeOgRQ}U2q*KTrsaVdxO
zB|f-DeIFYvY*7XF6ZJ>eL&;^CCzoYt4O~3-W^#X1;vUQU?zON$q#j5Skv${Bh%V0J
zF`lJ%$Q@z%f3h99Y#(t!08c@^f@?m@4%woB+OkC!;V*moF6F=Qa{LQ5{^85=|KbJy
z6_@A#2mFoVGv(h!`!y*wY%*r~xui9bCm;Ggnzg$WZB=5HZ&0f^$D<}F6eMaVNY3<`
zLU}I~Vx{R;V=k<Tq7Z5DhOI~5<#df=Q~wAB!vp+jDu^Uvq8uaHJ_S1-?MtQ^?Psyt
z$N<)7f!<=L;jL~Zi}nw44wWt#;94j95r0fAkrME%VGDQkhsKx2N4WLpdE4eQ7JhGz
z=0A6uhR^E0SB+?WGu7v?P2sQqiuz7Wobng&hSOBw|2D(PYJH7<!=QsJHP49;U!lIK
zRWjAzqcHq#N`JKv81*;!=t%014S+<?xR=t6^BiuZ$UcYE5$FzEb7JHp6HXH-^DSws
za-Y7Oz=p51R||Q4BE88)Mn5zeLm4tYDH(-ef_abOk1I5(p-Cjq9DFc>MV*L3>Rb!-
z`cN(kn*Cd!vj}wV-uEJ%16Ehx7R!UEt6zms>R&K|u7&aHpjH_JoxP0W@X4*lPSEFE
z#l^c&s#6?8+GBnAN8qQXYcdvLbKeL#M{WbINyCwDHvo5<a8(j#eKbD2hKqusTj3WX
z{Rz?gyc1j^C+;lj-)Zu^((f(pMTC9=uWHSga0F4mZ^Syz@=dV$blbSR81M#7RF=o(
z{U1QG-3lnjxw7wh%$2DfI9s4vvbjR9=-K7F4{`o{i~H3?BHYRAEgdMpYHyJsH-FQ7
z`h#Y8)vg@$TRmSX4BvyC-}*~sJdb_8kf#rzn1Q%zqc@hjpGU{rJ@~6bp;(;jb@T+X
zMOjvQ4|3Q5-Hl8iehW?-sWqu&;@L7g#Mv04N;Ygc129dRcA<9XVB303{Ru=aJ&IkC
zv-x;9lRsSW2vmmIz%gm-x^dwzfMHvYh0L3ehR5Q-EyNB07zZGYm3)}t0}IyOLK-=S
z<hQh72|7mJzLUR#O!&h@7?(N+)V&yQ*h;sNvAiO*t3M_I_I1a()pdZbvNfM5_v@3i
zz0VF_9X~sm=$Gav_k>Ni4;zp83mJcL&JW(2^{pZr)^ctxfTJ(mhBUA+QE){8VcmrY
zIP(()xv1fSV>Xquv~tX6)9Q@sZiE{?+;X3=@lupa-TAz<$4ENC=>}9vjlmp!khq6O
zE!{LGY=HB#1E_wPs+hz|=@;k_$>))U>n1{n;fzGVy75M^L9T-$`jxk!Lt^Sz(Eyu?
z<@rz_sz!JK7xsCS`;w4+*k4H}ku0<Nj#j`WoyNzqP|}jmsN%7o+MSeqZF)Bj^@?N9
z)9~s&V2YJCivusuh)gwu9%J}MN{=eL2GFDqA$lQ1qF~>ZD2eZ?lH!|#B#b!VE{!J&
zo}?BqS->L=_IV(Wosg}P2!C&)dnkGT9gC^dfa-MONd;T!zC^+Ol67}KHOkA~Xg3W5
zyNyYtvg<J#mF^Ov-CIypmy%dQ>w&PQ7MEKU1#mlnmE>y@1!>@k;D@r^3cBBN@|b(X
z`e+}OISqQ`3T-rJqTmpU@M+m+j$a+0Y+-WozGEMNnh@@jwh-edeJ|o;{V=<>^=e{q
z%Nl^;30ychq8eEAVYP`wc#YHTq~p!NUoHs}=<Lz_cnYsM8n2>H@xrP6cX%bH{t%Nr
zIP|9vQe%&p<!NYyZVscSGrdR*<N>R~!yo}Syer9(Z|t3jU&Xd7jqkPm+iWeGw*J5+
zdiGj=fGTNK*)-A`@;AH0er419O|5>9OB{9Q^ov(Eox0248g_|6SI&MJHY@P9o8GTi
ze6CF&DB)0}vgwq+HPoc!yq<FmZM~)Yi1ogxd&Ipt?uz<wA7uI39GGQ)bmi%2)%nm;
z9?82E!zPqSzj^A&oe8TeYIy(@3*#9k7Mi}WHY1INCNFF!aFu1}x$_8hZR@V)IBMu0
zW^Ucl7tBF-6MB}Qr+f3!(4<XoGwX;I_lMS6)=8~qv|fSMT{t9IwCV(e`7`~&&Q2mi
zK9a{b3X!5KRqG3X8Y5Yzq0=8Aonn3A?eW3Zy_Ss#9VmU+YuSJjyr68lI=GA|t_ga<
z%!I4@KiYT>970t-JW#$pV?joEj<9&qBhsI>*Wy3{cFoSXRa?|@3u>V&BmK6$mMJL0
z3R%=*LkY1VT#Jl1rCpZB=UZk1k1(UJS372qkv@|T<xPE7e!ncgkIC-_`CXBM=d%2O
z{Ceg05&6~Vx61Ob<o7r7+b_RI<@Y=CtI>DJvc_M-uSS-6@Ze4p#j~`7E`2WC7bH$x
z+$Qg@tKji%T%0UDim;#rcDpS}lx#<Cb`n<_jkr&0=fYR3&N-P#$PNhvipdT<wzUKb
z9C|`cB!=EXi_>7f)#sG1dFW&O_2^&{txh|eNNn|KS{`~k*+%1WVG{Y$i{X~t=8feA
zM&zwcyQqR3kYV{5x+uq0Jk|#sWslN*o9IF{Zhf>z^Z*ZO{s*6DDm7-0>aatH4LYpQ
z;jKEHqQjA8TEACy7}w#Cb+}E3xjMZea@yy$(lt6X@So`QLpq$dRBH+8^`GjnP{+Tc
z*SG4>tHb+sXz<;j({Iz^S9NH#U#H7?s}9q2_>NBZm=2%Np-XRnMz2@uaJLQ(zVB2R
zB@Moy*MF?T?K=FwI^3ee4LWSsp}{4qgl#0}6xX4F|L?*nmTycV|1;flffG(sHV^e}
zI*P_6x(gIqiSUh}v*``wX$*e0#hT~ef_B311T4|%41P4OL01BLqN@h9rO;Ic>(=;h
zx0Trz+R8kNYq4^7x%=+&dux13<x)@ebY-S*hV64p|D*PqOJ)>jv+}lZbAye3k671?
zAAZ$^{5F4UTX;>Qt;OHc7Fa(S`7S+c{q>=?z=Fy<Y@xO`TXS3M8V#>~NA5IgTU^?D
zd}o>lZ8vJLs`ZPlZR=WX{*HQod#I_c)#%{<Z2DDo4TeOLc;kOW7YNj?x3&7$*_!>W
zYeJ30I%|=}H@8@Wgfo82i2E(p03~-W!Yh9`cgb%8iTHo$DXhIPek#kS6b-*qhpBC{
zOvZpm2eMpS3wv=f1|47aA^QH5_Q8}gbs`?dg99KzWhY+ZoBE`VJFgb|z>QXVFY}Pi
zI#b%KQNDC+>Pox}-l^kD{zRZZ1`SoW)Z#aq;0GJH>_f+VJf-~v%9oRYm=I5rnVwWR
zXq?n1RgPV?*sHJ^*w$qqqUR~?)hT7_L_CZqbzI_m(UZ^E4jW_g_owz2xm|X`QCtBc
z17|NOVFSSZF^TJti%Gv{EpDRUkJ>5yV6Zj$)79dVlKR!yx4Tf!qCVwIaeGmY8gzFt
z4%sy9=pvj)(hXdUlXQa@;VLBEiHmWPPQ3_MDd|Qo#z{K*{pw~cj`5pXviH*_qizq7
zY_xZ24{J2`4I4HztRk0mg6ne&gzD`cMUJ6fgu73UF_Ma_)aXVp!fA92{`q$>uHp{u
z_qc;z#@@v^THOwX<2T3pZ<LGu8V&tc`D;X@t-&0kc^0_w7jUJ7>jy4nt>zMr&bMZB
zvM=2VVAC>6p_uX8VcJ96jXKnE0`-klUlj}jB!3%i{Dzns$<1lM6}GP@lE3$iD;|qE
zX0w|bbJ%sJN$kpzaVM+;dGVa~?AkFUSrym7?r5FJhHbMoI1?~_wN^fbdqH~MwrTtQ
z-pLw%k~NKGEKMt+{?pNa0H-JMm}JXfwz*bzMPTfS-1eMWYOg@M@nHF--}nyJ!)YJ^
zM?i;VWBFHUe98goc|fmIJ3Su*5|2sQX)JqbhLoT9n{Wp=sUeq5s?1@N=4P`=fr54u
zZr%z)cpEZV!Q2d1FlXF}NqHt_UWMP5gHH$gk<7%`fK;Z(kkf_p+9@&GhxRFM>exno
zzA-&&=-2DiPR}1w<(#9*N#mK!7(b1%$(A%`nVZH2;0R9R-G*@{=bBk=2ysF~y2O11
z{9}YC4+lKaU5dM?KgLb1n=;Z_#$3GZ`gquA@o|iu#Cu-y#X6_dO_}K|b5(k68f2e5
zA%jggox#TbIhR>NIc)m`#(sl$<`R+zcAHW+rI}coF$TtC;CUV12AwvwZn9=DYbc#%
zLl(<i6B{SjXv{@xRIKanp(%{z-oV)G*`!ghrM?YW%!;+N&dF&v=zav6-FUf9XF}?m
zF(<9UG(L-s2mScUOg0{U#?Q%bA9Ga(y9)MsRbax2@$FaE8ayW08G8qB19%XWJeGoo
z95XXHrYYOZvcW5RPDZ<2%dapthSn6a8oZvKfo%LH#=Z?+1f_l|be?n4N=$iXmIoWn
z3uIJi<uNP|HX`|zfv&&;dwqcwn0B!Y>L=+lH5yG7^1Ef4RvCpayYxu|A|L*29^TX^
z9~JUD^cXf@i1N0n5_Qq1wpOdA(pBhVrV<)*Y`kPFqDjZQ9r(|Z#o$3_I6bN3jC_VX
z8r6mPFAaXz*rx<XG0u6C0eJFX*8noMs;REwfx3EsYyJ9~mby@&siU~X-?8r2xeQ=Y
zxV2tJu_e&6@w|a@qr#Xi1$PGJYT)L5&Y)uKj?cqIJK^6_aAivolK|JBg1eh?D)fCS
z1=kMT38IrSq8-nnN_?DD`t<Y9JXX`m|MomKU}@>N%O8RjwrC|!pysyH64tKO7T3$#
zCaqQxU_q?}EBKOD^0uvMs;_GfG6nVWfFGIMvi7<_(62Z6qzOwd%}uLXI*J>bn~{0K
zmfeAXFSw?X{+koE__Zb`((bIOMjBQl6GLY()Zld9t5jFt#~z^;E!C>=2Lf$@WMhT9
z%;iLU<y*GAykhp;5;+LFfz{NYdrin6XlZJNVAy>%<sBWBje)jx?h6UwSkM8z2>(gW
z&+A$nn*9O9Nz;MF9jU*?9}3V;Y-+7(YF*p*MSl(U<eD}90Gsh?ihw^94zwmIvWRm{
zu-#wZw7RLjrcq-~Cz2*vGApgAZ);yq|H<o8e1kt23bd_fQ}ve6`gT9$Slw2mx70K@
z1);$^pwX6~AEo8xORMg#^!VIKJ<Mk$d0lf;Lk(62lY~NQTH7R-);3LKie785j?GAC
z8`&h*BDK$0AzK~r`x(2Hcr=AbmF%_)<r+V`lhp+MjWw&Anu#r~ZmHJZgb_FRYg+5D
zRO@Q|t!tYCZLKZ1J*KEqa?>f=TKyeOp_)+Ls%DI|fYk*2YcMHr(_2;>UJv^5clhhW
zA-~b2b-E6+2SPPiVlcvgfvc&P1y<MIG^-^zYh6?8EVR$U|9cEIwfJW>&z?1VmS!ZE
zP&E4M+EbfZiTU$ke_(xuKd`zj&{Ef0@5jvr?#=@&KMnh)JRAsMMiqg!dVetJX<*}1
zu&^_KT?3Hp4}@K|9&>7`gaAr#QB$*@N^GLZ)fA+OYsB8BRe`#|`f_ML$STu4P`Re0
zWnO56gB|;sd1<J*ysjOF23a5qHqgHj&fC`Z#c;cELbzLDwv7FXT9!8jLgBjRs#Yih
z(masv3A+5N!eqo10e_H|<X<dRt(ti@BzFdcq=~YnmSz6XWt-c<O`m^TU=j8|<TAJ}
zaWB2w?Jb?7?Z;1_692?ps)6uhT3kW#0mVc&+cXN}@1QTQv>jdjJ1qyG7NVo4zx?9+
zp5i-|<(D|o%hDyikmgS>ODFl!omUN<M2+T%jV_-xe$rPtos#E2KmQ30<m1mqc()-J
zNzFqjKY0dkGw=kT#k&#Z)O?8Yq<zS_vVbQ@xz#l&r{-9xIT__<SB+=vr^u}ceg*Gt
zlnK6$cMxTQ<@odCyC~BiX1{|xN<}W5nom)lbrb#wJr83MoQ<~<WhdZz<eBF|Px&Y1
z-1*=`a4hoVYTzk<{yE-ul;eO-#KAvBen9XUy-cxj*JS7eG&=#`#rrkToCb7F(dY@b
zA*b4oaoYh;;XR1*X~6TykMcoJkpAEJdEg1g@H&B~T;ecZ;z@D*&Bz(3Ou0k1UdFvL
zdlPR3@FxJ-jf|~8nIP_(WqB@O3tp1H9dMgoCip|W{1o7TUMBb#y{rOyrfaf!0Xy*$
zAA;NTGQnebNwzlte>em8$0$Dq=(-8HAj$+A@e&QeZ|LPm0so|z{|xvMUgCcq@Tnr`
zjraf_z)Sd1z$<5J<!b=zX2IrwZvgxmUeeo6zz_8@?z`D-cxl{ufah+8EuoCRkFZ|6
z11Qs7!(Z`kT&&%n6wZc?VNEGtrd;^+5)D#LOJ#zTlg>k5g3sXHjPgJ7b1NnXl`xv-
z-FPc>c#jTO0$zzX2k$?he_Rci<<v}wzbOW18;zM7c!~{ZD_x2o0|E|Y^)|-ne*pYh
z>%bP&1%v*URn6;d9WBkR!G%+hrraK^Z}hj+1!uK1)d$*wZL34G>f2gwuM4&mubn-`
zhG@5GHPVme{y-3a3tKp4c5%s+JMyw^wgsU;I2iIE3;9oSE7kg;XAseQpeeLo^0DDr
z5b%E~j8Xgz6@jL;2#eSFgUQC!X15IdA&A$%*58ajx#7ETN?p(+ld`}RTewN7rzm{k
zl-0;b{ZsB(aC4IP#hsJ<Qz$+)`huG;l6Aq&$w{O8f}0I}-cg}cC@z=h?z^h1^}>Ir
z&YYBa!WTcj^YM8*oICiA#vScDI(BT^@z{>-JK{U~ckm}_pJ;r7)#6M8-MsC!+qZ1r
NwH?KOKK}q3`2SohCrSVS

literal 0
HcmV?d00001

diff --git a/code/texture_gui/code/functions/build_dictionary.m b/code/texture_gui/code/functions/build_dictionary.m
new file mode 100755
index 0000000..6750331
--- /dev/null
+++ b/code/texture_gui/code/functions/build_dictionary.m
@@ -0,0 +1,23 @@
+function dictionary = build_dictionary(image,dictionary_options)
+
+image = normalize_image(image);
+dictionary.options = dictionary_options;
+
+switch dictionary.options.method%dictionary_options.method
+    case 'euclidean'
+        dictionary.tree = build_km_tree(image,...
+            dictionary_options.patch_size,...
+            dictionary_options.branching_factor,...
+            dictionary_options.number_training_patches,...
+            dictionary_options.number_layers,...
+            dictionary_options.normalization);
+    case 'nxcorr'
+        dictionary.tree = build_km_tree_xcorr(image,...
+            dictionary_options.patch_size,...
+            dictionary_options.branching_factor,...
+            dictionary_options.number_training_patches,...
+            dictionary_options.number_layers);
+    otherwise
+        error('Unknown dictionary method.')
+        
+end
diff --git a/code/texture_gui/code/functions/build_km_tree.cpp b/code/texture_gui/code/functions/build_km_tree.cpp
new file mode 100755
index 0000000..a1e1116
--- /dev/null
+++ b/code/texture_gui/code/functions/build_km_tree.cpp
@@ -0,0 +1,421 @@
+/*=================================================================
+* syntax: T = build_km_tree(I, M, b, t, L, n); OR T = build_km_tree(I, M, b, t, L);
+*
+* build_km_tree  - build km-tree matrix from image
+* 			
+* 			Input: 	- I: X-by-Y intensity image
+* 					- M: patch size (length of edge)
+*                   - L: number of dictionary layers. This parameter is limited 
+*                        such that the average number of patches in a leafnode is 
+*                        greater than five
+*                   - b: branching factor
+*                   - t: number of training patches
+*                   - n: normalization (true or false), defaults to false
+*
+* 			Output: - T: MMl-by-K matrix where l is the number of layers 
+*                        in the image (1 for grayscale and 3 for RGB)
+*                        and K is the number of nodes in the tree.
+*
+* 			Author: Anders Dahl, abda@dtu.dk, december 2015.
+*=================================================================*/
+
+#include "mex.h"
+#include <stdio.h>
+#include <math.h>
+#include "matrix.h"
+#include <vector>
+#include <algorithm>
+
+#include <iostream>
+using namespace std;
+
+// struct for image
+struct im_st
+{
+    double *im_data; // pointer to image data
+    int rows, cols, layers, n_pix; // rows, cols and layers are the image dimensions and n_pix = rows*cols
+};
+
+// struct for the tree
+struct tree_st
+{
+    double *tree_data;
+    int n_dim, n_nodes, branch_fac, M, Mh;
+};
+
+// struct for image patches
+struct im_patch
+{
+    double *patch_data; // pointer to the data
+    int idx; // id used for sorting the patches according to the tree
+    bool operator<(const im_patch& rhs) const {return idx < rhs.idx;} // operator needed for sorting
+};
+
+
+// Function for sampling patches from the image into the patch arrays
+// inputs reference to the image struct, tree struct, patch struct and position of the sampling coordinate.
+// There is no check if the sampling is outside the image
+void sample_patch(im_st& im, tree_st& tree, im_patch& patch, int r_im, int c_im, bool normalize)
+{
+    int id_l, id_r, id_i; // iterators for looking up image data
+    int id_p = 0; // iterator for looking up patch data
+    double sum_sq = 0, pix_val; // variables for normalization
+    
+    for ( int l = 0; l < im.layers; l++ ){ // image is sampled by three nested loops
+        id_l = im.n_pix*l;
+        for ( int i = c_im-tree.Mh; i <= c_im+tree.Mh; i++ ){
+            id_r = id_l + i*im.rows;
+            for ( int j = r_im-tree.Mh; j <= r_im+tree.Mh; j++ ){
+                id_i = id_r + j;
+                pix_val = *(im.im_data + id_i);
+                *(patch.patch_data + id_p) = pix_val;
+                sum_sq += pix_val*pix_val;
+                id_p++;
+            }
+        }
+    }
+    
+    if ( normalize ){ // normalization to unit length
+        double inv_sq = 1;
+        if ( sum_sq > 0 ){
+            inv_sq = 1/sqrt(sum_sq); // divide by sum of squares
+        }
+        for ( int i = 0; i < tree.n_dim; i++ ){
+            *(patch.patch_data + i) = (*(patch.patch_data + i))*inv_sq;
+        }
+    }
+
+    
+}
+
+
+// function for randomly permuted set of indices
+// n is the numbers to choose from, n_set is the number of random indices
+// that is returned. Returns a vector of indices
+vector<int> randperm( int n, int n_set ) {
+    if ( n_set > n ){ // check if n_set exceeds n
+        n_set = n;
+    }
+    
+    vector<int> rid;
+    rid.reserve(n); // vector of indices
+    for ( int i = 0; i < n; i++ ){ // set all indices in order
+        rid.push_back(i);
+    }
+    
+    int t, id; // place holders for id and temporary number
+    int r_max = RAND_MAX; // maximum random number
+    for ( int i = 0; i < n_set; i++ ){
+        // choose a random number between i and n-1 and swap place between i and id
+        if ( LONG_MAX > RAND_MAX && n-i-1>RAND_MAX ){ // not enough with a random integer up til RAND_MAX
+            id = ((rand()*(r_max+1)+rand()) % (n-i)) + i; 
+        }
+        else{
+            id = (rand() % (n-i)) + i; 
+        }
+        t = rid[id];
+        rid[id] = rid[i];
+        rid[i] = t;
+    }
+    rid.resize(n_set); // set size to n_set
+    return rid;
+}
+
+
+// copy values from a patch array into the tree array at node
+void set_values(tree_st& tree, im_patch& patch, int node){
+    int idx = tree.n_dim*node;
+    for ( int i = 0; i < tree.n_dim; i++ ){
+        *(tree.tree_data + idx) = *(patch.patch_data + i);
+        idx++;
+    }
+}
+
+// add values to vector of cluster center points
+void add_values(vector<double>& center_sum, im_patch& patch, int id, int n_dim){
+    int idx = n_dim*id;
+    for ( int i = 0; i < n_dim; i++ ){
+        center_sum[idx] += *(patch.patch_data + i);
+        idx++;
+    }
+}
+
+// estimates the squared Euclidian distance between an image patch and a tree node
+double get_dist(tree_st& tree, im_patch& patch, int node)
+{
+    double d = 0, tmp;
+    int id = tree.n_dim*node;
+    
+    for ( int i = 0; i < tree.n_dim; i++ ){
+        tmp = *(tree.tree_data + id) - *(patch.patch_data + i);
+        d += tmp*tmp;
+        id++;
+        
+    }
+    
+    return d;
+}
+
+// k-means-function taking a reference to the vector of image patches and a
+// tree struct as input f and t gives the image patches that should be clustered.
+// node is the first node in the tree included in the clustering
+void k_means( vector<im_patch>& patches, tree_st& tree, int f, int t, int node )
+{
+    // vectors holding the sum of values in the cluster and a vector containing the change
+    vector<double> centSum(tree.branch_fac*tree.n_dim), centChange(tree.branch_fac);
+    vector<int> centCount(tree.branch_fac); // vector for counting the number of points in a cluster
+    double min_d, d, tmp;//, diff; // variables for clustering
+    // variables for cluster id and index of previous cluseter, which will be overwritten by new cluster id
+    int id = 0, id_in = patches[f].idx;
+    
+    if ( t-f > tree.branch_fac ){ // check if there are enough point to carry out the clustering
+        // initialize the center positions
+        for (  int i = 0; i < tree.branch_fac; i++ ){
+            set_values(tree, patches[f+i], node+i);
+        }
+        
+        // run clutering for 20 iterations - only little change happens after 10 iterations
+        for ( int n_run = 0; n_run < 30; n_run++){
+            
+            for ( int i = f; i < t; i++ ){ // go through the patches from f to t
+                min_d = get_dist(tree, patches[i], node); // initially set min distance and id to the first
+                id = 0;
+                for ( int j = 1; j < tree.branch_fac; j++ ){ // run throgh the other points
+                    d = get_dist(tree, patches[i], node + j); // get the distance
+                    if ( d < min_d ){ // if the this cluster is closer set this as min distance
+                        min_d = d;
+                        id = j;
+                    }
+                }
+                add_values(centSum, patches[i], id, tree.n_dim); // add the patch to the closest cluster
+                centCount[id]++; // count the extra patch
+                // update the idx to the child idx - note that all layers start with idx = 0
+                patches[i].idx = (id + id_in*tree.branch_fac);
+            }
+            
+            // update the clusters in the tree and calculate the center change (not used for anything)
+            id = node*tree.n_dim;
+            int id_c = 0;
+            
+            for ( int i = 0; i < tree.branch_fac; i++ ){ // go through all new clusters
+                if ( centCount[i] == 0 ){
+                    centCount[i] = 1;
+                }
+                for ( int j = 0; j < tree.n_dim; j++ ){ // go through cluster pixels
+                    tmp = centSum[id_c]/centCount[i];
+                    //diff = (tmp - *(tree.tree_data + id)); // for calculating center change
+                    //centChange[i] += diff*diff;
+                    *(tree.tree_data + id) = tmp;
+                    id_c++;
+                    id++;
+                }
+            }
+            
+            // set counter and sum to zero
+            fill(centSum.begin(), centSum.end(), 0);
+            fill(centCount.begin(), centCount.end(),0);
+            fill(centChange.begin(), centChange.end(), 0);
+        }
+    }
+}
+
+// runs through the patches vector to find the last element with id
+int get_to( vector<im_patch>& patches, int id )
+{
+    int to = 0;
+    for ( int i = 0; i < patches.size(); i++ ){
+        if ( patches[i].idx == id ){
+            to = i;
+        }
+    }
+    return to+1;
+}
+
+// Main function for building the km-tree. Takes the image and tree struct
+// and the number of training patches as argument
+void build_km_tree ( im_st& im, tree_st& tree, int n_train, bool normalize ) {
+    // allocate memory for the image patches
+    double* im_patch_data = new double[n_train*tree.M*tree.M*im.layers];
+    
+    int rows_c = im.rows-tree.M+1, cols_c = im.cols-tree.M+1; // number of rows and cols within sampling area
+    int n_im_patches = rows_c*cols_c; // number of pixels in the image for sampling - inside boundary
+    
+    // checks that the number of training patches is not exceeding the number of pixels in the sample area
+    if ( n_im_patches < n_train ){
+        n_train = n_im_patches;
+    }
+    
+    vector<int> r_id = randperm(n_im_patches, n_train); // indices of random patches
+    
+    vector<im_patch> patches; // vector of image patches
+    patches.resize(n_train); // allocate memory
+    
+    int r, c, idx = 0; // variables used for sampling the image
+    // sample image patches
+    for (int i = 0; i < n_train; i++ )
+    {
+        c = r_id[i]/rows_c; // column is floored because of int
+        r = r_id[i]-c*rows_c; // row is rest after column
+        patches[i].idx = 0; // inital id is 0
+        patches[i].patch_data = im_patch_data + idx; // pointer to patch memory
+        sample_patch(im, tree, patches[i], r + tree.Mh, c + tree.Mh, normalize); // sampel in image with added boundary
+        idx += tree.n_dim; // step number of patch pixels forward
+    }
+    
+    // k-means tree
+    int n_layer = (int)ceil(log((double)tree.n_nodes)/log((double)tree.branch_fac)); // number of layers in the tree
+    int n_in_layer; // number of nodes in layer
+    int t, f; // keeps track of patches that belong to a certain cluster
+    int node = 0; // node number that will be updated
+    
+    // go through the layers in the tree
+    for (int i = 0; i < n_layer; i++ )
+    {
+        t = 0; // start at 0
+        n_in_layer = pow((double)tree.branch_fac,i); // number of nodes in current layer of the tree
+        sort(patches.begin(), patches.end()); // sort the patches according to their current id
+        for ( int j = 0; j < n_in_layer; j++ ) // go through the nodes in the layer and cluster that node
+        {
+            f = t; // patch j from
+            t = get_to(patches,j); // patch j to
+            // check that the node does not exceed the size of the tree
+            if ( node + tree.branch_fac <= tree.n_nodes ){
+                k_means( patches, tree, f, t, node );
+            }
+            else {
+                break;
+            }
+            node += tree.branch_fac; // next node
+        }
+    }
+    
+    delete[] im_patch_data; // free up patch memory
+}
+
+
+// The gateway routine
+void mexFunction( int nlhs, mxArray *plhs[],
+        int nrhs, const mxArray *prhs[])
+{
+    // input image (I), patch size (M*M), number of nodes in the tree (n), branching
+    // factor (b), and number of training patches (n_train). Outputs the km-tree (tree)
+    double *I, *tree; // pointers to image and tree
+    int b, M, L, n, ndim, n_train; // variables
+    const int *dim; // image dimensinos
+    int dtree[2]; // tree dimensions
+    bool normalize = false; // decide if vectors of image patches should be normalized to unit length
+    
+    /*  Check for proper number of arguments. */
+    /* NOTE: You do not need an else statement when using
+     mexErrMsgTxt within an if statement. It will never
+     get to the else statement if mexErrMsgTxt is executed.
+     (mexErrMsgTxt breaks you out of the MEX-file.)
+     */
+    if(nrhs < 5 || nrhs > 6)
+        mexErrMsgTxt("Five or six inputs required.");
+    if(nlhs != 1)
+        mexErrMsgTxt("One output required.");
+    
+    if ( !mxIsDouble(prhs[0]) )
+        mexErrMsgTxt("Image should be double!");
+    
+    // Create a pointer to the input matrix.
+    I = mxGetPr(prhs[0]);
+    
+    // input passing
+    double *Md, *bd, *Ld, *n_train_d;
+    Md = mxGetPr(prhs[1]);
+    M = (int)Md[0];
+    
+    bd = mxGetPr(prhs[2]);
+    b = (int)bd[0];
+    
+    // check if number of clusters is smaller than branching factor
+    if ( n < b ){
+        n = b;
+    }
+    
+    n_train_d = mxGetPr(prhs[3]);
+    n_train = (int)n_train_d[0];
+    
+    // determine number of tree nodes
+    Ld = mxGetPr(prhs[4]);
+    L = (int)Ld[0]; // layers in tree
+    n = 0;
+    int n_tmp = 0;
+    int max_n = (double)n_train/1.0;
+//     int max_n = (double)n_train/5.0;
+    for ( int i = 0; i < L; i++ ){
+        n_tmp += pow((double)b,(i+1));
+        if ( n_tmp > max_n ){
+            L = i+1;
+            break;
+        }
+        n = n_tmp;
+    }
+    printf("Number of nodes in resulting tree: %d in %d layers.\n", n, L);
+    
+    if ( nrhs == 6 ){
+        bool *normalize_d;
+        normalize_d = (bool *)mxGetData(prhs[5]);
+        normalize = normalize_d[0];
+    }
+    
+    // check input properties
+    if ( 1 - (M % 2)  || M < 1)
+        mexErrMsgTxt("M must be odd and positive.");
+    
+    if ( n < 1 )
+        mexErrMsgTxt("n must be positive.");
+    
+    if ( b < 1 )
+        mexErrMsgTxt("b must be positive.");
+    
+    // Get the dimensions of the matrix input.
+    ndim = mxGetNumberOfDimensions(prhs[0]);
+    if (ndim != 2 && ndim != 3)
+        mexErrMsgTxt("search_km_tree only works for 2-dimensional or 3-dimensional images.");
+    
+    // image dimensions
+    dim = mxGetDimensions(prhs[0]);
+    
+    
+    // image struct
+    im_st Im;
+    Im.im_data = I;
+    Im.rows = dim[0];
+    Im.cols = dim[1];
+    if ( ndim == 3 )
+    {
+        Im.layers = dim[2];
+    }
+    else
+    {
+        Im.layers = 1;
+    }
+    Im.n_pix = Im.rows*Im.cols;
+    
+    dtree[0] = Im.layers*M*M;
+    dtree[1] = n;
+    
+    // Set the output pointer to the output matrix. Array initialized to zero.
+    plhs[0] = mxCreateNumericArray(2, dtree, mxDOUBLE_CLASS, mxREAL);
+    
+    // Create a C pointer to a copy of the output matrix.
+    tree = mxGetPr(plhs[0]);
+    for (int i = 0; i < dtree[0]*dtree[1]; i++ )
+        *(tree + i) = -1;
+    
+    // tree struct
+    tree_st Tree;
+    Tree.tree_data = tree;
+    Tree.n_dim = dtree[0];
+    Tree.n_nodes = dtree[1];
+    Tree.branch_fac = b;
+    Tree.M = M;
+    Tree.Mh = (int)(0.5*((double)M-1.0));
+    
+    // build the km-tree using C++ subroutine
+    build_km_tree ( Im, Tree, n_train, normalize );
+    
+}
diff --git a/code/texture_gui/code/functions/build_km_tree.mexa64 b/code/texture_gui/code/functions/build_km_tree.mexa64
new file mode 100755
index 0000000000000000000000000000000000000000..64f090ccc0f775fd55f0c576b8e29df61ad8ff29
GIT binary patch
literal 19188
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

literal 0
HcmV?d00001

diff --git a/code/texture_gui/code/functions/build_km_tree.mexmaci64 b/code/texture_gui/code/functions/build_km_tree.mexmaci64
new file mode 100755
index 0000000000000000000000000000000000000000..af834dcdddc581cf19474646a2383c938c2441ca
GIT binary patch
literal 23416
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

literal 0
HcmV?d00001

diff --git a/code/texture_gui/code/functions/build_km_tree.mexw64 b/code/texture_gui/code/functions/build_km_tree.mexw64
new file mode 100755
index 0000000000000000000000000000000000000000..fc2e3cefa7e292a1cc3fd9baf7d06414b15fa888
GIT binary patch
literal 26112
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

literal 0
HcmV?d00001

diff --git a/code/texture_gui/code/functions/build_km_tree_xcorr.cpp b/code/texture_gui/code/functions/build_km_tree_xcorr.cpp
new file mode 100755
index 0000000..0e15bbf
--- /dev/null
+++ b/code/texture_gui/code/functions/build_km_tree_xcorr.cpp
@@ -0,0 +1,427 @@
+/*=================================================================
+* syntax: T = build_km_tree_xcorr(I, M, L, b, t);
+*
+* build_km_tre:xcorr  - build km-tree matrix from image based on cross correlation
+* 			
+* 			Input: 	- I: X-by-Y intensity image
+* 					- M: patch size (length of edge)
+*                   - L: number of dictionary layers. This parameter is limited 
+*                        such that the average number of patches in a leafnode is 
+*                        greater than five
+*                   - b: brancing factor
+*                   - t: number of training patches
+*
+* 			Output: - T: MMl-by-K matrix where l is the number of layers 
+*                        in the image (1 for grayscale and 3 for RGB)
+*                        and K is the number of nodes in the tree. 
+*
+* 			Author: Anders Dahl, abda@dtu.dk, december 2015.
+*=================================================================*/
+
+#include "mex.h"
+#include <stdio.h>
+#include <math.h>
+#include "matrix.h"
+#include <vector>
+#include <algorithm>
+
+#include <iostream>
+using namespace std;
+
+// struct for image
+struct im_st
+{
+    double *im_data; // pointer to image data
+    int rows, cols, layers, n_pix; // rows, cols and layers are the image dimensions and n_pix = rows*cols
+};
+
+// struct for the tree
+struct tree_st
+{
+    double *tree_data;
+    int n_dim, n_nodes, branch_fac, M, Mh;
+    double inv_ndim;
+};
+
+// struct for image patches
+struct im_patch
+{
+    double *patch_data; // pointer to the data
+    int idx; // id used for sorting the patches according to the tree
+    bool operator<(const im_patch& rhs) const {return idx < rhs.idx;} // operator needed for sorting
+};
+
+// nomalize patch vectors to zero mean and unit Euclidean length
+void norm_patch(double* patch_data, double& mu, int n_dim){
+    
+    double sum_sq = 0;
+    
+    for ( int i = 0; i < n_dim; i++ ){
+        *(patch_data + i) = *(patch_data + i) - mu;
+        sum_sq += (*(patch_data + i))*(*(patch_data + i));
+    }
+    
+    double inv_sq = 1;
+    if ( sum_sq > 0 ){
+        inv_sq = 1.0/sqrt(sum_sq); // divide by sum of squares
+    }
+
+    for ( int i = 0; i < n_dim; i++ ){
+        *(patch_data + i) = (*(patch_data + i))*inv_sq;
+    }
+}
+
+
+// Function for sampling patches from the image into the patch arrays
+// inputs reference to the image struct, tree struct, patch struct and position of the sampling coordinate.
+// There is no check if the sampling is outside the image
+void sample_patch(im_st& im, tree_st& tree, im_patch& patch, int r_im, int c_im)
+{
+    int id_l, id_r, id_i; // iterators for looking up image data
+    int id_p = 0; // iterator for looking up patch data
+    double sum_sq = 0, sum = 0, pix_val, mu, tmp; // variables for normalization
+    
+    for ( int l = 0; l < im.layers; l++ ){ // image is sampled by three nested loops
+        id_l = im.n_pix*l;
+        for ( int i = c_im-tree.Mh; i <= c_im+tree.Mh; i++ ){
+            id_r = id_l + i*im.rows;
+            for ( int j = r_im-tree.Mh; j <= r_im+tree.Mh; j++ ){
+                id_i = id_r + j;
+                pix_val = *(im.im_data + id_i);
+                *(patch.patch_data + id_p) = pix_val;
+                sum += pix_val;
+                id_p++;
+            }
+        }
+    }
+    
+    mu = sum*tree.inv_ndim;
+    
+    norm_patch(patch.patch_data, mu, tree.n_dim);
+}
+
+
+// function for randomly permuted set of indices
+// n is the numbers to choose from, n_set is the number of random indices
+// that is returned. Returns a vector of indices
+vector<int> randperm( int n, int n_set ) {
+    if ( n_set > n ){ // check if n_set exceeds n
+        n_set = n;
+    }
+    
+    vector<int> rid;
+    rid.reserve(n); // vector of indices
+    for ( int i = 0; i < n; i++ ){ // set all indices in order
+        rid.push_back(i);
+    }
+    
+    int t, id; // place holders for id and temporary number
+    int r_max = RAND_MAX; // maximum random number
+    for ( int i = 0; i < n_set; i++ ){
+        // choose a random number between i and n-1 and swap place between i and id
+        if ( LONG_MAX > RAND_MAX && n-i-1>RAND_MAX ){ // not enough with a random integer up til RAND_MAX
+            id = ((rand()*(r_max+1)+rand()) % (n-i)) + i; 
+        }
+        else{
+            id = (rand() % (n-i)) + i; 
+        }
+        t = rid[id];
+        rid[id] = rid[i];
+        rid[i] = t;
+    }
+    rid.resize(n_set); // set size to n_set
+    return rid;
+}
+
+
+// copy values from a patch array into the tree array at node
+void set_values(tree_st& tree, im_patch& patch, int node){
+    int idx = tree.n_dim*node;
+    for ( int i = 0; i < tree.n_dim; i++ ){
+        *(tree.tree_data + idx) = *(patch.patch_data + i);
+        idx++;
+    }
+}
+
+// add values to vector of cluster center points
+void add_values(vector<double>& center_sum, im_patch& patch, int id, int n_dim){
+    int idx = n_dim*id;
+    for ( int i = 0; i < n_dim; i++ ){
+        center_sum[idx] += *(patch.patch_data + i);
+        idx++;
+    }
+}
+
+// estimates the normalized cross correlation between an image patch and a tree node
+double get_corr(tree_st& tree, im_patch& patch, int node)
+{
+    double corr = 0, tmp_t, tmp_p;
+    int id = tree.n_dim*node;
+    
+    for ( int i = 0; i < tree.n_dim; i++ ){
+        tmp_t = *(tree.tree_data + id);
+        tmp_p = *(patch.patch_data + i);
+        corr += tmp_t*tmp_p;
+        id++;   
+    }
+    
+    return corr;
+}
+
+// k-means-function taking a reference to the vector of image patches and a
+// tree struct as input f and t gives the image patches that should be clustered.
+// node is the first node in the tree included in the clustering
+void k_means( vector<im_patch>& patches, tree_st& tree, int f, int t, int node )
+{
+    // vectors holding the sum of values in the cluster and a vector containing the change
+    vector<double> centSum(tree.branch_fac*tree.n_dim), centChange(tree.branch_fac);
+    vector<int> centCount(tree.branch_fac); // vector for counting the number of points in a cluster
+    double max_corr, corr, tmp, mu, sum;//, diff; // variables for clustering
+    // variables for cluster id and index of previous cluseter, which will be overwritten by new cluster id
+    int id = 0, id_in = patches[f].idx;
+    
+    if ( t-f > tree.branch_fac ){ // check if there are enough point to carry out the clustering
+        // initialize the center positions
+        for (  int i = 0; i < tree.branch_fac; i++ ){
+            set_values(tree, patches[f+i], node+i);
+        }
+        
+        // run clutering for 10 iterations - only little change happens after 10 iterations
+        for ( int n_run = 0; n_run < 10; n_run++){
+            
+            for ( int i = f; i < t; i++ ){ // go through the patches from f to t
+                max_corr = get_corr(tree, patches[i], node); // initially set min distance and id to the first
+                id = 0;
+                for ( int j = 1; j < tree.branch_fac; j++ ){ // run throgh the other points
+                    corr = get_corr(tree, patches[i], node + j); // get the cross correlation
+                    if ( corr > max_corr ){ // if the this cluster is closer set this as max correlation
+                        max_corr = corr;
+                        id = j;
+                    }
+                }
+                add_values(centSum, patches[i], id, tree.n_dim); // add the patch to the closest cluster
+                centCount[id]++; // count the extra patch
+                // update the idx to the child idx - note that all layers start with idx = 0
+                patches[i].idx = (id + id_in*tree.branch_fac);
+            }
+            
+            // update the clusters in the tree and calculate the center change (not used for anything)
+            id = node*tree.n_dim;
+            int id_c = 0;
+            
+            
+            for ( int i = 0; i < tree.branch_fac; i++ ){ // go through all new clusters
+                sum = 0;
+                if ( centCount[i] == 0 ){
+                    centCount[i] = 1;
+                }
+                for ( int j = 0; j < tree.n_dim; j++ ){ // go through cluster pixels
+                    tmp = centSum[id_c]/centCount[i];
+                    //diff = (tmp - *(tree.tree_data + id)); // for calculating center change
+                    //centChange[i] += diff*diff;
+                    *(tree.tree_data + id) = tmp;
+                    sum += tmp;
+                    id_c++;
+                    id++;
+                }
+                mu = sum*tree.inv_ndim;
+                norm_patch(tree.tree_data+id-tree.n_dim, mu, tree.n_dim);
+            }
+            
+            // set counter and sum to zero
+            fill(centSum.begin(), centSum.end(), 0);
+            fill(centCount.begin(), centCount.end(),0);
+            fill(centChange.begin(), centChange.end(), 0);
+        }
+    }
+}
+
+// runs through the patches vector to find the last element with id
+int get_to( vector<im_patch>& patches, int id )
+{
+    int to = 0;
+    for ( int i = 0; i < patches.size(); i++ ){
+        if ( patches[i].idx == id ){
+            to = i;
+        }
+    }
+    return to+1;
+}
+
+// Main function for building the km-tree. Takes the image and tree struct
+// and the number of training patches as argument
+void build_km_tree ( im_st& im, tree_st& tree, int n_train ) {
+    // allocate memory for the image patches
+    double* im_patch_data = new double[n_train*tree.M*tree.M*im.layers];
+    
+    int rows_c = im.rows-tree.M+1, cols_c = im.cols-tree.M+1; // number of rows and cols within sampling area
+    int n_im_patches = rows_c*cols_c; // number of pixels in the image for sampling - inside boundary
+    
+    // checks that the number of training patches is not exceeding the number of pixels in the sample area
+    if ( n_im_patches < n_train ){
+        n_train = n_im_patches;
+    }
+    
+    vector<int> r_id = randperm(n_im_patches, n_train); // indices of random patches
+    
+    vector<im_patch> patches; // vector of image patches
+    patches.resize(n_train); // allocate memory
+    
+    int r, c, idx = 0; // variables used for sampling the image
+    // sample image patches
+    for (int i = 0; i < n_train; i++ )
+    {
+        c = r_id[i]/rows_c; // column is floored because of int
+        r = r_id[i]-c*rows_c; // row is rest after column
+        patches[i].idx = 0; // inital id is 0
+        patches[i].patch_data = im_patch_data + idx; // pointer to patch memory
+        sample_patch(im, tree, patches[i], r + tree.Mh, c + tree.Mh); // sampel in image with added boundary
+        idx += tree.n_dim; // step number of patch pixels forward
+    }
+    
+    // k-means tree
+    int n_layer = (int)ceil(log((double)tree.n_nodes)/log((double)tree.branch_fac)); // number of layers in the tree
+    int n_in_layer; // number of nodes in layer
+    int t, f; // keeps track of patches that belong to a certain cluster
+    int node = 0; // node number that will be updated
+    
+    // go through the layers in the tree
+    for (int i = 0; i < n_layer; i++ )
+    {
+        t = 0; // start at 0
+        n_in_layer = pow((double)tree.branch_fac,i); // number of nodes in current layer of the tree
+        sort(patches.begin(), patches.end()); // sort the patches according to their current id
+        for ( int j = 0; j < n_in_layer; j++ ) // go through the nodes in the layer and cluster that node
+        {
+            f = t; // patch j from
+            t = get_to(patches,j); // patch j to
+            // check that the node does not exceed the size of the tree
+            if ( node + tree.branch_fac <= tree.n_nodes ){
+                k_means( patches, tree, f, t, node );
+            }
+            else {
+                break;
+            }
+            node += tree.branch_fac; // next node
+        }
+    }
+    
+    delete[] im_patch_data; // free up patch memory
+}
+
+
+// The gateway routine
+void mexFunction( int nlhs, mxArray *plhs[],
+        int nrhs, const mxArray *prhs[])
+{
+    // input image (I), patch size (M*M), number of nodes in the tree (n), branching
+    // factor (b), and number of training patches (n_train). Outputs the km-tree (tree)
+    double *I, *tree; // pointers to image and tree
+    int b, M, L, n, ndim, n_train; // variables
+    const int *dim; // image dimensinos
+    int dtree[2]; // tree dimensions
+    
+    /*  Check for proper number of arguments. */
+    /* NOTE: You do not need an else statement when using
+     mexErrMsgTxt within an if statement. It will never
+     get to the else statement if mexErrMsgTxt is executed.
+     (mexErrMsgTxt breaks you out of the MEX-file.)
+     */
+    if(nrhs != 5)
+        mexErrMsgTxt("Five inputs required.");
+    if(nlhs != 1)
+        mexErrMsgTxt("One output required.");
+    
+    // Create a pointer to the input matrix.
+    I = mxGetPr(prhs[0]);
+    
+    // input passing
+    double *Md, *bd, *Ld, *n_train_d;
+    Md = mxGetPr(prhs[1]);
+    M = (int)Md[0];
+    
+    bd = mxGetPr(prhs[2]);
+    b = (int)bd[0];
+    
+    // check if number of clusters is smaller than branching factor
+    if ( n < b ){
+        n = b;
+    }
+    
+    n_train_d = mxGetPr(prhs[3]);
+    n_train = (int)n_train_d[0];
+    
+    // determine number of tree nodes
+    Ld = mxGetPr(prhs[4]);
+    L = (int)Ld[0]; // layers in tree
+    n = 0;
+    int n_tmp = 0;
+    int max_n = (double)n_train/5.0;
+    for ( int i = 0; i < L; i++ ){
+        n_tmp += pow((double)b,(i+1));
+        if ( n_tmp > max_n ){
+            L = i+1;
+            break;
+        }
+        n = n_tmp;
+    }
+    printf("Number of nodes in resulting tree: %d in %d layers.\n", n, L);
+        
+    // check input properties
+    if ( 1 - (M % 2)  || M < 1)
+        mexErrMsgTxt("M must be odd and positive.");
+    
+    if ( n < 1 )
+        mexErrMsgTxt("n must be positive.");
+    
+    if ( b < 1 )
+        mexErrMsgTxt("b must be positive.");
+    
+    // Get the dimensions of the matrix input.
+    ndim = mxGetNumberOfDimensions(prhs[0]);
+    if (ndim != 2 && ndim != 3)
+        mexErrMsgTxt("search_km_tree only works for 2-dimensional or 3-dimensional images.");
+    
+    // image dimensions
+    dim = mxGetDimensions(prhs[0]);
+    
+    
+    // image struct
+    im_st Im;
+    Im.im_data = I;
+    Im.rows = dim[0];
+    Im.cols = dim[1];
+    if ( ndim == 3 )
+    {
+        Im.layers = dim[2];
+    }
+    else
+    {
+        Im.layers = 1;
+    }
+    Im.n_pix = Im.rows*Im.cols;
+    
+    dtree[0] = Im.layers*M*M;
+    dtree[1] = n;
+    
+    // Set the output pointer to the output matrix. Array initialized to zero.
+    plhs[0] = mxCreateNumericArray(2, dtree, mxDOUBLE_CLASS, mxREAL);
+    
+    // Create a C pointer to a copy of the output matrix.
+    tree = mxGetPr(plhs[0]);
+    for (int i = 0; i < dtree[0]*dtree[1]; i++ )
+        *(tree + i) = -1;
+    
+    // tree struct
+    tree_st Tree;
+    Tree.tree_data = tree;
+    Tree.n_dim = dtree[0];
+    Tree.inv_ndim = 1/(double)Tree.n_dim;
+    Tree.n_nodes = dtree[1];
+    Tree.branch_fac = b;
+    Tree.M = M;
+    Tree.Mh = (int)(0.5*((double)M-1.0));
+    // build the km-tree using C++ subroutine
+    build_km_tree ( Im, Tree, n_train );
+    
+}
diff --git a/code/texture_gui/code/functions/build_km_tree_xcorr.mexa64 b/code/texture_gui/code/functions/build_km_tree_xcorr.mexa64
new file mode 100755
index 0000000000000000000000000000000000000000..4f23c01adc36f93d1ea6e2b3a2df0915bac3247f
GIT binary patch
literal 19157
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
K{w<LFdi)=mfd0n-

literal 0
HcmV?d00001

diff --git a/code/texture_gui/code/functions/build_km_tree_xcorr.mexmaci64 b/code/texture_gui/code/functions/build_km_tree_xcorr.mexmaci64
new file mode 100755
index 0000000000000000000000000000000000000000..592f56e947462978fc07a59c067768e67277fcc6
GIT binary patch
literal 23344
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

literal 0
HcmV?d00001

diff --git a/code/texture_gui/code/functions/build_km_tree_xcorr.mexw64 b/code/texture_gui/code/functions/build_km_tree_xcorr.mexw64
new file mode 100755
index 0000000000000000000000000000000000000000..a0b030b73702276a175b4c59a684ad0e0d2e5ff6
GIT binary patch
literal 27136
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
D6!K%N

literal 0
HcmV?d00001

diff --git a/code/texture_gui/code/functions/compile_mex_functions.m b/code/texture_gui/code/functions/compile_mex_functions.m
new file mode 100755
index 0000000..bab817b
--- /dev/null
+++ b/code/texture_gui/code/functions/compile_mex_functions.m
@@ -0,0 +1,8 @@
+% compile mex files
+mex -largeArrayDims biadjacency_matrix.cpp
+mex build_km_tree.cpp % based on Euclidean distance
+mex search_km_tree.cpp % based on Euclidean distance
+mex build_km_tree_xcorr.cpp % based on normalized cross correlation
+mex search_km_tree_xcorr.cpp % based on normalized cross correlation
+mex probability_search_km_tree.cpp % based on normalized cross correlation
+
diff --git a/code/texture_gui/code/functions/compute_mappings.m b/code/texture_gui/code/functions/compute_mappings.m
new file mode 100755
index 0000000..9abe4f7
--- /dev/null
+++ b/code/texture_gui/code/functions/compute_mappings.m
@@ -0,0 +1,21 @@
+function [mappings,A] = compute_mappings(image,dictionary)
+
+switch dictionary.options.method
+    case 'euclidean'
+        A = search_km_tree(image,...
+            dictionary.tree,...
+            dictionary.options.branching_factor,...
+            dictionary.options.normalization);
+    case 'nxcorr'
+        A = search_km_tree_xcorr(image,...
+            dictionary.tree,...
+            dictionary.options.branching_factor);
+    otherwise
+        error('Unknown dictionary method.')
+end
+B = biadjacency_matrix(A,dictionary.options.patch_size);
+
+[rc,nm] = size(B);
+mappings.T1 = sparse(1:nm,1:nm,1./(sum(B,1)+eps),nm,nm)*B';
+mappings.T2 = sparse(1:rc,1:rc,1./(sum(B,2)+eps),rc,rc)*B;
+
diff --git a/code/texture_gui/code/functions/image_texture_gui.m b/code/texture_gui/code/functions/image_texture_gui.m
new file mode 100755
index 0000000..a314577
--- /dev/null
+++ b/code/texture_gui/code/functions/image_texture_gui.m
@@ -0,0 +1,805 @@
+function image_texture_gui(image,dict,nr_labels,labeling)
+%IMAGE_TEXTURE_GUI   Interactive texture segmentation of the image
+% IMAGE_TEXTURE_GUI(IMAGE,DICTOP,NR_LABELS,LABELING)
+% Called without imput arguments starts in a demo mode. Input:
+%   IMAGE, may be rgb or grayscale, 0-to-1 or uint8
+%   DICT, may be either:
+%       - dictopt struct containing dictinary parameters,
+%       - dictionary struct containing the dictionary,
+%       - mappings struct containing the transformation matrices,
+%       - not given or empty, so default options are loaded
+%   NR_LABELS, number of labels, defaults to 2.
+%   LABELING, optional initial labeling, given as either
+%       - binary matrix of the size nr_pixels-by-nr_labels,
+%       - labeling image of the same dimensions as IMAGE
+%
+% Keyboard controls (TODO update this for newest version):
+%   L, shift+L and numerical values change label
+%   T, shift+T, uparrow and downarros change pen thickness
+%   W and shift+W change show option
+%   M and shift+M change method
+%   O and shift+O change overwrite option
+%   R and shift+R change regularize option
+%   U and shift+U change live update option
+%   C and shift+C change colormap
+%   A and shift+A change opacity (alpha)
+%   S saves a project
+%   E export
+%   F freeze
+%
+% Author: vand@dtu.dk, 2015
+% char(100+[18 -3 10 0 -36 0 16 17 -54 0 7])
+%
+% TODO:
+%   - when LABELING given, update segmentation upon startup - DONE, TESTING
+%   - when zooming, make sure mouse overlay circle not displayed (frozen)
+%   - option for changing opacity - DONE, TESTING
+
+%%%%%%%%%% DEFAULTS %%%%%%%%%%
+if nargin<1 % default example image
+    image = imread('bag.png');
+    dict.method = 'euclidean';
+    dict.patch_size = 15;
+    dict.branching_factor = 2;
+    dict.number_layers = 5;
+    dict.number_training_patches = 1000;
+    dict.normalization = false;
+    nr_labels = 2;
+else
+    if nargin<2 || isempty(dict)% default dictionary
+        dict.method = 'euclidean';
+        dict.patch_size = 3;
+        dict.branching_factor = 2;
+        dict.number_layers = 5;
+        dict.number_training_patches = 1000;
+        dict.normalization = false;
+    end
+    if nargin<3 || isempty(nr_labels) % defalult number of labels
+        nr_labels = 2;
+    else
+        nr_labels = double(nr_labels); % for colormaps to work properly
+    end
+end
+
+[r,c,~] = size(image);
+if nargin<4 || isempty(labeling) % default, unlabeled initial labeling
+    LABELING = zeros(r*c,nr_labels);
+else
+    parse_labeling_input(labeling)
+end
+
+%%%%%%%%%% PROBABILITY COMPUTING METHODS %%%%%%%%%%
+% to add a new method, add a function to the method_options list
+method_options = {...
+    @(labeling)distributed(labeling),...
+    @(labeling)two_max(labeling),...
+    @(labeling)two_max_over(labeling),...
+    @(labeling)two_cont(labeling),...
+    @(labeling)two_cont_over(labeling),...
+    };
+
+%%%%%%%%%% SETTINGS %%%%%%%%%%
+
+% method options
+METHOD_INDEX = 1; % initial method is the first on the list
+METHOD = method_options{METHOD_INDEX};
+METHOD_NAME = method_name_str;
+
+% brush label options
+LABEL = 1; % initial label is 1
+
+% brush thickness options
+thickness_options = [1 2 3 4 5 10 20 30 40 50 100 -1]; % last option (value -1) is 'fill'
+thickness_options_string = num2cell(thickness_options);
+thickness_options_string{end} = 'fill';
+THICKNESS_INDEX = 5; % initial pencil thickness is the fifth option
+RADIUS = thickness2radius(thickness_options(THICKNESS_INDEX)); % pencil radius
+
+% results visualization options
+show_options(1:2) = {'segmentation','overlay'};
+show_options((1:nr_labels)+2) = num2cell([repmat('probability ',[nr_labels,1]),num2str((1:nr_labels)')],2);
+SHOW_INDEX = 1;
+
+% overwrite option
+overwrite_options = {'no','yes'};
+OVERWRITE = false; % initialy no overwrite
+
+% regularization (smoothness) options
+regularize_options = [0 1 2 3 4 5 10 15 20 25 30 50];
+REGULARIZE_INDEX = 1; % initialy no regularization
+
+% visualization colormap options (for labelings and results)
+colormap_options = {@(x)[0.5,0.5,0.5;cool(x)], @(x)[0.5,0.5,0.5;spring(x)],...
+    @(x)[0.5,0.5,0.5;parula(x)]}; % gray color for unlabeled
+COLORMAP_INDEX = 1; % current colormap
+COLORS = colormap_options{COLORMAP_INDEX}(nr_labels); % visualization colors for label overlay
+
+% visualization opacity options (for labelings and results)
+color_weight_options = 0.1:0.1:0.9;
+COLOR_WEIGHT_INDEX = 2;
+COLOR_WEIGHT = color_weight_options(COLOR_WEIGHT_INDEX);
+
+% live update option
+live_update_options = {'off','on'};
+LIVE_UPDATE = true; % initially on
+
+% other settings
+nr_circle_pts = 16; % number of points defining a circular pencil
+
+%%%%%%%%%% INITIALIZATION AND LAYOUT %%%%%%%%%%
+
+[image,image_rgb,image_gray] = normalize_image(image); % impose 0-to-1 rgb
+LABELING_OVERLAY = image_rgb; % image overlaid labeling
+SEGMENTATION_OVERLAY = 0.5+zeros(r,c,3); % segmentation, optionally overlay
+
+fmar = [0.2 0.2]; % discance from screen edge to figure (x and y)
+amar = [0.02 0.02]; % margin around axes, relative to figure
+my = 0.85:0.04:0.95; % menu items y position
+mw = 0.15; % menu items width
+mx = 0.05:0.15:0.8;
+mh = 0.03; % menu items height
+cw = (0.25-0.15)/(nr_labels+1); % colorcube width
+cx = 0.15:cw:0.25; % colorcubes x position
+pointer_char = 'X';
+
+fig = figure('Units','Normalized','Position',[fmar,1-2*fmar],...
+    'Pointer','watch','KeyPressFcn',@key_press,'InvertHardCopy', 'off',...
+    'Name','Texture segmentation GUI');
+
+labeling_axes = axes('Units','Normalized','Position',[0,0,0.5,0.85]+[amar,-2*amar]);
+imagesc(LABELING_OVERLAY), axis image off, hold on
+segmentation_axes = axes('Units','Normalized','Position',[0.5,0,0.5,0.85]+[amar,-2*amar]);
+imagesc(SEGMENTATION_OVERLAY,[0,nr_labels]), axis image off, hold on
+
+clean_toolbar % also defines linkaxes tool
+
+uicontrol('String','Label [L] : ','Style','text','HorizontalAlignment','right',...
+    'Units','Normalized','Position',[mx(1),my(3),mw,mh]);
+labels_text = uicontrol('String',num2str(LABEL),...
+    'BackgroundColor',COLORS(LABEL+1,:),...
+    'Style','text','HorizontalAlignment','left',...
+    'Units','Normalized','Position',[mx(2),my(3),0.03,mh]);
+label_pointer = cell(nr_labels+1,1);
+for k = 1:nr_labels+1
+    label_pointer{k} = uicontrol('String',' ','Style','text',...
+        'HorizontalAlignment','center','BackgroundColor',COLORS(k,:),...
+        'Units','Normalized','Position',[cx(k),my(2),cw,mh],...
+        'Enable','Inactive','ButtonDownFcn',@label_click,'UserData',k-1);
+end
+set(label_pointer{LABEL+1},'String',pointer_char);
+
+uicontrol('String','Thickness [T] : ','Style','text','HorizontalAlignment','right',...
+    'Units','Normalized','Position',[mx(1),my(1),mw,mh]);
+thickness_text = uicontrol('String',thickness_options_string(THICKNESS_INDEX),...
+    'Style','text','HorizontalAlignment','left',...
+    'Units','Normalized','Position',[mx(2),my(1),mw,mh]);
+
+uicontrol('String','Show [W] : ','Style','text','HorizontalAlignment','right',...
+    'Units','Normalized','Position',[mx(5),my(2),mw,mh]);
+show_text = uicontrol('String',show_options{SHOW_INDEX},...
+    'Style','text','HorizontalAlignment','left',...
+    'Units','Normalized','Position',[mx(6),my(2),mw,mh]);
+
+uicontrol('String','Live update [U] : ','Style','text','HorizontalAlignment','right',...
+    'Units','Normalized','Position',[mx(5),my(3),mw,mh]);
+update_text = uicontrol('String',live_update_options(LIVE_UPDATE+1),...
+    'Style','text','HorizontalAlignment','left',...
+    'Units','Normalized','Position',[mx(6),my(3),mw,mh]);
+
+uicontrol('String','Method [M] : ','Style','text','HorizontalAlignment','right',...
+    'Units','Normalized','Position',[mx(3),my(3),mw,mh]);
+method_text = uicontrol('String',METHOD_NAME,...
+    'Style','text','HorizontalAlignment','left',...
+    'Units','Normalized','Position',[mx(4),my(3),mw,mh]);
+
+uicontrol('String','Overwrite [O] : ','Style','text','HorizontalAlignment','right',...
+    'Units','Normalized','Position',[mx(3),my(2),mw,mh]);
+overlay_text = uicontrol('String',overwrite_options(OVERWRITE+1),...
+    'Style','text','HorizontalAlignment','left',...
+    'Units','Normalized','Position',[mx(4),my(2),mw,mh]);
+
+uicontrol('String','Regularize [R] : ','Style','text','HorizontalAlignment','right',...
+    'Units','Normalized','Position',[mx(3),my(1),mw,mh]);
+regularize_text = uicontrol('String',regularize_options(REGULARIZE_INDEX),...
+    'Style','text','HorizontalAlignment','left',...
+    'Units','Normalized','Position',[mx(4),my(1),mw,mh]);
+
+drawnow % pointer shows busy system
+
+LIMITS = [1,c-0.5,1,r+0.5]; % to capture zoom
+zoom_handle = zoom(fig);
+pan_handle = pan(fig);
+set(zoom_handle,'ActionPostCallback',@adjust_limits,...
+    'ActionPreCallback',@force_keep_key_press);
+set(pan_handle,'ActionPostCallback',@adjust_limits,...
+    'ActionPreCallback',@force_keep_key_press);
+
+%%%%%%%%%% TEXTURE REPRESENTATION %%%%%%%%%%
+% initiolization: building a texture representation of the image
+T1 = 0;
+T2 = 0;
+parsing_dictionary_input; % T1 and T2 are assigned here
+
+if nargin>3
+    PROBABILITY = METHOD(LABELING);
+else
+    PROBABILITY = 1/nr_labels*ones(size(LABELING));
+    %labeling_overwrite % relevant only if we allow loading all settings
+    %regularize % relevant only if we allow loading all settings
+end
+compute_overlays
+
+% ready to draw
+set(fig,'Pointer','arrow','WindowButtonDownFcn',@start_draw,...
+    'WindowButtonMotionFcn',@pointer_motion);
+XO = []; % current drawing point
+
+show_overlays(get_pixel);
+uiwait % waits with assigning output until a figure is closed
+
+%%%%%%%%%% CALLBACK FUNCTIONS %%%%%%%%%%
+    function key_press(~,object)
+        % keyboard commands
+        key = object.Key;
+        numkey = str2double(key);
+        if ~isempty(numkey) && numkey<=nr_labels;
+            change_label(numkey)
+        else
+            switch key
+                case 'l'
+                    change_label(move_once(LABEL+1,nr_labels+1,...
+                        any(strcmp(object.Modifier,'shift')))-1)
+                case 'uparrow'
+                    THICKNESS_INDEX = move_once(THICKNESS_INDEX,...
+                        numel(thickness_options),false);
+                    RADIUS = thickness2radius(thickness_options(THICKNESS_INDEX));
+                    set(thickness_text,'String',...
+                        thickness_options_string(THICKNESS_INDEX));
+                    show_overlays(get_pixel);
+                case 'downarrow'
+                    THICKNESS_INDEX = move_once(THICKNESS_INDEX,...
+                        numel(thickness_options),true);
+                    RADIUS = thickness2radius(thickness_options(THICKNESS_INDEX));
+                    set(thickness_text,'String',...
+                        thickness_options_string(THICKNESS_INDEX));
+                    show_overlays(get_pixel);
+                case 't'
+                    THICKNESS_INDEX = move_once(THICKNESS_INDEX,...
+                        numel(thickness_options),any(strcmp(object.Modifier,'shift')));
+                    RADIUS = thickness2radius(thickness_options(THICKNESS_INDEX));
+                    set(thickness_text,'String',...
+                        thickness_options_string(THICKNESS_INDEX));
+                    show_overlays(get_pixel);
+                case 'w'
+                    SHOW_INDEX = move_once(SHOW_INDEX,numel(show_options),...
+                        any(strcmp(object.Modifier,'shift')));
+                    set(show_text,'String',show_options{SHOW_INDEX})
+                    compute_overlays
+                    show_overlays(get_pixel);
+                case 'c'
+                    COLORMAP_INDEX = move_once(COLORMAP_INDEX,...
+                        length(colormap_options),...
+                        any(strcmp(object.Modifier,'shift')));
+                    COLORS = colormap_options{COLORMAP_INDEX}(nr_labels);
+                    set(labels_text,'BackgroundColor',COLORS(LABEL+1,:));
+                    for kk = 1:nr_labels+1
+                        set(label_pointer{kk},'BackgroundColor',COLORS(kk,:))
+                    end
+                    compute_overlays
+                    show_overlays(get_pixel);
+                case 'a'
+                    COLOR_WEIGHT_INDEX = move_once(COLOR_WEIGHT_INDEX,...
+                        length(color_weight_options),...
+                        any(strcmp(object.Modifier,'shift')));
+                    COLOR_WEIGHT = color_weight_options(COLOR_WEIGHT_INDEX);
+                    compute_overlays
+                    show_overlays(get_pixel);
+                case 'm'
+                    METHOD_INDEX = move_once(METHOD_INDEX,...
+                        length(method_options),...
+                        any(strcmp(object.Modifier,'shift')));
+                    METHOD = method_options{METHOD_INDEX};
+                    METHOD_NAME = method_name_str;
+                    set(method_text,'String',METHOD_NAME)
+                    PROBABILITY = METHOD(LABELING);
+                    labeling_overwrite
+                    regularize
+                    compute_overlays
+                    show_overlays(get_pixel);
+                case 'o'
+                    OVERWRITE = ~OVERWRITE;
+                    set(overlay_text,'String',overwrite_options{OVERWRITE+1})
+                    PROBABILITY = METHOD(LABELING);
+                    labeling_overwrite
+                    regularize
+                    compute_overlays
+                    show_overlays(get_pixel);
+                case 'u'
+                    LIVE_UPDATE = ~LIVE_UPDATE;
+                    set(update_text,'String',live_update_options{LIVE_UPDATE+1})
+                    if LIVE_UPDATE
+                        PROBABILITY = METHOD(LABELING);
+                        labeling_overwrite
+                        regularize
+                        compute_overlays
+                        show_overlays(get_pixel);
+                    end
+                case 'r'
+                    REGULARIZE_INDEX = move_once(REGULARIZE_INDEX,...
+                        numel(regularize_options),...
+                        any(strcmp(object.Modifier,'shift')));
+                    set(regularize_text,'String',...
+                        regularize_options(REGULARIZE_INDEX))
+                    PROBABILITY = METHOD(LABELING);
+                    labeling_overwrite
+                    regularize
+                    compute_overlays
+                    show_overlays(get_pixel);
+                case 's'
+                    save_displayed
+                case 'e'
+                    export_LS
+                case 'f'
+                    freeze_LS
+                case 'q'
+                    close(fig)
+            end
+        end
+    end
+
+    function label_click(source,~)
+        change_label(source.UserData)
+    end
+
+    function change_label(new_label)
+        set(label_pointer{LABEL+1},'String',' ');
+        LABEL = new_label;
+        set(label_pointer{LABEL+1},'String',pointer_char);
+        set(labels_text,'String',num2str(LABEL),...
+            'BackgroundColor',COLORS(LABEL+1,:));
+    end
+
+    function adjust_limits(~,~)
+        % response to zooming and panning
+        LIMITS([1,2]) = get(labeling_axes,'XLim');
+        LIMITS([3,4]) = get(labeling_axes,'YLim');
+    end
+
+    function force_keep_key_press(~,~)
+        % a hack to maintain my key_press while in zoom and pan mode
+        % http://undocumentedmatlab.com/blog/enabling-user-callbacks-during-zoom-pan
+        hManager = uigetmodemanager(fig);
+        [hManager.WindowListenerHandles.Enabled] = deal(false);
+        set(fig, 'KeyPressFcn', @key_press);
+    end
+
+    function start_draw(~,~)
+        % click in the image
+        x = get_pixel;
+        if is_inside(x)
+            if RADIUS>0 % thickness>0
+                XO = x;
+                M = disc(XO,RADIUS,nr_circle_pts,[r,c]);
+                set(fig,'WindowButtonMotionFcn',@drag_and_draw,...
+                    'WindowButtonUpFcn',@end_draw)
+            else % fill
+                M = fill(x);
+            end
+            update(M);
+        end
+    end
+
+    function drag_and_draw(~,~)
+        % drag after clicking in the image
+        x = get_pixel;
+        M = stadium(XO,x,RADIUS,nr_circle_pts,[r,c]);
+        update(M);
+        XO = x;
+    end
+
+    function end_draw(~,~)
+        % release click after clicking in the image
+        M = stadium(XO,get_pixel,RADIUS,nr_circle_pts,[r,c]);
+        update(M);
+        XO = [];
+        set(fig,'WindowButtonMotionFcn',@pointer_motion,...
+            'WindowButtonUpFcn','')
+    end
+
+    function pointer_motion(~,~)
+        % move around without clicking
+        if strcmp(zoom_handle.Enable,'off') && ...
+                strcmp(pan_handle.Enable,'off') % not zooming or panning
+            x = get_pixel;
+            if is_inside(x)
+                set(fig,'Pointer','crosshair')
+            else
+                set(fig,'Pointer','arrow')
+            end
+            show_overlays(x);
+        end
+    end
+
+%%%%%%%%%% HELPING FUNCTIONS %%%%%%%%%%
+
+    function [L,S] = membership2indexed
+        % computes labeling and segmentation as indexed r-by-c images
+        % from membership r*c-by-nr_labels representation
+        [maxlab,L] = max(LABELING,[],2);
+        L(maxlab==0) = 0;
+        L = uint8(reshape(L,[r,c]));
+        [maxprob,S] = max(PROBABILITY,[],2);
+        S(sum(PROBABILITY==maxprob(:,ones(nr_labels,1)),2)>1) = 0;
+        S = uint8(reshape(S,[r,c]));
+    end
+
+    function save_displayed
+        % saves mat file with user settings and images as separate files
+        [file,path] = uiputfile('settings.mat','Save settings as');
+        if ~isequal(file,0) && ~isequal(path,0)
+            matfile = fullfile(path,file);
+            roothname = matfile(1:find(matfile=='.',1,'last')-1);
+            current_settings.method = METHOD_NAME;
+            current_settings.show = show_options{SHOW_INDEX};
+            current_settings.overwrite = OVERWRITE;
+            current_settings.regularize = regularize_options(REGULARIZE_INDEX);
+            save(matfile,'current_settings')
+            % saving displayed images
+            imwrite(LABELING_OVERLAY,[roothname,'_labels_displayed.png'])
+            imwrite(SEGMENTATION_OVERLAY,[roothname,'_results_displayed.png'])
+            [L,S] = membership2indexed;
+            imwrite(L,COLORS,[roothname,'_labels_indexed.png'])
+            imwrite(S,COLORS,[roothname,'_segmentation_indexed.png'])
+        end
+    end
+
+    function export_LS
+        % saves variables to workspace
+        % TODO, consider using:
+        % export2wsdlg({'Labeling','Segmentation'},{'gui_L','gui_S'},{L,S})
+        button = questdlg({'Exporting variables to the base workspace',...
+            'will close texture segmentation gui and',...
+            'might overwrite existing variables'},...
+            'Exporting variables','OK','Cancel','OK');
+        if strcmp(button,'OK')
+            [L,S] = membership2indexed;
+            [~,dictprob] = METHOD(LABELING);
+            assignin('base','gui_L',L)
+            assignin('base','gui_S',S)
+            assignin('base','gui_dictprob',dictprob)
+            %             assignin('base','gui_dictprob',T1*LABELING)
+        end
+        close(fig)
+    end
+
+    function freeze_LS
+        % feezes, closes and opens segmentation_correction_gui
+        button = questdlg({'Freezing segmentation will close texture segmentation gui',...
+            'and open segmentation correction gui.'},...
+            'Freezing segmentation','OK','Cancel','OK');
+        if strcmp(button,'OK')
+            [L,S] = membership2indexed;
+            close(fig)
+            segmentation_correction_gui(image_rgb,S,nr_labels,L);
+        end
+    end
+
+    function a = is_inside(x)
+        % check if x is inside image limits
+        a = inpolygon(x(1),x(2),LIMITS([1,2,2,1]),LIMITS([3,3,4,4]));
+    end
+
+    function p = get_pixel
+        % get cursor position
+        p = get(labeling_axes,'CurrentPoint');
+        p = round(p(1,[1,2]));
+    end
+
+    function show_overlays(x)
+        % overlay a circular region where the pointer is and show
+        shown_left = LABELING_OVERLAY;
+        shown_right = SEGMENTATION_OVERLAY;
+        if RADIUS>0 % thickness>0
+            P = repmat(disc(x,RADIUS,nr_circle_pts,[r,c]),[1,1,3]);
+            shown_left(P(:)) = 0.5+0.5*LABELING_OVERLAY(P(:));
+            shown_right(P(:)) = 0.5+0.5*SEGMENTATION_OVERLAY(P(:));
+        end
+        % we have to imagesc(shown) to remove overlay if needed
+        axes(labeling_axes), cla, imagesc(shown_left)
+        axes(segmentation_axes), cla, imagesc(shown_right)
+    end
+
+    function update(M)
+        % change the state of the segmentation by updating LABELING with a
+        % mask M, and updating PROBABILITY
+        labcol = zeros(1,nr_labels);
+        if LABEL>0 % not unlabeling
+            labcol(LABEL) = 1;
+        end
+        LABELING(M(:),:) = repmat(labcol,[sum(M(:)),1]);
+        if LIVE_UPDATE
+            PROBABILITY = METHOD(LABELING); % PROBABILITY computed
+            labeling_overwrite
+            regularize
+            compute_overlays(true) % compute both overlays
+        else
+            compute_overlays(false) % comput only left overlay
+        end
+        % computing overlay images
+        show_overlays(get_pixel); % showing overlay and pointer
+    end
+
+    function compute_overlays(compute_both)
+        if nargin<1
+            compute_both = true; % default computes overlay for both images
+        end
+        % computes overlays but not pointer overalay
+        % TODO: a lot of this does not need to be recalculated
+        LABELING_OVERLAY = reshape(LABELING*COLORS(2:end,:),size(image_rgb)).*...
+            (COLOR_WEIGHT+(1-COLOR_WEIGHT)*image_gray);
+        unlabeled = repmat(~any(LABELING,2),[3,1]); % pixels not labeled
+        LABELING_OVERLAY(unlabeled) = image_rgb(unlabeled);
+        if compute_both
+            if SHOW_INDEX<3 % showing segmentation or overlay
+                maxprob = max(PROBABILITY,[],2);
+                maxprobloc = PROBABILITY == maxprob(:,ones(nr_labels,1));
+                uncertain = sum(maxprobloc,2)>1; % pixels with max probability at two or more classes
+                maxprobloc(uncertain,:) = 0;
+                if SHOW_INDEX==1 % segmentation
+                    SEGMENTATION_OVERLAY = reshape([uncertain,maxprobloc]*COLORS,size(image_rgb));
+                else % SHOW_INDEX==2 overlay
+                    SEGMENTATION_OVERLAY = reshape([uncertain,maxprobloc]*COLORS,...
+                        size(image_rgb)).*(COLOR_WEIGHT+(1-COLOR_WEIGHT)*image_gray);
+                end
+            else % 'probability x'
+                pw = SHOW_INDEX-2; % probability to show
+                minpw = min(PROBABILITY(:,pw));
+                maxpw = max(PROBABILITY(:,pw));
+                % TODO scaling should be better, relative to 1/nr_labels
+                SEGMENTATION_OVERLAY = reshape((PROBABILITY(:,pw)-minpw)/(maxpw-minpw)*[1,1,1],size(image_rgb));
+            end
+        end
+    end
+
+% TODO disc shold be saved as a list of index shifts with respect to
+% the central pixel, and change only when thickness changes
+    function M = disc(x,r,N,dim)
+        % disc shaped mask in the image
+        angles = (0:2*pi/N:2*pi*(1-1/N));
+        X = x(1)+r*cos(angles);
+        Y = x(2)+r*sin(angles);
+        M = poly2mask(X,Y,dim(1),dim(2));
+    end
+
+    function M = stadium(x1,x2,r,N,dim)
+        % stadium shaped mask in the image
+        angles = (0:2*pi/N:pi)-atan2(x1(1)-x2(1),x1(2)-x2(2));
+        X = [x1(1)+r*cos(angles), x2(1)+r*cos(angles+pi)];
+        Y = [x1(2)+r*sin(angles), x2(2)+r*sin(angles+pi)];
+        M = poly2mask(X,Y,dim(1),dim(2));
+    end
+
+    function M = fill(x)
+        [maxL,labL] = max(LABELING,[],2);
+        label_image = reshape(maxL.*labL,[r,c]);
+        M = bwselect(label_image==label_image(x(2),x(1)),x(1),x(2),4);
+    end
+
+    function [I,I_rgb,I_gray] = normalize_image(I)
+        % initialization: normalize image
+        if isa(I,'uint8')
+            I = double(I)/255;
+        end
+        if isa(I,'uint16')
+            I = double(I)/65535;
+        end
+        if size(I,3)==3 % rgb image
+            I_gray = repmat(rgb2gray(I),[1 1 3]);
+            I_rgb = I;
+        else % assuming grayscale image
+            I_gray = repmat(I,[1,1,3]);
+            I_rgb = I_gray;
+        end
+    end
+
+    function name = method_name_str
+        method_str = func2str(METHOD);
+        s1 = find(method_str==')',1,'first')+1;
+        s2 = find(method_str=='(',1,'last')-1;
+        name = method_str(s1:s2);
+    end
+
+    function n = move_once(n,total,reverse)
+        % moves option index once, respecting total number of options
+        if ~reverse
+            n = mod(n,total)+1;
+        else
+            n = mod(n+total-2,total)+1;
+        end
+    end
+
+    function labeling_overwrite
+        % labeled areas get assigned probability 1
+        if OVERWRITE
+            labeled = any(LABELING,2);
+            PROBABILITY(labeled,:) = LABELING(labeled,:); % overwritting labeled
+        end
+    end
+
+    function regularize
+        sigma = regularize_options(REGULARIZE_INDEX);
+        if sigma>0
+            filter = fspecial('gaussian',[2*ceil(sigma)+1,1],sigma);
+            PROBABILITY = reshape(PROBABILITY,[r,c,nr_labels]);
+            PROBABILITY = imfilter(PROBABILITY,filter,'replicate');
+            PROBABILITY = imfilter(PROBABILITY,filter','replicate');
+            PROBABILITY = reshape(PROBABILITY,[r*c,nr_labels]);
+        end
+    end
+
+    function r = thickness2radius(t)
+        r = t/2+0.4;
+    end
+
+    function clean_toolbar
+        set(fig,'MenuBar','none','Toolbar','figure');
+        toolbar = findall(fig,'Type','uitoolbar');
+        all_tools = allchild(toolbar);
+        % removing tools
+        for i=1:numel(all_tools)
+            if isempty(strfind(all_tools(i).Tag,'Pan'))&&...
+                    isempty(strfind(all_tools(i).Tag,'Zoom'))&&...
+                    isempty(strfind(all_tools(i).Tag,'SaveFigure'))&&...
+                    isempty(strfind(all_tools(i).Tag,'PrintFigure'))&&...
+                    isempty(strfind(all_tools(i).Tag,'DataCursor'))
+                delete(all_tools(i)) % keeping only Pan, Zoom, Save and Print
+            end
+        end
+        % adding a tool
+        [icon,~,alpha] = imread('linkaxesicon.png');
+        icon = double(icon)/255;
+        icon(alpha==0)=NaN;
+        uitoggletool(toolbar,'CData',icon,...
+            'TooltipString','Link Axes','Tag','LinkAxes',...
+            'OnCallback',{@link_axes,'xy'},...
+            'OffCallback',{@link_axes,'off'});
+        % changing the order of tools
+        all_tools = allchild(toolbar);
+        set(toolbar,'children',all_tools([2,1,3:end]));
+    end
+
+    function link_axes(~,~,flag)
+        linkaxes([labeling_axes,segmentation_axes],flag)
+    end
+
+    function parsing_dictionary_input
+        % either dictionary_options, dictionary or mappings should be given
+        if isfield(dict,'patch_size') % dictionary options given
+            dictionary = build_dictionary(image,dict);
+            mappings = compute_mappings(image,dictionary);
+            T1 = mappings.T1;
+            T2 = mappings.T2;
+        elseif isfield(dict,'tree')% dictinary given
+            mappings = compute_mappings(image,dict);
+            T1 = mappings.T1;
+            T2 = mappings.T2;
+        elseif isfield(dict,'T1')% mapping given
+            T1 = dict.T1;
+            T2 = dict.T2;
+        else
+            error('Could not parse dictionary input.')
+        end
+    end
+
+    function parse_labeling_input(labeling)
+        % parsing labeling input, either labeling or labeling image
+        dim_l = size(labeling);
+        labeling = double(labeling);
+        if numel(dim_l)==3 %% rgb labeling image, to be turned to 2D image
+            max_l = max(labeling(:))+1;
+            labeling = labeling(:,:,1)+max_l*labeling(:,:,2)+max_l^2*labeling(:,:,3);
+            dim_l = size(labeling);
+        end
+        if numel(dim_l)==2 % either LABELING or 2D labeling image
+            if all(dim_l==[r*c,nr_labels]) % LABELING
+                LABELING = labeling;
+            elseif all(dim_l==[r,c]) % labeling image
+                l = unique(labeling(:)); % present labels
+                if numel(union(l,0:nr_labels))~=nr_labels+1
+                    labeling_old = labeling;
+                    for li = 1:numel(l)
+                        labeling(labeling_old==l(li)) = li-1;
+                    end
+                end
+                % now we have labels from 0 to nr_labels
+                i = (labeling(:)-1)*r*c + (1:r*c)'; % indices in LABELINGS
+                i = i(labeling(:)>0); % only labeled parts
+                LABELING = zeros(r*c,nr_labels);
+                LABELING(i) = 1;
+            else
+                error('Could not parse labeling input.')
+            end
+        else
+            error('Could not parse labeling input.')
+        end
+    end
+
+%%%%%%%%%% LABELINGS TO PROBABILITIES METHODS %%%%%%%%%%
+
+    function [probabilities,dictprob] = distributed(labelings)
+        % unlabeled pixels have label weights DISTRIBUTED equally
+        labelings(~any(labelings,2),:) = 1/nr_labels; % distributing
+        dictprob = T1*labelings;
+        probabilities = T2*dictprob; % computing probabilities
+    end
+
+    function [probabilities,dictprob] = two_max(labelings)
+        % DISTRIBUTED tresholded and repeated
+        labelings(~any(labelings,2),:) = 1/nr_labels; % distributing
+        probabilities = T2*(T1*labelings); % probabilities
+        maxprob = max(probabilities,[],2); % finding max probabilities
+        labelings_new = probabilities == maxprob(:,ones(nr_labels,1)); % new labeling is where max prob was
+        uncertain = sum(labelings_new,2)>1; % pixels with max probability at two or more classes
+        labelings_new(uncertain,:) = 1/nr_labels; % distributing at uncertain
+        dictprob = T1*labelings_new;
+        probabilities = T2*dictprob;
+    end
+
+    function [probabilities,dictprob] = two_max_over(labelings)
+        % DISTRIBUTED tresholded, overwriten and repeated
+        known_labels = any(labelings,2);
+        labelings(~known_labels,:) = 1/nr_labels; % distributing
+        probabilities = T2*(T1*labelings); % probabilities
+        maxprob = max(probabilities,[],2); % finding max probabilities
+        labelings_new = probabilities == maxprob(:,ones(nr_labels,1)); % new labeling is where max prob was
+        uncertain = sum(labelings_new,2)>1; % pixels with max probability at two or more classes
+        labelings_new(uncertain,:) = 1/nr_labels; % distributing at uncertain
+        labelings_new(known_labels,:) = labelings(known_labels,:); % OVERWRITING
+        dictprob = T1*labelings_new;
+        probabilities = T2*dictprob;
+    end
+
+    function [probabilities,dictprob] = two_cont(labelings)
+        % DISTRIBUTED repeated
+        labelings(~any(labelings,2),:) = 1/nr_labels; % distributing
+        labelings_new = T2*(T1*labelings); % probabilities
+        dictprob = T1*labelings_new;
+        probabilities = T2*dictprob;
+    end
+
+    function [probabilities,dictprob] = two_cont_over(labelings)
+        % DISTRIBUTED overwriten and repeated
+        known_labels = any(labelings,2);
+        labelings(~known_labels,:) = 1/nr_labels; % distributing
+        labelings_new = T2*(T1*labelings); % probabilities
+        labelings_new(known_labels,:) = labelings(known_labels,:); % OVERWRITING
+        dictprob = T1*labelings_new;
+        probabilities = T2*dictprob;
+    end
+
+%     function probabilities = normalized(labelings)
+%         probabilities = T2*(T1*labelings); % computing probabilities
+%         % normalizing probabilities so that they sum to 1
+%         probabilities = probabilities./repmat(sum(probabilities,2),[1,size(probabilities,2)]);
+%         probabilities(isnan(probabilities)) = 0;
+%     end
+%
+%     function probabilities = normalized_2_max(labelings)
+%         probabilities = T2*(T1*labelings); % probabilities
+%         maxprob = max(probabilities,[],2); % finding max probabilities
+%         labelings_new = probabilities == maxprob(:,ones(nr_labels,1)); % new labeling is where max prob was
+%         uncertain = sum(labelings_new,2)>1; % pixels with max probability at two or more classes
+%         labelings_new(uncertain,:) = 0; % zero at uncertain
+%         probabilities = T2*(T1*labelings_new);
+%         probabilities = probabilities./repmat(sum(probabilities,2),[1,size(probabilities,2)]);
+%         probabilities(isnan(probabilities)) = 0;
+%     end
+%
+%     function probabilities = normalized_2_cont(labelings)
+%         labelings_new = T2*(T1*labelings); % probabilities
+%         probabilities = T2*(T1*labelings_new);
+%         probabilities = probabilities./repmat(sum(probabilities,2),[1,size(probabilities,2)]);
+%         probabilities(isnan(probabilities)) = 0;
+%     end
+
+end
diff --git a/code/texture_gui/code/functions/linkaxesicon.png b/code/texture_gui/code/functions/linkaxesicon.png
new file mode 100755
index 0000000000000000000000000000000000000000..f1c1759a401c8c3cc0dbbb158860bcb9e18ab4ae
GIT binary patch
literal 568
zcmV-80>}M{P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00007bV*G`2j2`A
z3>^ngkcOrJ00HbtL_t(Ijm4ACOOtUN$6wEWF{u3rnbufsb5pmKtY#DiA*>?FLOVtm
z4`P>Yb&BZFq5r{%@X`*uSa|EQ5t%ma>Cr?SUV5-*Wy$kAKIOKW-wvaNphkG;bNayR
z&HMA_4IfElvg~GTT_dvC4!#~pNq^%ufQhkt)HVb{2n1laS~zw2ZbP^ew*WXCcFb}O
z{d<iSy^6zO-*jmwZu`C19agLxV6|AbjJqA*TKy06{|y=)yjM%STh{sb<r_vt=f+T)
ze849_MxHIQ^vUG&>N-Z*!0m+lxBH;9R5zF_s?4h<9q|yC(jN2*<Q0|N)Fd~rpJ(wy
zl~^K5U+@nbFTA80@d-&}vWzxGMJn0K=-6|zPoLrUyXd*ti`}^w%HZ{SG1qiP9u4Da
za&e*iEKXN5GgG;Gg5?#HV2g)`kDqXBs0WWP!Ig7|(E&{dO#`j06OTnnbq4ra{Xr}i
z;=%Aj-N5aUm?^3ZUh79zSLu*S?2F$4v_@Gcx{|adlB@|g`+aVdNriCuAd<*rDI|`F
z7qcpn<^zO6Av8@RuPDqFWV+9EQnBnI+T!2D-oBcqH+{5j05BeI7ZdUV1$iDrH)v~b
z<@E6=SIef93j{^s%_7rE5#2C|L=JKCSeOCvQ<8T3&c6Wui`nF!Ww&Pl0000<MNUMn
GLSTZcSO^UO

literal 0
HcmV?d00001

diff --git a/code/texture_gui/code/functions/normalize_image.m b/code/texture_gui/code/functions/normalize_image.m
new file mode 100755
index 0000000..8dd729f
--- /dev/null
+++ b/code/texture_gui/code/functions/normalize_image.m
@@ -0,0 +1,9 @@
+function I = normalize_image(I)
+% we work with [0 1] images
+if isa(I,'uint8')
+    I = double(I)/255;
+end
+if isa(I,'uint16')
+    I = double(I)/65535;
+end
+end
\ No newline at end of file
diff --git a/code/texture_gui/code/functions/probability_search_km_tree.cpp b/code/texture_gui/code/functions/probability_search_km_tree.cpp
new file mode 100755
index 0000000..489281b
--- /dev/null
+++ b/code/texture_gui/code/functions/probability_search_km_tree.cpp
@@ -0,0 +1,305 @@
+/*=================================================================
+* syntax: Q = probability_search_km_tree(I, T, P, b, n); OR Q = search_km_tree(I, T, P, b);
+*
+* serach_km_tree  - build probability image from dictionary and intensity image
+* 			
+* 			Input: 	- I: X-by-Y image
+* 					- T: MMl-by-K tree matrix where l is the number of layers 
+*                        in the image (1 for grayscale and 3 for RGB)
+                    - P: MMc-by-K probability matrix where c is the number of 
+                         classes
+*                   - b: branching factor
+*                   - n: normalization (true or false), defaults to false
+*
+* 			Output: - Q: X-by-Y-by-c probability image
+*
+* 			Author: Anders Dahl, abda@dtu.dk, February 2016.
+*=================================================================*/
+
+#include "mex.h"
+#include <stdio.h>
+#include <math.h>
+#include "matrix.h"
+#include <vector>
+
+#include <iostream>
+using namespace std;
+
+// struct for the tree
+struct tree_st
+{
+    double *tree_data;
+    double *probability_data;
+    int n_dim, n_dprob, n_nodes, branch_fac, M, Mh, n_cls;
+    vector<int> idx_disp;
+};
+
+// struct for image
+struct im_st
+{
+    double *im_data;
+    int rows, cols, layers, n_pix;
+};
+
+// estimate the distance between a vector in tree given by the node and a 
+// patch in the image given by the row and column
+double get_dist(vector<double>& patch, tree_st& tree, int& node)
+{
+    double d = 0, tmp;
+    int id_t = tree.n_dim*node;
+    
+    for ( int i = 0; i < tree.n_dim; i++ ){
+        tmp = patch[i] - *(tree.tree_data + id_t);
+        id_t++;
+        d += tmp*tmp;
+    }
+    
+    return d;
+}
+
+
+// Function for sampling patches from the image into the patch arrays
+// inputs reference to the image struct, tree struct, patch struct and position of the sampling coordinate.
+// There is no check if the sampling is outside the image
+// vector<double> sample_patch(im_st& im, int& M, int r_im, int c_im, bool& normalize)
+vector<double> sample_patch(im_st& im, int& M, int r_im, int c_im, bool& normalize)
+{
+    int id_l, id_r, id_i; // iterators for looking up image data
+    int id_p = 0; // iterator for looking up patch data
+    double sum_sq = 0, pix_val; // variables for normalization
+    int n_dim = M*M*im.layers; // number of dimensions computed here, becasue tree is not included
+    vector<double> patch(n_dim);
+    int Mh = (M-1)/2;
+    
+    for ( int l = 0; l < im.layers; l++ ){ // image is sampled by three nested loops (layers, columns, rows)
+        id_l = im.n_pix*l;
+        for ( int i = c_im-Mh; i <= c_im+Mh; i++ ){
+            id_r = id_l + i*im.rows;
+            for ( int j = r_im-Mh; j <= r_im+Mh; j++ ){
+                id_i = id_r + j;
+                pix_val = *(im.im_data + id_i);
+                patch[id_p] = pix_val;
+                sum_sq += pix_val*pix_val; // sum of squares for normalization
+                id_p++;
+            }
+        }
+    }
+    if ( normalize ){ // if the patch should be normalized to unit length
+        double inv_sq = 1;
+        if ( sum_sq > 0 ){
+            inv_sq = 1/sqrt(sum_sq); // inverse sum of squares
+        }
+        for ( int i = 0; i < n_dim; i++ ){
+            patch[i] = patch[i]*inv_sq;
+        }
+    }
+    return patch;
+}
+
+
+// The tree search function
+int search_tree(im_st& im, tree_st& tree, int& r, int& c, bool& normalize)
+{
+    int node = 0, node_min = -1, node_min_level, next_node; // variables for searching the tree
+    double d_min = 10e100, d, d_min_level; 
+    
+    vector<double> patch = sample_patch(im, tree.M, c, r, normalize); // get the pixel values in a patch
+    while ( node < tree.n_nodes ){ // go through the tree
+        if ( *(tree.tree_data + node*tree.n_dim) == -1 ){ // check if node is a leaf-node
+            return node_min;
+        }
+        
+        d_min_level = 10e100; // set minimum distance to high value
+        for ( int i = 0; i < tree.branch_fac; i++ ){ // go through nodes at level 
+            next_node = node + i;
+            d = get_dist(patch, tree, next_node);
+            
+            if ( d < d_min_level ){ // set current node to the minimum distance
+                d_min_level = d;
+                node_min_level = next_node;
+            }
+        }
+        if ( d_min_level < d_min ){ // set overall minimum distance and minimum node
+            d_min = d_min_level;
+            node_min = node_min_level;
+        }
+        node = (node_min_level+1)*tree.branch_fac; // go to the child node
+    }
+    return node_min;
+}
+
+void add_probability(tree_st& tree, double *Q, int& idx, int& node){
+    int id_node = node*tree.n_dprob;
+    for ( int i = 0; i < tree.idx_disp.size(); i++ ){
+        *(Q + idx + tree.idx_disp[i]) += *(tree.probability_data + id_node + i);
+    }
+}
+
+
+void add_count(vector<int>& ct_im, int& col, int& row, int& rows, tree_st& tree){
+    for ( int i = col-tree.Mh; i <= col+tree.Mh; i++ ){
+        for ( int j = row-tree.Mh; j <= row+tree.Mh; j++ ){
+            ct_im[i*rows+j]++;
+        }
+    }
+}
+
+// The tree search function applied to the entire image - border is zero and interior is in 1,...,n
+void probability_search_image(im_st& im, tree_st& tree, double *Q, bool& normalize)
+{
+    vector<int> ct_im;
+    ct_im.resize(im.rows*im.cols);
+    int node;
+    int idx = tree.Mh*im.rows; // increase with empty rows at border
+    for ( int i = tree.Mh; i < im.cols-tree.Mh; i++ ){
+        idx += tree.Mh; // first Mh pixels are border
+        for ( int j = tree.Mh; j < im.rows-tree.Mh; j++ ){           
+            node = search_tree(im, tree, i, j, normalize); // find assignment
+            add_probability(tree, Q, idx, node);
+            idx++;
+            add_count(ct_im, i, j, im.rows, tree);
+        }
+        idx += tree.Mh; // last Mh pixels are border
+    }
+    
+    int l_id;
+    for ( int j = 0; j < tree.n_cls; j++) {
+        l_id = j*im.rows*im.cols;
+        for ( int i = 0; i < ct_im.size(); i++ ){
+            *(Q+i+l_id) = *(Q+i+l_id)/(double)ct_im[i];
+        }
+    }
+}
+
+
+// The gateway routine 
+void mexFunction( int nlhs, mxArray *plhs[],
+                  int nrhs, const mxArray *prhs[])
+{
+  // input image (I), tree (tree), probabilities (P) and output probabilities (Q)
+  double *I, *tree, *P, *Q;
+  int b, M, ndim, ndtree, ndprob;
+  const int *dim, *dtree, *dprob;
+  bool normalize = false;
+  /*  Check for proper number of arguments. */
+  /* NOTE: You do not need an else statement when using
+     mexErrMsgTxt within an if statement. It will never
+     get to the else statement if mexErrMsgTxt is executed.
+     (mexErrMsgTxt breaks you out of the MEX-file.) 
+  */
+  if(nrhs < 4 || nrhs > 5) 
+    mexErrMsgTxt("Four or five inputs required.");
+  if(nlhs != 1) 
+    mexErrMsgTxt("One output required.");
+    
+  // Create a pointer to the input matrix.
+  I = mxGetPr(prhs[0]);
+  tree = mxGetPr(prhs[1]);
+  P = mxGetPr(prhs[2]);
+  
+  double *bd;
+  bd = mxGetPr(prhs[3]);
+  b = (int)bd[0];
+  
+  if ( nrhs == 5 ){
+      bool *normalize_d;
+      normalize_d = (bool *)mxGetData(prhs[4]);
+      normalize = normalize_d[0];
+  }
+  
+  if ( b < 1 )
+    mexErrMsgTxt("b must be positive.");
+  
+  // Get the dimensions of the matrix input.
+  ndim = mxGetNumberOfDimensions(prhs[0]);
+  if (ndim != 2 && ndim != 3)
+    mexErrMsgTxt("probability_search_km_tree only works for 2-dimensional or 3-dimensional images.");
+
+  ndtree = mxGetNumberOfDimensions(prhs[1]);
+  if (ndtree != 2)
+    mexErrMsgTxt("probability_search_km_tree requires tree to be a matrix (2-dimensional).");
+
+  ndprob = mxGetNumberOfDimensions(prhs[2]);
+  if (ndprob != 2)
+    mexErrMsgTxt("probability_search_km_tree requires probability matrix to be a matrix (2-dimensional).");
+
+  dim = mxGetDimensions(prhs[0]);
+  dtree = mxGetDimensions(prhs[1]);
+  dprob = mxGetDimensions(prhs[2]);
+  
+  if ( dtree[1] != dprob[1] )
+    mexErrMsgTxt("Tree matrix and probability matrix must have the same number of columns.");
+  
+  if ( ndim == 3 )
+  {
+      M = (int)sqrt((double)dtree[0]/(double)dim[2]);
+  }
+  else
+  {
+      M = (int)sqrt((double)dtree[0]);
+  }
+  
+  if ( 1 - (M % 2)  || M < 1)
+    mexErrMsgTxt("M must be odd and positive.");
+  
+  
+  // image struct
+  im_st Im;
+  Im.im_data = I;
+  Im.rows = dim[0];
+  Im.cols = dim[1];
+  if ( ndim == 3 )
+  {
+      Im.layers = dim[2];
+  }
+  else
+  {
+      Im.layers = 1;
+  }
+  Im.n_pix = Im.rows*Im.cols;
+
+  // tree struct
+  tree_st Tree;
+  Tree.tree_data = tree;
+  Tree.probability_data = P;
+  Tree.n_dim = dtree[0];
+  Tree.n_nodes = dtree[1];
+  Tree.n_dprob = dprob[0];
+  Tree.branch_fac = b;
+  Tree.M = M;
+  Tree.Mh = (int)(0.5*(double)(M-1.0));
+  // Number of classes
+  Tree.n_cls = dprob[0]/(M*M);
+  // Compute relative displacement vector
+  Tree.idx_disp.reserve(dprob[0]);
+  int id;
+  for ( int k = 0; k < Tree.n_cls; k++ ){
+      id = -Tree.Mh*Im.rows - Tree.Mh + k*Im.rows*Im.cols;
+      for ( int i = 0; i < M; i++ ){
+          for ( int j = 0; j < M; j++ ){
+              Tree.idx_disp.push_back(id);
+              id++;
+          }
+      id+=Im.rows-M;
+      }
+  }
+//   for ( int i = 0; i < Tree.idx_disp.size(); i++ ){
+//       cout << Tree.idx_disp[i] << " ";
+//   }
+//   cout << endl;
+
+  
+  if ( M*M*Im.layers != Tree.n_dim )
+    mexErrMsgTxt("Dimensions of the tree and the image does not fit.");
+  
+  int ndpout[3] = {Im.rows, Im.cols, Tree.n_cls};
+  
+  // Set the output pointer to the output matrix. Array initialized to zero. 
+  plhs[0] = mxCreateNumericArray(3, ndpout, mxDOUBLE_CLASS, mxREAL);
+  
+  // Create a C pointer to a copy of the output matrix.
+  Q = mxGetPr(plhs[0]);
+  // Search the tree using the C++ subroutine
+  probability_search_image(Im, Tree, Q, normalize);
+}
+
diff --git a/code/texture_gui/code/functions/probability_search_km_tree.mexa64 b/code/texture_gui/code/functions/probability_search_km_tree.mexa64
new file mode 100755
index 0000000000000000000000000000000000000000..80a9ec4cb9d02af3b31b2d1b6f0df54720cd8d27
GIT binary patch
literal 18140
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
K{38arE&6ZNnPP+h

literal 0
HcmV?d00001

diff --git a/code/texture_gui/code/functions/probability_search_km_tree.mexmaci64 b/code/texture_gui/code/functions/probability_search_km_tree.mexmaci64
new file mode 100755
index 0000000000000000000000000000000000000000..86ce9e57e1823c0b786e2bedbfb5a8fbdd0aada4
GIT binary patch
literal 14168
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
Co7S}e

literal 0
HcmV?d00001

diff --git a/code/texture_gui/code/functions/probability_search_km_tree.mexw64 b/code/texture_gui/code/functions/probability_search_km_tree.mexw64
new file mode 100755
index 0000000000000000000000000000000000000000..14ed3e6c6fea7689c9c02ffc4a86221931b35546
GIT binary patch
literal 20992
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

literal 0
HcmV?d00001

diff --git a/code/texture_gui/code/functions/process_image.m b/code/texture_gui/code/functions/process_image.m
new file mode 100755
index 0000000..6dce460
--- /dev/null
+++ b/code/texture_gui/code/functions/process_image.m
@@ -0,0 +1,16 @@
+function [S,P] = process_image(im,dictionary)
+% segmentation and probabilities from and image and a dictionary
+
+im = normalize_image(im);
+P = probability_search_km_tree(im, ...
+    dictionary.tree, ...
+    dictionary.dictprob, ...
+    dictionary.options.branching_factor, ...
+    dictionary.options.normalization);
+
+[maxprob,S] = max(P,[],3);
+uncertain = sum(P == maxprob(:,:,ones(size(P,3),1)),3)>1; 
+S(uncertain) = 0;
+
+end
+
diff --git a/code/texture_gui/code/functions/search_km_tree.cpp b/code/texture_gui/code/functions/search_km_tree.cpp
new file mode 100755
index 0000000..3b9fcbc
--- /dev/null
+++ b/code/texture_gui/code/functions/search_km_tree.cpp
@@ -0,0 +1,239 @@
+/*=================================================================
+* syntax: A = search_km_tree(I, T, b, n); OR A = search_km_tree(I, T, b);
+*
+* serach_km_tree  - build assignment image from intensity image
+* 			
+* 			Input: 	- I: X-by-Y image
+* 					- T: MMl-by-K tree matrix  where l is the number of layers 
+*                        in the image (1 for grayscale and 3 for RGB)
+*                   - b: brancing factor
+*                   - n: normalization (true or false), defaults to false
+*
+* 			Output: - A: X-by-Y assignment matrix
+*
+* 			Author: Anders Dahl, abda@dtu.dk, december 2015.
+*=================================================================*/
+
+#include "mex.h"
+#include <stdio.h>
+#include <math.h>
+#include "matrix.h"
+#include <vector>
+
+#include <iostream>
+using namespace std;
+
+// struct for the tree
+struct tree_st
+{
+    double *tree_data;
+    int n_dim, n_nodes, branch_fac, M, Mh;
+};
+
+// struct for image
+struct im_st
+{
+    double *im_data;
+    int rows, cols, layers, n_pix;
+};
+
+// estimate the distance between a vector in tree given by the node and a 
+// patch in the image given by the row and column
+double get_dist(vector<double>& patch, tree_st& tree, int& node)
+{
+    double d = 0, tmp;
+    int id_t = tree.n_dim*node;
+    
+    for ( int i = 0; i < tree.n_dim; i++ ){
+        tmp = patch[i] - *(tree.tree_data + id_t);
+        id_t++;
+        d += tmp*tmp;
+    }
+    
+    return d;
+}
+
+
+// Function for sampling patches from the image into the patch arrays
+// inputs reference to the image struct, tree struct, patch struct and position of the sampling coordinate.
+// There is no check if the sampling is outside the image
+// vector<double> sample_patch(im_st& im, int& M, int r_im, int c_im, bool& normalize)
+vector<double> sample_patch(im_st& im, int& M, int r_im, int c_im, bool& normalize)
+{
+    int id_l, id_r, id_i; // iterators for looking up image data
+    int id_p = 0; // iterator for looking up patch data
+    double sum_sq = 0, pix_val; // variables for normalization
+    int n_dim = M*M*im.layers; // number of dimensions computed here, becasue tree is not included
+    vector<double> patch(n_dim);
+    int Mh = (M-1)/2;
+    
+    for ( int l = 0; l < im.layers; l++ ){ // image is sampled by three nested loops (layers, columns, rows)
+        id_l = im.n_pix*l;
+        for ( int i = c_im-Mh; i <= c_im+Mh; i++ ){
+            id_r = id_l + i*im.rows;
+            for ( int j = r_im-Mh; j <= r_im+Mh; j++ ){
+                id_i = id_r + j;
+                pix_val = *(im.im_data + id_i);
+                patch[id_p] = pix_val;
+                sum_sq += pix_val*pix_val; // sum of squares for normalization
+                id_p++;
+            }
+        }
+    }
+    if ( normalize ){ // if the patch should be normalized to unit length
+        double inv_sq = 1;
+        if ( sum_sq > 0 ){
+            inv_sq = 1/sqrt(sum_sq); // inverse sum of squares
+        }
+        for ( int i = 0; i < n_dim; i++ ){
+            patch[i] = patch[i]*inv_sq;
+        }
+    }
+    return patch;
+}
+
+
+// The tree search function
+int search_tree(im_st& im, tree_st& tree, int& r, int& c, bool& normalize)
+{
+    int node = 0, node_min = -1, node_min_level, next_node; // variables for searching the tree
+    double d_min = 10e100, d, d_min_level; 
+    
+    vector<double> patch = sample_patch(im, tree.M, c, r, normalize); // get the pixel values in a patch
+    while ( node < tree.n_nodes ){ // go through the tree
+        if ( *(tree.tree_data + node*tree.n_dim) == -1 ){ // check if node is a leaf-node
+            return node_min;
+        }
+        
+        d_min_level = 10e100; // set minimum distance to high value
+        for ( int i = 0; i < tree.branch_fac; i++ ){ // go through nodes at level 
+            next_node = node + i;
+            d = get_dist(patch, tree, next_node);
+            
+            if ( d < d_min_level ){ // set current node to the minimum distance
+                d_min_level = d;
+                node_min_level = next_node;
+            }
+        }
+        if ( d_min_level < d_min ){ // set overall minimum distance and minimum node
+            d_min = d_min_level;
+            node_min = node_min_level;
+        }
+        node = (node_min_level+1)*tree.branch_fac; // go to the child node
+    }
+    return node_min;
+}
+
+// The tree search function applied to the entire image - border is zero and interior is in 1,...,n
+void search_image(im_st& im, tree_st& tree, double *A, bool& normalize)
+{
+    int idx = tree.Mh*im.rows; // increase with empty rows at border
+    for ( int i = tree.Mh; i < im.cols-tree.Mh; i++ ){
+        idx += tree.Mh; // first Mh pixels are border
+        for ( int j = tree.Mh; j < im.rows-tree.Mh; j++ ){           
+            *(A + idx) = search_tree(im, tree, i, j, normalize) + 1; // find assignment
+            idx++;
+        }
+        idx += tree.Mh; // last Mh pixels are border
+    }
+}
+
+
+// The gateway routine 
+void mexFunction( int nlhs, mxArray *plhs[],
+                  int nrhs, const mxArray *prhs[])
+{
+  // input image (I), tree (tree) and output assignment (A)
+  double *I, *A, *tree;
+  int b, M, ndim, ndtree;
+  const int *dim, *dtree;
+  bool normalize = false;
+  /*  Check for proper number of arguments. */
+  /* NOTE: You do not need an else statement when using
+     mexErrMsgTxt within an if statement. It will never
+     get to the else statement if mexErrMsgTxt is executed.
+     (mexErrMsgTxt breaks you out of the MEX-file.) 
+  */
+  if(nrhs < 3 || nrhs > 4) 
+    mexErrMsgTxt("Three or four inputs required.");
+  if(nlhs != 1) 
+    mexErrMsgTxt("One output required.");
+    
+  // Create a pointer to the input matrix.
+  I = mxGetPr(prhs[0]);
+  tree = mxGetPr(prhs[1]);
+  
+  double *bd;
+  bd = mxGetPr(prhs[2]);
+  b = (int)bd[0];
+  
+  if ( nrhs == 4 ){
+      bool *normalize_d;
+      normalize_d = (bool *)mxGetData(prhs[3]);
+      normalize = normalize_d[0];
+  }
+  
+  if ( b < 1 )
+    mexErrMsgTxt("b must be positive.");
+  
+  // Get the dimensions of the matrix input.
+  ndim = mxGetNumberOfDimensions(prhs[0]);
+  if (ndim != 2 && ndim != 3)
+    mexErrMsgTxt("search_km_tree only works for 2-dimensional or 3-dimensional images.");
+
+  ndtree = mxGetNumberOfDimensions(prhs[1]);
+  if (ndtree != 2)
+    mexErrMsgTxt("search_km_tree only works for 2-dimensional tree.");
+
+  dim = mxGetDimensions(prhs[0]);
+  dtree = mxGetDimensions(prhs[1]);
+  
+  if ( ndim == 3 )
+  {
+      M = (int)sqrt((double)dtree[0]/(double)dim[2]);
+  }
+  else
+  {
+      M = (int)sqrt((double)dtree[0]);
+  }
+  
+  if ( 1 - (M % 2)  || M < 1)
+    mexErrMsgTxt("M must be odd and positive.");
+  
+  
+  // tree struct
+  tree_st Tree;
+  Tree.tree_data = tree;
+  Tree.n_dim = dtree[0];
+  Tree.n_nodes = dtree[1];
+  Tree.branch_fac = b;
+  Tree.M = M;
+  Tree.Mh = (int)(0.5*(double)(M-1.0));
+  
+  // image struct
+  im_st Im;
+  Im.im_data = I;
+  Im.rows = dim[0];
+  Im.cols = dim[1];
+  if ( ndim == 3 )
+  {
+      Im.layers = dim[2];
+  }
+  else
+  {
+      Im.layers = 1;
+  }
+  Im.n_pix = Im.rows*Im.cols;
+  
+  if ( M*M*Im.layers != Tree.n_dim )
+    mexErrMsgTxt("Dimensions of the tree and the image does not fit.");
+  
+  // Set the output pointer to the output matrix. Array initialized to zero. 
+  plhs[0] = mxCreateNumericArray(ndtree, dim, mxDOUBLE_CLASS, mxREAL);
+  
+  // Create a C pointer to a copy of the output matrix.
+  A = mxGetPr(plhs[0]);
+  // Search the tree using the C++ subroutine
+  search_image(Im, Tree, A, normalize);
+}
+
diff --git a/code/texture_gui/code/functions/search_km_tree.mexa64 b/code/texture_gui/code/functions/search_km_tree.mexa64
new file mode 100755
index 0000000000000000000000000000000000000000..1c413daea71625531c3473517f3c177df8cadac0
GIT binary patch
literal 13522
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
ZiNJCSGB5V80`d;c|3`u10rC0H|2J1ZN#Fng

literal 0
HcmV?d00001

diff --git a/code/texture_gui/code/functions/search_km_tree.mexmaci64 b/code/texture_gui/code/functions/search_km_tree.mexmaci64
new file mode 100755
index 0000000000000000000000000000000000000000..f6786b110627679ad91fbfd91cb9022bdf2b1a71
GIT binary patch
literal 13604
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

literal 0
HcmV?d00001

diff --git a/code/texture_gui/code/functions/search_km_tree.mexw64 b/code/texture_gui/code/functions/search_km_tree.mexw64
new file mode 100755
index 0000000000000000000000000000000000000000..cbe6d41e8ffdb3c5057845234410e9daeeebe734
GIT binary patch
literal 16896
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
Y976&4s&+T--n#q1Ze+hqe*+fyUw8Et5dZ)H

literal 0
HcmV?d00001

diff --git a/code/texture_gui/code/functions/search_km_tree_xcorr.cpp b/code/texture_gui/code/functions/search_km_tree_xcorr.cpp
new file mode 100755
index 0000000..20c722b
--- /dev/null
+++ b/code/texture_gui/code/functions/search_km_tree_xcorr.cpp
@@ -0,0 +1,239 @@
+#include "mex.h"
+#include <stdio.h>
+#include <math.h>
+#include "matrix.h"
+#include <vector>
+
+#include <iostream>
+using namespace std;
+
+/*
+ * This is a MEX-file for MATLAB.
+ * 
+ * Anders Bjorholm Dahl, 8/12-2015
+ *
+ *
+ */
+
+// struct for the tree
+struct tree_st
+{
+    double *tree_data;
+    int n_dim, inv_ndim, n_nodes, branch_fac, M, Mh;
+};
+
+// struct for image
+struct im_st
+{
+    double *im_data;
+    int rows, cols, layers, n_pix;
+};
+
+// estimate the distance between a vector in tree given by the node and a 
+// patch in the image given by the row and column
+double get_corr(vector<double>& patch, tree_st& tree, int& node)
+{
+    double corr = 0, tmp;
+    int id_t = tree.n_dim*node;
+    
+    for ( int i = 0; i < tree.n_dim; i++ ){
+        corr += patch[i]*(*(tree.tree_data + id_t));
+        id_t++;
+    }
+    
+    return corr;
+}
+
+// nomalize patch vectors to zero mean and unit Euclidean length
+void norm_patch(vector<double>& patch, double& mu, int n_dim){
+    
+    double sum_sq = 0;
+    
+    for ( int i = 0; i < n_dim; i++ ){
+        patch[i] = patch[i] - mu;
+        sum_sq += patch[i]*patch[i];
+    }
+    
+    double inv_sq = 1;
+    if ( sum_sq > 0 ){
+        inv_sq = 1.0/sqrt(sum_sq); // divide by sum of squares
+    }
+
+    for ( int i = 0; i < n_dim; i++ ){
+        patch[i] = patch[i]*inv_sq;
+    }
+}
+
+
+// Function for sampling patches from the image into the patch arrays
+// inputs reference to the image struct, tree struct, patch struct and position of the sampling coordinate.
+// There is no check if the sampling is outside the image
+// vector<double> sample_patch(im_st& im, int& M, int r_im, int c_im, bool& normalize)
+vector<double> sample_patch(im_st& im, int& M, int r_im, int c_im)
+{
+    int id_l, id_r, id_i; // iterators for looking up image data
+    int id_p = 0; // iterator for looking up patch data
+    double sum = 0, pix_val, mu; // variables for normalization
+    int n_dim = M*M*im.layers; // number of dimensions computed here, becasue tree is not included
+    vector<double> patch(n_dim);
+    int Mh = (M-1)/2;
+    
+    for ( int l = 0; l < im.layers; l++ ){ // image is sampled by three nested loops (layers, columns, rows)
+        id_l = im.n_pix*l;
+        for ( int i = c_im-Mh; i <= c_im+Mh; i++ ){
+            id_r = id_l + i*im.rows;
+            for ( int j = r_im-Mh; j <= r_im+Mh; j++ ){
+                id_i = id_r + j;
+                pix_val = *(im.im_data + id_i);
+                patch[id_p] = pix_val;
+                sum += pix_val; // sum for estimating the mean
+                id_p++;
+            }
+        }
+    }
+    
+    mu = sum/((double)n_dim); // mean value
+    norm_patch(patch, mu, n_dim); // nomalization
+
+    return patch;
+}
+
+
+// The tree search function
+int search_tree(im_st& im, tree_st& tree, int& r, int& c)
+{
+    int node = 0, node_max = -1, node_max_level, next_node; // variables for searching the tree
+    double corr_max = -1, corr, corr_max_level; 
+    
+    vector<double> patch = sample_patch(im, tree.M, c, r); // get the pixel values in a patch
+    while ( node < tree.n_nodes ){ // go through the tree
+        if ( *(tree.tree_data + node*tree.n_dim) == -1 ){ // check if node is a leaf-node
+            return node_max;
+        }
+        
+        corr_max_level = -1; // set correlation to low value
+        for ( int i = 0; i < tree.branch_fac; i++ ){ // go through nodes at level 
+            next_node = node + i;
+            corr = get_corr(patch, tree, next_node);
+            
+            if ( corr > corr_max_level ){ // set current node to the maximum correlation
+                corr_max_level = corr;
+                node_max_level = next_node;
+            }
+        }
+        if ( corr_max_level > corr_max ){ // set overall maximum correlation and corresponding node
+            corr_max = corr_max_level;
+            node_max = node_max_level;
+        }
+        node = (node_max_level+1)*tree.branch_fac; // go to the child node
+    }
+    return node_max;
+}
+
+// The tree search function applied to the entire image - border is zero and interior is in 1,...,n
+void search_image(im_st& im, tree_st& tree, double *A)
+{
+    int idx = tree.Mh*im.rows; // increase with empty rows at border
+    for ( int i = tree.Mh; i < im.cols-tree.Mh; i++ ){
+        idx += tree.Mh; // first Mh pixels are border
+        for ( int j = tree.Mh; j < im.rows-tree.Mh; j++ ){           
+            *(A + idx) = search_tree(im, tree, i, j) + 1; // find assignment
+            idx++;
+        }
+        idx += tree.Mh; // last Mh pixels are border
+    }
+}
+
+
+// The gateway routine 
+void mexFunction( int nlhs, mxArray *plhs[],
+                  int nrhs, const mxArray *prhs[])
+{
+  // input image (I), tree (tree) and output assignment (A)
+  double *I, *A, *tree;
+  int b, M, ndim, ndtree;
+  const int *dim, *dtree;
+  /*  Check for proper number of arguments. */
+  /* NOTE: You do not need an else statement when using
+     mexErrMsgTxt within an if statement. It will never
+     get to the else statement if mexErrMsgTxt is executed.
+     (mexErrMsgTxt breaks you out of the MEX-file.) 
+  */
+  if(nrhs != 3 ) 
+    mexErrMsgTxt("Three inputs required.");
+  if(nlhs != 1) 
+    mexErrMsgTxt("One output required.");
+    
+  // Create a pointer to the input matrix.
+  I = mxGetPr(prhs[0]);
+  tree = mxGetPr(prhs[1]);
+  
+  double *bd;
+  bd = mxGetPr(prhs[2]);
+  b = (int)bd[0];
+    
+  if ( b < 1 )
+    mexErrMsgTxt("b must be positive.");
+  
+  // Get the dimensions of the matrix input.
+  ndim = mxGetNumberOfDimensions(prhs[0]);
+  if (ndim != 2 && ndim != 3)
+    mexErrMsgTxt("search_km_tree only works for 2-dimensional or 3-dimensional images.");
+
+  ndtree = mxGetNumberOfDimensions(prhs[1]);
+  if (ndtree != 2)
+    mexErrMsgTxt("search_km_tree only works for 2-dimensional tree.");
+
+  dim = mxGetDimensions(prhs[0]);
+  dtree = mxGetDimensions(prhs[1]);
+  
+  if ( ndim == 3 )
+  {
+      M = (int)sqrt((double)dtree[0]/(double)dim[2]);
+  }
+  else
+  {
+      M = (int)sqrt((double)dtree[0]);
+  }
+  
+  if ( 1 - (M % 2)  || M < 1)
+    mexErrMsgTxt("M must be odd and positive.");
+  
+  
+  // tree struct
+  tree_st Tree;
+  Tree.tree_data = tree;
+  Tree.n_dim = dtree[0];
+  Tree.inv_ndim = 1/((double)Tree.n_dim);
+  Tree.n_nodes = dtree[1];
+  Tree.branch_fac = b;
+  Tree.M = M;
+  Tree.Mh = (int)(0.5*(double)(M-1.0));
+  
+  // image struct
+  im_st Im;
+  Im.im_data = I;
+  Im.rows = dim[0];
+  Im.cols = dim[1];
+  if ( ndim == 3 )
+  {
+      Im.layers = dim[2];
+  }
+  else
+  {
+      Im.layers = 1;
+  }
+  Im.n_pix = Im.rows*Im.cols;
+  
+  if ( M*M*Im.layers != Tree.n_dim )
+    mexErrMsgTxt("Dimensions of the tree and the image does not fit.");
+  
+  // Set the output pointer to the output matrix. Array initialized to zero. 
+  plhs[0] = mxCreateNumericArray(ndtree, dim, mxDOUBLE_CLASS, mxREAL);
+  
+  // Create a C pointer to a copy of the output matrix.
+  A = mxGetPr(plhs[0]);
+  // Search the tree using the C++ subroutine
+  search_image(Im, Tree, A);
+}
+
diff --git a/code/texture_gui/code/functions/search_km_tree_xcorr.mexa64 b/code/texture_gui/code/functions/search_km_tree_xcorr.mexa64
new file mode 100755
index 0000000000000000000000000000000000000000..0ac82cdef7ccd8a4ca18fcd4b65ed8df7fd7ec13
GIT binary patch
literal 13546
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
I>9bw_Us=^@WdHyG

literal 0
HcmV?d00001

diff --git a/code/texture_gui/code/functions/search_km_tree_xcorr.mexmaci64 b/code/texture_gui/code/functions/search_km_tree_xcorr.mexmaci64
new file mode 100755
index 0000000000000000000000000000000000000000..5f224caefe0987623c73d07353e150a8b390ada6
GIT binary patch
literal 13628
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
R-r;DlD{&~?cACL2{uf3;V@Ci0

literal 0
HcmV?d00001

diff --git a/code/texture_gui/code/functions/search_km_tree_xcorr.mexw64 b/code/texture_gui/code/functions/search_km_tree_xcorr.mexw64
new file mode 100755
index 0000000000000000000000000000000000000000..8d771be06e99b9fa7ee3d64aa69f4f7669f16de2
GIT binary patch
literal 17408
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
a?WKjm3cfje8uo18vwsh=U#33;3;ZiPLSfnf

literal 0
HcmV?d00001

diff --git a/code/texture_gui/code/functions/segmentation_correction_gui.m b/code/texture_gui/code/functions/segmentation_correction_gui.m
new file mode 100755
index 0000000..6df8c87
--- /dev/null
+++ b/code/texture_gui/code/functions/segmentation_correction_gui.m
@@ -0,0 +1,406 @@
+function segmentation_correction_gui(image,segmentation,nr_labels,labeling)
+%IMAGE_TEXTURE_GUI   Interactive segmentation correction
+
+%%%%%%%%%% DEFAULTS %%%%%%%%%%
+
+if nargin<1 % default example image
+    %image = imread('bag.png');
+    image = imread('football.jpg');
+end
+[r,c,~] = size(image);
+if nargin<2 || isempty(segmentation)% default segmentation
+    segmentation = zeros(r,c,'uint8');
+else
+    segmentation = uint8(segmentation);
+end
+if nargin<3 || isempty(nr_labels) % defalult number of labels
+    nr_labels = double(max(2,max(segmentation(:))));
+end
+if nargin<4 || isempty(labeling) % default, unlabeled initial correction
+    % TODO allow corrections to be inferred from labelings
+    DRAWING = zeros(r,c,'uint8');
+else
+    DRAWING = uint8(labeling);
+end
+
+%%%%%%%%%% SETTINGS %%%%%%%%%%
+
+% labels
+LABEL = 1; % initial label is 1
+
+% thickness
+thickness_options = [1 2 3 4 5 10 20 30 40 50 100 -1]; % last option (value -1) is 'fill'
+thickness_options_string = num2cell(thickness_options);
+thickness_options_string{end} = 'fill';
+THICKNESS_INDEX = 5; % initial pencil thickness is the fifth option
+RADIUS = thickness2radius(thickness_options(THICKNESS_INDEX)); % pencil radius
+
+% show
+show_options(1:2) = {'segmentation','overlay'};
+SHOW_INDEX = 1;
+
+% colormap
+colormap_options = {@(x)[0.5,0.5,0.5;cool(x)], @(x)[0.5,0.5,0.5;spring(x)],...
+    @(x)[0.5,0.5,0.5;parula(x)]}; % gray color for unlabeled
+COLORMAP_INDEX = 1; % current colormap
+COLORS = colormap_options{COLORMAP_INDEX}(nr_labels); % visualization colors for label overlay
+% other settings
+color_weight = 0.4; % color weight for label overlay
+nr_circle_pts = 16; % number of points defining a circular pencil
+
+%%%%%%%%%% INITIALIZATION AND LAYOUT %%%%%%%%%%
+[image,gray] = normalize_image(image); % impose 0-to-1 rgb
+CORRECTED = uint8(segmentation);
+CORRECTED(DRAWING~=0) = DRAWING(DRAWING~=0); % if initial corrections given
+DRAWING_OVERLAY = image; % image overlaid labeling
+CORRECTED_OVERLAY = ind2rgb(CORRECTED,COLORS);
+
+fmar = [0.2 0.2]; % discance from screen edge to figure (x and y)
+amar = [0.05 0.05]; % margin around axes, relative to figure
+my = 0.8:0.05:0.9; % menu items y position
+mh = 0.03; % menu items height
+cw = (0.4-0.3)/(nr_labels+1); % colorcube width
+cx = 0.3:cw:0.4; % colorcubes x position
+
+fig = figure('Units','Normalized','Position',[fmar,1-2*fmar],...
+    'Pointer','watch','KeyPressFcn',@key_press,'InvertHardCopy', 'off',...
+    'Name','Segmentation correction GUI');
+clean_toolbar
+
+labeling_axes = axes('Units','Normalized','Position',[0,0,0.5,0.8]+[amar,-2*amar]);
+imagesc(DRAWING_OVERLAY), axis image off, hold on
+segmentation_axes = axes('Units','Normalized','Position',[0.5,0,0.5,0.8]+[amar,-2*amar]);
+imagesc(CORRECTED_OVERLAY,[0,nr_labels]), axis image off, hold on
+
+uicontrol('String','Label [L] : ','Style','text','HorizontalAlignment','right',...
+    'Units','Normalized','Position',[0,my(3),0.25,mh]);
+labels_text = uicontrol('String',num2str(LABEL),...
+    'BackgroundColor',COLORS(LABEL+1,:),...
+    'Style','text','HorizontalAlignment','left',...
+    'Units','Normalized','Position',[0.25,my(3),0.03,mh]);
+label_pointer = cell(nr_labels+1,1);
+label_colorcubes = cell(nr_labels+1,1);
+label_char = repmat(' ',[1,nr_labels+1]);
+label_char(LABEL+1)='|';
+for k = 1:nr_labels+1
+    label_colorcubes{k} = uicontrol('String',' ','Style','text',...
+        'BackgroundColor',COLORS(k,:),...
+        'Units','Normalized','Position',[cx(k),my(3),cw,mh/2]);
+    label_pointer{k} = uicontrol('String',label_char(k),'Style','text',...
+        'HorizontalAlignment','center',...
+        'Units','Normalized','Position',[cx(k),my(3)+mh/2,cw,mh/2]);
+end
+
+uicontrol('String','Thickness [T] : ','Style','text','HorizontalAlignment','right',...
+    'Units','Normalized','Position',[0,my(2),0.25,mh]);
+thickness_text = uicontrol('String',thickness_options_string(THICKNESS_INDEX),...
+    'Style','text','HorizontalAlignment','left',...
+    'Units','Normalized','Position',[0.25,my(2),0.25,mh]);
+
+uicontrol('String','Show [W] :','Style','text','HorizontalAlignment','right',...
+    'Units','Normalized','Position',[0,my(1),0.25,mh]);
+show_text = uicontrol('String',show_options{SHOW_INDEX},...
+    'Style','text','HorizontalAlignment','left',...
+    'Units','Normalized','Position',[0.25,my(1),0.25,mh]);
+
+drawnow % pointer shows busy system
+
+LIMITS = [1,c-0.5,1,r+0.5]; % to capture zoom
+zoom_handle = zoom(fig);
+pan_handle = pan(fig);
+set(zoom_handle,'ActionPostCallback',@adjust_limits,...
+    'ActionPreCallback',@force_keep_key_press);
+set(pan_handle,'ActionPostCallback',@adjust_limits,...
+    'ActionPreCallback',@force_keep_key_press);
+
+compute_overlays
+
+% ready to draw
+set(fig,'Pointer','arrow','WindowButtonDownFcn',@start_draw,...
+    'WindowButtonMotionFcn',@pointer_motion);
+XO = []; % current drawing point
+uiwait % waits with assigning output until a figure is closed
+
+%%%%%%%%%% CALLBACK FUNCTIONS %%%%%%%%%%
+    function key_press(~,object)
+        % keyboard commands
+        key = object.Key;
+        numkey = str2double(key);
+        if ~isempty(numkey) && numkey<=nr_labels;
+            label_char(LABEL+1)=' ';
+            LABEL = numkey;
+            set(labels_text,'String',num2str(LABEL),...
+                'BackgroundColor',COLORS(LABEL+1,:));
+            label_char(LABEL+1)='|';
+            for kk = 1:nr_labels+1
+                set(label_pointer{kk},'String',label_char(kk));
+            end
+        else
+            switch key
+                case 'l'
+                    label_char(LABEL+1)=' ';
+                    LABEL = move_once(LABEL+1,nr_labels+1,...
+                        any(strcmp(object.Modifier,'shift')))-1;
+                    set(labels_text,'String',num2str(LABEL),...
+                        'BackgroundColor',COLORS(LABEL+1,:));
+                    label_char(LABEL+1)='|';
+                    for kk = 1:nr_labels+1
+                        set(label_pointer{kk},'String',label_char(kk));
+                    end
+                case 'uparrow'
+                    THICKNESS_INDEX = move_once(THICKNESS_INDEX,...
+                        numel(thickness_options),false);
+                    RADIUS = thickness2radius(thickness_options(THICKNESS_INDEX));
+                    set(thickness_text,'String',...
+                        thickness_options_string(THICKNESS_INDEX));
+                    show_overlays(get_pixel);
+                case 'downarrow'
+                    THICKNESS_INDEX = move_once(THICKNESS_INDEX,...
+                        numel(thickness_options),true);
+                    RADIUS = thickness2radius(thickness_options(THICKNESS_INDEX));
+                    set(thickness_text,'String',...
+                        thickness_options_string(THICKNESS_INDEX));
+                    show_overlays(get_pixel);
+                case 't'
+                    THICKNESS_INDEX = move_once(THICKNESS_INDEX,...
+                        numel(thickness_options),any(strcmp(object.Modifier,'shift')));
+                    RADIUS = thickness2radius(thickness_options(THICKNESS_INDEX));
+                    set(thickness_text,'String',...
+                        thickness_options_string(THICKNESS_INDEX));
+                    show_overlays(get_pixel);
+                case 'w'
+                    SHOW_INDEX = move_once(SHOW_INDEX,numel(show_options),...
+                        any(strcmp(object.Modifier,'shift')));
+                    set(show_text,'String',show_options{SHOW_INDEX})
+                    compute_overlays
+                    show_overlays(get_pixel);
+                case 'c'
+                    COLORMAP_INDEX = move_once(COLORMAP_INDEX,...
+                        length(colormap_options),...
+                        any(strcmp(object.Modifier,'shift')));
+                    COLORS = colormap_options{COLORMAP_INDEX}(nr_labels);
+                    set(labels_text,'BackgroundColor',COLORS(LABEL+1,:));
+                    for kk = 1:nr_labels+1
+                        set(label_colorcubes{kk},'BackgroundColor',COLORS(kk,:))
+                    end
+                    compute_overlays
+                    show_overlays(get_pixel);
+                case 's'
+                    save_project
+                case 'e'
+                    export_DC
+                case 'q'
+                    close(fig)
+            end
+        end
+    end
+
+    function adjust_limits(~,~)
+        % response to zooming and panning
+        LIMITS([1,2]) = get(labeling_axes,'XLim');
+        LIMITS([3,4]) = get(labeling_axes,'YLim');
+    end
+
+    function force_keep_key_press(~,~)
+        % a hack to maintain my key_press while in zoom and pan mode
+        % http://undocumentedmatlab.com/blog/enabling-user-callbacks-during-zoom-pan
+        hManager = uigetmodemanager(fig);
+        [hManager.WindowListenerHandles.Enabled] = deal(false);
+        set(fig, 'KeyPressFcn', @key_press);
+    end
+
+    function start_draw(~,~)
+        % click in the image
+        x = get_pixel;
+        if is_inside(x)
+            if RADIUS>0 % thickness>0
+                XO = x;
+                M = disc(XO,RADIUS,nr_circle_pts,[r,c]);
+                set(fig,'WindowButtonMotionFcn',@drag_and_draw,...
+                    'WindowButtonUpFcn',@end_draw)
+            else % fill
+                M = fill(x);
+            end
+            update(M);
+        end
+    end
+
+    function drag_and_draw(~,~)
+        % drag after clicking in the image
+        x = get_pixel;
+        M = stadium(XO,x,RADIUS,nr_circle_pts,[r,c]);
+        update(M);
+        XO = x;
+    end
+
+    function end_draw(~,~)
+        % release click after clicking in the image
+        M = stadium(XO,get_pixel,RADIUS,nr_circle_pts,[r,c]);
+        update(M);
+        XO = [];
+        set(fig,'WindowButtonMotionFcn',@pointer_motion,...
+            'WindowButtonUpFcn','')
+    end
+
+    function pointer_motion(~,~)
+        % move around without clicking
+        if strcmp(zoom_handle.Enable,'off') && ...
+                strcmp(pan_handle.Enable,'off') % not zooming or panning
+            x = get_pixel;
+            if is_inside(x)
+                set(fig,'Pointer','crosshair')
+            else
+                set(fig,'Pointer','arrow')
+            end
+            show_overlays(x);
+        end
+    end
+
+%%%%%%%%%% HELPING FUNCTIONS %%%%%%%%%%
+
+    function save_project
+        % save mat file with user input and setting
+        % save images as separate files
+        [file,path] = uiputfile('correction.mat','Save project as');
+        if ~isequal(file,0) && ~isequal(path,0)
+            matfile = fullfile(path,file);
+            roothname = matfile(1:find(matfile=='.',1,'last')-1);
+            current_settings.show = show_options{SHOW_INDEX};
+            save(matfile,'DRAWINGS','CORRECTED',...
+                'dictopt','nr_labels','current_settings')
+            imwrite(DRAWING_OVERLAY,[roothname,'_drawing.png'])
+            imwrite(CORRECTED_OVERLAY,[roothname,'_corrected.png'])
+        end
+    end
+
+    function export_DC
+        button = questdlg({'Exporting variables to the base workspace',...
+            'might overwrite existing variables'},...
+            'Exporting variables','OK','Cancel','OK');
+        if strcmp(button,'OK')
+            assignin('base','gui_D',DRAWING)
+            assignin('base','gui_C',CORRECTED)
+        end
+        
+    end
+
+    function a = is_inside(x)
+        % check if x is inside image limits
+        a = inpolygon(x(1),x(2),LIMITS([1,2,2,1]),LIMITS([3,3,4,4]));
+    end
+
+    function p = get_pixel
+        % get cursor position
+        p = get(labeling_axes,'CurrentPoint');
+        p = round(p(1,[1,2]));
+    end
+
+    function show_overlays(x)
+        % overlay a circular region where the pointer and show
+        shown_left = DRAWING_OVERLAY;
+        shown_right = CORRECTED_OVERLAY;
+        if RADIUS>0 % thickness>0
+            P = repmat(disc(x,RADIUS,nr_circle_pts,[r,c]),[1,1,3]);
+            shown_left(P(:)) = 0.5+0.5*DRAWING_OVERLAY(P(:));
+            shown_right(P(:)) = 0.5+0.5*CORRECTED_OVERLAY(P(:));
+        end
+        % we have to imagesc(shown) to remove overlay if needed
+        axes(labeling_axes), cla, imagesc(shown_left)
+        axes(segmentation_axes), cla, imagesc(shown_right)
+    end
+
+    function update(M)
+        % change the state of the segmentation by updating LABELINGS with a
+        % mask M, and updating PROBABILITIES
+        DRAWING(M(:)) = LABEL;
+        if LABEL>0
+            CORRECTED(M(:)) = LABEL;
+        else
+            CORRECTED(M(:)) = segmentation(M(:));
+        end
+        compute_overlays % computing overlay images
+        show_overlays(get_pixel); % showing overlay and pointer
+    end
+
+    function compute_overlays
+        % computes overlays but not pointer overalay
+        uncorrected = repmat(DRAWING==0,[1 1 3]);
+        DRAWING_OVERLAY = uncorrected.*image + ~uncorrected.*...
+            (color_weight.*ind2rgb(DRAWING,COLORS) + (1-color_weight).*gray);
+        switch show_options{SHOW_INDEX}
+            case 'segmentation'
+                CORRECTED_OVERLAY = ind2rgb(CORRECTED,COLORS);
+            case 'overlay'
+                CORRECTED_OVERLAY = color_weight*...
+                    ind2rgb(CORRECTED,COLORS) + (1-color_weight)*gray;
+        end
+    end
+
+% TODO disc shold be saved as a list of index shifts with respect to
+% the central pixel, and change only when thickness changes
+    function M = disc(x,r,N,dim)
+        % disc shaped mask in the image
+        angles = (0:2*pi/N:2*pi*(1-1/N));
+        X = x(1)+r*cos(angles);
+        Y = x(2)+r*sin(angles);
+        M = poly2mask(X,Y,dim(1),dim(2));
+    end
+
+    function M = stadium(x1,x2,r,N,dim)
+        % stadium shaped mask in the image
+        angles = (0:2*pi/N:pi)-atan2(x1(1)-x2(1),x1(2)-x2(2));
+        X = [x1(1)+r*cos(angles), x2(1)+r*cos(angles+pi)];
+        Y = [x1(2)+r*sin(angles), x2(2)+r*sin(angles+pi)];
+        M = poly2mask(X,Y,dim(1),dim(2));
+    end
+
+    function M = fill(x)
+        M = bwselect(DRAWING==DRAWING(x(2),x(1)),x(1),x(2),4);
+    end
+
+    function [I,G] = normalize_image(I)
+        % initialization: normalize image
+        if isa(I,'uint8')
+            I = double(I)/255;
+        end
+        if isa(I,'uint16')
+            I = double(I)/65535;
+        end
+        if size(I,3)==3 % rgb image
+            G = repmat(rgb2gray(I),[1 1 3]);
+        else % assuming grayscale image
+            I = repmat(I,[1,1,3]);
+            G = I;
+        end
+    end
+
+    function n = move_once(n,total,reverse)
+        % moves option index once, respecting total number of options
+        if ~reverse
+            n = mod(n,total)+1;
+        else
+            n = mod(n+total-2,total)+1;
+        end
+    end
+
+    function r = thickness2radius(t)
+        r = t/2+0.4;
+    end
+
+    function clean_toolbar
+        set(fig,'MenuBar','none','Toolbar','figure');
+        all_tools = allchild(findall(fig,'Type','uitoolbar'));
+        %my_tool = uipushtool(toolbar,'CData',rand(16,16,3),'Separator','on',...
+        %            'TooltipString','my tool','Tag','my tool');
+        for i=1:numel(all_tools)
+            if isempty(strfind(all_tools(i).Tag,'Pan'))&&...
+                    isempty(strfind(all_tools(i).Tag,'Zoom'))&&...
+                    isempty(strfind(all_tools(i).Tag,'SaveFigure'))&&...
+                    isempty(strfind(all_tools(i).Tag,'PrintFigure'))&&...
+                    isempty(strfind(all_tools(i).Tag,'DataCursor'))
+                delete(all_tools(i)) % keeping only Pan, Zoom, Save and Print
+            end
+        end
+    end
+
+end
diff --git a/code/texture_gui/code/functions/update_dictionary.m b/code/texture_gui/code/functions/update_dictionary.m
new file mode 100755
index 0000000..11627b2
--- /dev/null
+++ b/code/texture_gui/code/functions/update_dictionary.m
@@ -0,0 +1,9 @@
+function dictionary = update_dictionary(dictionary,gui_dictprob)
+
+M = dictionary.options.patch_size;
+nr_dict_patches = size(dictionary.tree,2);
+L = size(gui_dictprob,2); % nr labels
+gui_dictprob = reshape(gui_dictprob,[M^2,nr_dict_patches,L]);
+gui_dictprob = permute(gui_dictprob,[1,3,2]);
+gui_dictprob = reshape(gui_dictprob,[M^2*L,nr_dict_patches]);
+dictionary.dictprob = gui_dictprob;
\ No newline at end of file
diff --git a/code/texture_gui/code/reusing_labels_script.m b/code/texture_gui/code/reusing_labels_script.m
new file mode 100755
index 0000000..f25eb92
--- /dev/null
+++ b/code/texture_gui/code/reusing_labels_script.m
@@ -0,0 +1,23 @@
+clear 
+close all
+addpath functions
+
+% example of re-using externaly made labeling image
+im = imread('../data/randen15B.png'); % randen 5 textures
+labeling = double(imread('../data/randen_labels_rgb.png'));
+dictopt.patch_size = 15;
+dictopt.branching_factor = 4;
+dictopt.number_layers = 4;
+dictopt.number_training_patches = 2000;
+dictopt.normalization = false;
+dictopt.method = 'euclidean';
+image_texture_gui(im,dictopt,5,labeling)
+
+%% an image exported from gui can be re-used 
+image_texture_gui(im,dictopt,5) %% <- EXPORT (E) labeling here
+image_texture_gui(im,dictopt,5,gui_L) %% <- use labeling here
+
+%% an image saved from gui can be re-used 
+image_texture_gui(im,dictopt,5) %% <- SAVE (S) labeling here using some filename
+image_texture_gui(im,dictopt,5,imread('filename_labels_indexed.png')) %% <- use labeling here
+
diff --git a/code/texture_gui/code/test.m b/code/texture_gui/code/test.m
new file mode 100755
index 0000000..b05b7fd
--- /dev/null
+++ b/code/texture_gui/code/test.m
@@ -0,0 +1,31 @@
+addpath('functions')
+%%
+fig = figure;
+imagesc(rand(200,200));
+set(fig,'MenuBar','none','Toolbar','figure');
+
+%%
+toolbar = findall(fig,'Type','uitoolbar');
+all_tools = allchild(toolbar);
+% removing tools
+for i=1:numel(all_tools)
+    t = get(all_tools(i),'Tag');
+    if isempty(strfind(t,'Pan'))&&...
+            isempty(strfind(t,'Zoom'))&&...
+            isempty(strfind(t,'SaveFigure'))&&...
+            isempty(strfind(t,'PrintFigure'))&&...
+            isempty(strfind(t,'DataCursor'))
+        delete(all_tools(i)) % keeping only Pan, Zoom, Save and Print
+    end
+end
+%% adding a tool
+[icon,~,alpha] = imread('linkaxesicon.png');
+icon = double(icon)/255;
+icon(alpha==0)=NaN;
+uitoggletool(toolbar,'CData',icon,...
+    'TooltipString','Link Axes','Tag','LinkAxes',...
+    'OnCallback',{@link_axes,'xy'},...
+    'OffCallback',{@link_axes,'off'});
+%% changing the order of tools
+all_tools = allchild(toolbar);
+set(toolbar,'children',all_tools([2,1,3:end]));
\ No newline at end of file
diff --git a/code/texture_gui/code/texture_gui_uses_script.m b/code/texture_gui/code/texture_gui_uses_script.m
new file mode 100755
index 0000000..aa2c156
--- /dev/null
+++ b/code/texture_gui/code/texture_gui_uses_script.m
@@ -0,0 +1,29 @@
+clear 
+close all
+
+addpath functions
+
+%% demo: no input
+image_texture_gui
+
+%% usage 1: only image (default dictionary options )
+im = double(imread('bag.png'))/255; 
+image_texture_gui(im)
+
+%% usage 2: image and dictionary options
+dictopt.method = 'euclidean';
+dictopt.patch_size = 11;
+dictopt.branching_factor = 2;
+dictopt.number_layers = 5;
+dictopt.number_training_patches = 30000;
+dictopt.normalization = false;
+image_texture_gui(im,dictopt,5)
+
+%% usage 3: image and dictionary
+dictionary = build_dictionary(im,dictopt);
+image_texture_gui(im,dictionary,2)
+
+%% usage 4: image and mappings
+mappings = compute_mappings(im,dictionary);
+image_texture_gui(im,mappings,2)
+
-- 
GitLab