Diploma thesis - Metrics for determination of patterns similarity
Tomáš Krč
2014

All the sections and subsections can be collapsed and opened in order to manage the readibility of this document. First step should be to evaluate the initialization cells.

1. Loading ink jet paper images and computing their SVD’s

Functions definition

LoadImageNames[path] will load all the ink jet paper filenames from specified path into one vector.
importImageAndCalculateSVD[fileName,sizeSVD,numPatches,PatchSize] imports one image at a time specified by it’s filename to prevent memory issues and calculates it’s SVD matrices using 3 parameters.
SVDsofAllImages[path,sizeSVD,numPtches,patchSize] basically just calls importImageAndCalculateSVD[] for all the images in specified path, not just one.
calculateSVDs[images,sizeSVD,numPatches,patchSize] works the same way as SVDsofALLImages[], except the input can be any array of actual images, instead of importing them form defined folder.
readFunOne[filename, slices,{mh,mw}] generates a given number of random patches (slices) of given size (mh,mw) from image that it imports using it’s filename.
readFun[image,slices,{mh,mw}] does exactly the same thing as readFunOne[], except it doesn’t import the image but is given one as an input parameter.
buildFeatures[img] collapses the patch into a single vector, substracts the mean from it.
loadSVDs[uAllname,wAllname] just loads the SVD matrices from previously exported files, saving time and calculations.

LoadImageNames[path_]:=Module[{microRakingPath,microImages},SetDirectory[NotebookDirectory[]];
microImages=FileNames["*.tif",path];
Return[microImages];]

importImageAndCalculateSVD[fileName_,sizeSVD_,numPatches_,patchSize_]:=Module[{allPatches,allFeatures,j,uAll,wAll,v},
allPatches=Flatten[readFunOne[fileName,numPatches,{patchSize,patchSize}]];
allFeatures=Table[buildFeatures[allPatches[[j]]],{j,1,numPatches}];
{uAll,wAll,v}=SingularValueDecomposition[Transpose[allFeatures],sizeSVD];
Return[{uAll,wAll}]]

SVDsofAllImages[path_,sizeSVD_,numPatches_,patchSize_]:=Module[{microImages,variable,uAll,wAll,i},
microImages=LoadImageNames[path];
variable=importImageAndCalculateSVD[#,sizeSVD,numPatches,patchSize]&/@microImages;
uAll=Table[variable[[i,1]],{i,1,Length[microImages]}];
wAll=Table[variable[[i,2]],{i,1,Length[microImages]}];
Return[{uAll,wAll}]]

calculateSVDs[images_,sizeSVD_,numPatches_,patchSize_]:=Module[{allPatches,allFeatures,uAll,wAll,numPics,i,j,u,w,v},numPics=Length[images];
allPatches=Table[Flatten[readFun[images[[i]],numPatches,{patchSize,patchSize}]],{i,1,numPics}];allFeatures=Table[buildFeatures[allPatches[[i,j]]],{i,1,numPics},{j,1,numPatches}];
uAll=ConstantArray[{},numPics];
wAll=ConstantArray[{},numPics];
Table[{u,w,v}=SingularValueDecomposition[Transpose[allFeatures[[i]]],sizeSVD];
uAll[[i]]=u;wAll[[i]]=w;,{i,1,numPics}];
Return[{uAll,wAll}]]

readFunOne[fileName_,slices_,{mh_,mw_}]:=Module[{img,imgH,imgW,subImgs,indH,indW,p},img=Import[fileName];
{imgW,imgH}=ImageDimensions[img];
indH=RandomVariate[DiscreteUniformDistribution[{1,imgH-mh}],slices];
indW=RandomVariate[DiscreteUniformDistribution[{1,imgW-mw}],slices];
Table[ImageTake[img,{indH[[p]],indH[[p]]+mh-1},{indW[[p]],indW[[p]]+mw-1}],{p,1,slices}]];

readFun[image_,slices_,{mh_,mw_}]:=Module[{img,imgH,imgW,subImgs,indH,indW,p},img=image;
{imgW,imgH}=ImageDimensions[img];
indH=RandomVariate[DiscreteUniformDistribution[{1,imgH-mh}],slices];
indW=RandomVariate[DiscreteUniformDistribution[{1,imgW-mw}],slices];
Table[ImageTake[img,{indH[[p]],indH[[p]]+mh-1},{indW[[p]],indW[[p]]+mw-1}],{p,1,slices}]];

buildFeatures[img_]:=Module[{flatImg},flatImg=Flatten[ImageData[img]];
flatImg-Mean[flatImg]];

loadSVDs[uAllname_,wAllname_]:=Module[{uAll,wAll},SetDirectory[NotebookDirectory[]];
uAll=Import[uAllname];
wAll=Import[wAllname];
Return[{uAll,wAll}]]

2. Matrix distance

Usual distance metrics

Three usual distance metrics are defined below. Minkowski distance, ASM distance and Yang distance. Output of those function is a corresponding similarity matrix.

minkowskiDist[matrix1_,matrix2_,x_]:=(Total[Total[(Abs[matrix1-matrix2])^x,{2}],{1}])^(1/x) 
(*
Parameter x=1->Manhattan model
Parameter x=2->Euclidean distance (=Frobenius distance)
Parameter x=>inf->Chebyshev distance
*)

asmDistance[matrix1_,matrix2_,x_]:=(Total[(Total[(matrix1-matrix2)^2,{2}])^((1*x)/2),{1}])^(1/x)

yangDistance[matrix1_,matrix2_]:=Total[(Total[(matrix1-matrix2)^2,{2}])^(1/2),{1}]

Distance similarities

Functions to compue weight vector, EROS similarity, PCA similarity and Cosine similarity are below. Again, output of the similarities is similarity matrix.

weightVector[wAll_,dimensions_]:=Module[{diagonalW,diagonalW2,wiTemp,wiTemp2,i},
diagonalW=Transpose[Table[Diagonal[wAll[[i]]],{i,1,dimensions[[1]]}]];
diagonalW2=Transpose[Table[diagonalW[[All,i]]/Total[diagonalW[[All,i]]],{i,1,dimensions[[1]]}]];
wiTemp=Table[Mean[diagonalW2[[i,All]]],{i,1,dimensions[[3]]}];
wiTemp2=Table[wiTemp[[i]]/Total[wiTemp],{i,1,dimensions[[3]]}]];

erosDistance[uAll_,wAll_,dimensions_]:=Module[{i,k,l},
Table[Total[Table[weightVector[wAll,dimensions][[i]] Abs[uAll[[k,All,i]].uAll[[l,All,i]]],{i,dimensions[[3]]}]],{k,dimensions[[1]]},{l,dimensions[[1]]}]]

pcaDistance[uAll_,wAll_,dimensions_]:=Module[{em,el,i,j},Table[em=Transpose[uAll[[i]]];el=Transpose[uAll[[j]]];Tr[el.Transpose[em].DiagonalMatrix[weightVector[wAll,dimensions]].em.Transpose[el]],{i,1,dimensions[[1]]},{j,1,dimensions[[1]]}]]

cosDistance[uAll_,wAll_,dimensions_]:=Module[{i,k,l},weightVector[wAll,dimensions].Table[Max[Abs[uAll[[l,All,i]].uAll[[k,All,All]]]],{i,dimensions[[3]]},{k,dimensions[[1]]},{l,dimensions[[1]]}]]

Functions bellow can be used to classify just one SVD matrix instead of all of them.

erosDistanceOne[uAll_,thisuAll_,weightV_,dimensions_]:=Module[{i,k},
Table[Total[Table[weightV[[i]] Abs[uAll[[k,All,i]].thisuAll[[All,i]]],{i,dimensions[[3]]}]],{k,1,dimensions[[1]]}]]

pcaDistanceOne[uAll_,thisuAll_,weightV_,dimensions_]:=Module[{el,em,i},
Table[em=Transpose[uAll[[i]]];el=Transpose[thisuAll];
Tr[el.Transpose[em].DiagonalMatrix[weightV].em.Transpose[el]],{i,1,dimensions[[1]]}]]

cosDistanceOne[uAll_,thisuAll_,weightV_,dimensions_]:=Module[{},
weightV.Table[Max[Abs[thisuAll[[All,i]].uAll[[k,All,All]]]],{i,dimensions[[3]]},{k,dimensions[[1]]}]]

Functions for calculating and plotting both usual metrics and similarities

calculateUsualDistances[uAll_]:=Module[{dMinkowski,dASM,dYang},
dMinkowski=Table[minkowskiDist[uAll[[i]],#,2]&/@uAll,{i,1,Length[uAll]}];
dASM=Table[asmDistance[uAll[[i]],#,0.125]&/@uAll,{i,1,Length[uAll]}];
dYang=Table[yangDistance[uAll[[i]],#]&/@uAll,{i,1,Length[uAll]}];
Return[{dMinkowski,dASM,dYang}]
]

calculateDistances[uAll_,wAll_]:=Module[{ed,epca,ecos,dimensions},
dimensions=Dimensions[uAll];
ed=erosDistance[uAll,wAll,dimensions];
epca=pcaDistance[uAll,wAll,dimensions];
ecos=cosDistance[uAll,wAll,dimensions];
Return[{ed,epca,ecos}]
]

drawDistances[dEROS_,dPCA_,dCOS_]:=Module[{},
Labeled[Grid[{Text@Style[#,"TableHeader",Larger]&/@{"EROS similarity","PCA similarity","Cosine similarity"},{ArrayPlot[dEROS-Min[dEROS],ImageSize->270],ArrayPlot[dPCA-Min[dPCA],ImageSize->270],ArrayPlot[dCOS-Min[dCOS],ImageSize->270]},Text@Style[#,"Text",Larger]&/@{Min[dEROS],Min[dPCA],Min[dCOS]}},
Alignment->{Center,{Bottom,Top}},Frame->All,Spacings->{0,1}],Text@Style["Vizualization of similarity matrices for distance similarities and corresponding minimal values","Text",Larger],{{Bottom,Center}}]]

drawUsualDistances[dMinkowski_,dASM_,dYang_]:=Module[{},
Labeled[Grid[{Text@Style[#,"TableHeader",Larger]&/@{"Minkowski distance (Frobenius norm)","ASM distance","Yang distance"},{Image[ColorNegate[ArrayPlot[dMinkowski]],ImageSize->270],Image[ColorNegate[ArrayPlot[dASM]],ImageSize->270],Image[ColorNegate[ArrayPlot[dYang]],ImageSize->270]}},
Alignment->{Center,{Bottom,Top}},Frame->All,Spacings->{0,1}],Text@Style["Vizualization of similarity matrices for usual distance measures","Text",Larger],{{Bottom,Center}}]]

3. Voting algorithm

Function doClassification[] is used for computing the original voting algorithm and all the combinations of voting algorithm with matrix similarities. One can needs to specify the type of algorithm (“EROS”,”PCA”,”COS”,”SimWI”), SVD matrices and path where to find the images, and also select the number of image that should be classified with certain number of drawn patches (noted as “Q” in the text).
Function simWI[] can be used to calculate the overal assesment (noted as “g” in text) from the sorted counts obtained by doClassification[].

doClassification[distanceType_,uAll_,wAll_,path_,images_,thisClass_,numTests_]:=Module[{allImages,thisImage,imgTest,testFeatures,distClasses,closestOnes,result,weightV,uAllNew,wAllNew,v,tempVector,dimensions,el,em},
allImages=LoadImageNames[path][[images]];
thisImage=LoadImageNames[path][[thisClass]];
dimensions=Dimensions[uAll];

If[distanceType=="SimWI",
imgTest=Flatten[readFunOne[thisImage,numTests,{patchSize,patchSize}]];
testFeatures=Table[buildFeatures[imgTest[[j]]],{j,1,numTests}];
distClasses=Table[Norm[testFeatures[[i]]-uAll[[j]].(Transpose[uAll[[j]]].testFeatures[[i]])],{i,1,numTests},{j,1,dimensions[[1]]}];
closestOnes=Table[Ordering[distClasses[[i]]][[1]],{i,1,numTests}];
result=Reverse[Sort[Tally[closestOnes],#1[[2]]<#2[[2]]&]],

weightV=weightVector[wAll,dimensions];

closestOnes=Table[imgTest=Flatten[readFunOne[thisImage,numTests,{patchSize,patchSize}]];
testFeatures=Table[buildFeatures[imgTest[[j]]],{j,1, numTests}];
{uAllNew,wAllNew,v}=SingularValueDecomposition[Transpose[testFeatures],sizeSVD];

If[distanceType=="EROS",
tempVector=Table[Total[Table[weightV[[i]] Abs[uAll[[k,All,i]].uAllNew[[All,i]]],{i,dimensions[[3]]}]],{k,1,dimensions[[1]]}]];

If[distanceType=="PCA",
tempVector=Table[em=Transpose[uAll[[k,All]]];el=Transpose[uAllNew];Tr[el.Transpose[em].DiagonalMatrix[weightV.em.Transpose[el]]],{k,1,dimensions[[1]]}]];

If[distanceType=="COS",
tempVector=weightV.Table[Max[Abs[uAllNew[[All,i]].uAll[[k,All,All]]]],{i,dimensions[[3]]},{k,dimensions[[1]]}]];

Position[tempVector,Max[tempVector]],{m,1,numTests}];
result=Reverse[Sort[Tally[Flatten[closestOnes]],#1[[2]]<#2[[2]]&]]];
Table[result[[j,1]]=images[[result[[j,1]]]],{j,Dimensions[result][[1]]}];
Return[result]];

simWI[allTest_]:=Module[{qual,res,pw,distWI,numPics},
numPics=Length[allTest];
qual=Total[1.0/Flatten[Table[res=First[Transpose[Select[allTest[[i]],#[[2]]>10&]]];
Position[res,i],{i,1,numPics}]]];
distWI=ConstantArray[1,{numPics,numPics}];
Do[pw=prunedWisc[k,0.1,allTest];
Do[distWI[[k,pw[[j,1]]]]=1-N[pw[[j,2]]/valWisc[k,allTest]];,{j,1,Length[pw]}],{k,1,numPics}];
Return[distWI]
];

valWisc[i_,allTest_]:=First[Last[Transpose[allTest[[i]]]]]

prunedWisc[i_,per_,allTest_]:=Select[allTest[[i]],#[[2]]>per valWisc[i,allTest]&]

4. Optimized voting algorithm

Function doClassification2[] is used for computing the optimized voting algorithm and all the combinations of optimized voting algorithm with matrix similarities. One can needs to specify the type of algorithm (“EROS”,”PCA”,”COS”,”SimWI”), SVD matrices and path where to find the images, and also select the number of image that should be classified. It also requires the maximum number of iterations (Noted as “ϕ” in text), number of tests performed during the first iteration (noted as “P” in text) and decreasing factor (noted as “α” in text)
Function simWI2[] can be used to calculate the ratio used as distance measure (noted as “(Subscript[r, i])” in text) from the sorted counts obtained by doClassification2[].

doClassification2[distanceType_,uAll_,wAll_,path_,images_,thisClass_,maxIterations_,firstStep_,stepControl_]:=Module[{allImages,thisImage,imgTest,testFeatures,imagesToTest,const,len,iter,final,temp2,a,sortedResult,step,norms,dimensions,el,em,uAllNew,wAllNew,v,weightV, distClasses, closestOnes,result},
allImages=LoadImageNames[path][[images]];
thisImage=LoadImageNames[path][[thisClass]];
imagesToTest=Accumulate[ConstantArray[1,Length[images]]];
len=Length[imagesToTest];
dimensions=Dimensions[uAll];
step=firstStep;
iter=1;
final=ConstantArray[0,{Length[images],3}];
Table[final[[i,1]]=i;,{i,1,Length[images]}];

weightV=weightVector[wAll,dimensions];

While[Length[imagesToTest]>Round[len/10] && iter<maxIterations && step>9,

If[distanceType=="SimWI",
imgTest=Flatten[readFunOne[thisImage,step,{patchSize,patchSize}]];
testFeatures=Table[buildFeatures[imgTest[[k]]],{k,1,step}];
norms=Table[Norm[testFeatures[[i]]-uAll[[j]].(Transpose[uAll[[j]]].testFeatures[[i]])],{i,1,step},{j,imagesToTest}];,

norms=Table[
imgTest=Flatten[readFunOne[thisImage,step,{patchSize,patchSize}]];
testFeatures=Table[buildFeatures[imgTest[[j]]],{j,1, step}];

{uAllNew,wAllNew,v}=SingularValueDecomposition[Transpose[testFeatures],sizeSVD];

If[distanceType=="EROS",
Table[Total[Table[weightV[[i]] Abs[uAll[[k,All,i]].uAllNew[[All,i]]],{i,dimensions[[3]]}]],{k,imagesToTest}],
,]

If[distanceType=="PCA",
Table[em=Transpose[uAll[[i,All]]];el=Transpose[uAllNew];Tr[el.Transpose[em].DiagonalMatrix[weightV.em.Transpose[el]]],{i,1,len}],
,]

If[distanceType=="COS",
weightV.Table[Max[Abs[uAllNew[[All,i]].uAll[[k,All,All]]]],{i,dimensions[[3]]},{k,len}],
,]
,{m,1,step}];
];

distClasses=ConstantArray[1,{step,len}];

Table[a=1;
Table[If[MemberQ[imagesToTest,m]==True,
distClasses[[n]][[m]]=norms[[n]][[a]];a=a+1;,],
{m,1,len}];
,{n,1,step}];

If[distanceType=="SimWI",closestOnes=Table[Ordering[distClasses[[l]]][[1]],{l,1,step}];
,closestOnes=Table[Ordering[distClasses[[l]]][[dimensions[[1]]]],{l,1,step}];];
result=Reverse[Sort[Tally[closestOnes],#1[[2]]<#2[[2]]&]];
sortedResult=Sort[result];

temp2=ConstantArray[0,len];
a=1;
Table[temp2[[i]]=sortedResult[[a,2]]; a=a+1;,{i,sortedResult[[All,1]]}];

final[[All,2]]=final[[All,2]]+temp2;
Table[If[temp2[[i]]==0,,final[[i,3]]=final[[i,3]]+step;],{i,1,len}];

imagesToTest=sortedResult[[All,1]];
iter=iter+1;
step=Round[step stepControl];
];
Table[If[final[[i,2]]==0,final[[i,3]]=firstStep;,],{i,1,len}];
Reverse[Sort[final,#1[[2]]<#2[[2]]&]];
Table[final[[j,1]]=images[[final[[j,1]]]],{j,Dimensions[final][[1]]}];
Return[final]
];

simWI2[allTest2_,numPics_]:=Module[{scaled,sorted,distMat,ratio},
scaled=ConstantArray[0,{numPics,numPics,3}];
sorted=ConstantArray[0,{numPics,numPics,3}];
distMat=Table[sorted[[i]]=Sort[allTest2[[i]]];
ratio=sorted[[i,All,2]]/sorted[[i,All,3]];
scaled[[i]]=ratio*(Max[ratio]^-1),{i,1,numPics}];
Return[N[distMat]]
]

Analyzing parameters of the optimized voting algorithm

Functions for computing the probability of correct match (Subscript[p, j]) tailored to data set consisting of blocks of 10 images from same or very similar paper.

group1=Table[i,{i,1,10}];
group2=Table[i,{i,11,20}];
group3=Table[i,{i,21,30}];
group4=Table[i,{i,31,40}];
group5=Table[i,{i,41,50}];
group6=Table[i,{i,51,60}];
group7=Table[i,{i,61,70}];
group8=Table[i,{i,71,80}];
group9=Table[i,{i,81,90}];
group10=Table[i,{i,91,120}];

findCorrectGroup[temp_,thisClass_]:=Module[{correctGroup},
If[MemberQ[group1,thisClass]==False,
If[MemberQ[group2,thisClass]==False,
If[MemberQ[group3,thisClass]==False,
If[MemberQ[group4,thisClass]==False,
If[MemberQ[group5,thisClass]==False,
If[MemberQ[group6,thisClass]==False,
If[MemberQ[group7,thisClass]==False,
If[MemberQ[group8,thisClass]==False,
If[MemberQ[group9,thisClass]==False,correctGroup=group10
,correctGroup=group9],correctGroup=group8],correctGroup=group7],correctGroup=group6],correctGroup=group5],correctGroup=group4],correctGroup=group3],correctGroup=group2],correctGroup=group1]]

findScore[temp_,thisClass_,testsForOne_]:=Module[{score,newScore,correctGroup},
correctGroup=findCorrectGroup[temp,thisClass];
score={};
newScore=Total[Table[If[MemberQ[correctGroup,temp[[i,1]]]==True,Append[score,temp[[i,2]]],Append[score,0]],{i,Length[temp]}]];
N[newScore/testsForOne]]

Following code was used to analyse the dependance of (Subscript[p, j]) on size of dictionary M. The only input parameters (besides the data set) are describing number of classifications used on each image (testsForOne) and number of images tested. Depending on the input parameters, this calculation will take hours.

SetDirectory[NotebookDirectory[]];
{uAll,wAll}=loadSVDs[];

testsForOne=30;
imagesTested=30;

scores=ConstantArray[0,Length[poolSize]];
index=0;
poolSize={20,30,40,50,60,70,80,90,100,110,120};
allPics=LoadImageNames[path];
numPics=Length[allPics];
dimensions=Dimensions[uAll];
Table[
var=ConstantArray[0,{testsForOne,imagesTested}];
temp=ConstantArray[0,{imagesTested,testsForOne}];
temp2=ConstantArray[0,{imagesTested,testsForOne}];
class=ConstantArray[0,imagesTested];
res=ConstantArray[0,{imagesTested,testsForOne}];
res2=ConstantArray[0,imagesTested];
Table[var[[i]]=RandomInteger[{1,120},l];
uAll2=uAll[[var[[i]]]];
wAll2=wAll[[var[[i]]]];
class[[i]]=RandomChoice[Select[var[[i]],#<=90&]];
Table[
temp[[i,k]]=doClassification["SimWI",uAll2,wAll2,path,var[[i]],class[[i]],2000];
temp2[[i,k]]=1-simWI[ConstantArray[temp[[i,k]],120]][[1]];
res[[i,k]]=Position[temp2[[i,k]],Max[temp2[[i,k]]]];
,{k,1,testsForOne}];
res2[[i]]=Reverse[Sort[Tally[Flatten[res[[i,All,1]],1]],#1[[2]]<#2[[2]]&]];
,{i,1,imagesTested}];
index=index+1;
scores[[index]]=Mean[Flatten[Table[findScore[res2[[i]],class[[i]],testsForOne],{i,1,imagesTested}]]];
,{l,poolSize}];
Grid[Table[If[k==1,{"Size of dictionary M","pj"},{poolSize[[k-1]],scores[[k-1]]}],{k,1,Length[poolSize]+1}],
Alignment->{Center,{Bottom,Top}},Frame->All,Spacings->{2,1}]

5. Actual computation and results

Vizualization of all similarity matrices

We need to import the images and compute corresponding SVD matrices. But first, there are some important input parameters to consider:
numPatches is how many patches to draw randomly from each picture. Noted as “N” in the text of the thesis. Suggested value = 3000, use 500 for faster computation.
patchSize defines the height (and width) of the square patches. Noted as “p” in text Suggested value = 25, use 15 for faster computation.
sizeSVD defines, how many columns from calculated SVD matrix will be take into account. Noted as “(Subscript[n, u])” in text. Suggested value = 30, use 10 for faster computation.
path is the absolute path to folder where images are stored.

sizeSVD=10;
numPatches=500;
patchSize=15;
path="C:\\inkjetPapers\\";

Importing the images and calculating all their SVD matrices denoted as uAll and wAll ((Subscript[U, j]) and Σ) (depending on the input data, it might take a while to compute):

{uAll,wAll}=SVDsofAllImages[path,sizeSVD,numPatches,patchSize];

Since the images are not changing, it certainly is worth it to export the calculated SVD’s once, and then just import the values instead of doing the whole computation again. If the input parameters of the SVD change, it is necessary to recompute it.

Export["allUs.mx",uAll];
Export["allWs.mx",wAll];

Importing back from the files:

{uAll,wAll}=loadSVDs["AllUs.mx","allWs.mx"];

allPics=LoadImageNames[path];
numPics=Length[allPics];

For comparison, here are visualized similarity matrices computed using usual matrix distances:

{dMinkowski,dASM,dYang}=calculateUsualDistances[uAll];
drawUsualDistances[dMinkowski,dASM,dYang]

Visualized similarity matrices for the distance similarities, and the minimum value in each matrix serves for context. Depending on the input SVD parameters, this will take several minutes.

{dEROS,dPCA,dCOS}=calculateDistances[uAll,wAll];
drawDistances[dEROS,dPCA,dCOS]

Calculating and visualizing all the voting algorithms will take quite a while (probably several hours, depending on input parameters). It might be a good idea to export the results in case they are needed later.

dVote=1-simWI[Table[doClassification["SimWI",uAll,wAll,path,Accumulate[ConstantArray[1,120]],i,1000],{i,1,120}]];
dVoteEROS=1-simWI[Table[doClassification["EROS",uAll,wAll,path,Accumulate[ConstantArray[1,120]],i,200],{i,1,120}]];
dVotePCA=1-simWI[Table[doClassification["PCA",uAll,wAll,path,Accumulate[ConstantArray[1,120]],i,200],{i,1,120}]];
dVoteCOS=1-simWI[Table[doClassification["COS",uAll,wAll,path,Accumulate[ConstantArray[1,120]],i,200],{i,1,120}]];

dOptimizedVote=simWI2[Table[doClassification2["SimWI",uAll,wAll,path,Accumulate[ConstantArray[1,120]],i,10,200,0.8],{i,1,numPics}],numPics];
dOptimizedVoteEROS=simWI2[Table[doClassification2["EROS",uAll,wAll,path,Accumulate[ConstantArray[1,120]],i,10,50,0.8],{i,1,numPics}],numPics];
dOptimizedVotePCA=simWI2[Table[doClassification2["PCA",uAll,wAll,path,Accumulate[ConstantArray[1,120]],i,10,50,0.8],{i,1,numPics}],numPics];
dOptimizedVoteCOS=simWI2[Table[doClassification2["COS",uAll,wAll,path,Accumulate[ConstantArray[1,120]],i,10,50,0.8],{i,1,numPics}],numPics];

Labeled[Grid[{Text@Style[#,"TableHeader",Larger]&/@{"Voting algorithm","Voting algorithm + EROS", "Voting algorithm + PCA", "Voting algorithm + COS"},{ArrayPlot[dEROS,ImageSize->300],ArrayPlot[dEROS,ImageSize->300],ArrayPlot[dEROS,ImageSize->300],ArrayPlot[dEROS,ImageSize->300]}},
Alignment->{Center,{Bottom,Top}},Frame->All,Spacings->{0,1}],Text@Style["Visualization of similarity matrices for voting algorithms","Text",Larger],{{Bottom,Center}}]
Labeled[Grid[{Text@Style[#,"TableHeader",Larger]&/@{"Optimized voting algorithm","Optimized voting algorithm + EROS", "Optimized voting algorithm + PCA", "Optimized voting algorithm + COS"},{ArrayPlot[dEROS,ImageSize->300],ArrayPlot[dEROS,ImageSize->300],ArrayPlot[dEROS,ImageSize->300],ArrayPlot[dEROS,ImageSize->300]}},
Alignment->{Center,{Bottom,Top}},Frame->All,Spacings->{0,1}],Text@Style["Visualization of similarity matrices for optimized voting algorithms","Text",Larger],{{Bottom,Center}}]

Objective assesment of all the classification methods

Once again, we assume that all the SVD matrices are computed from a given data set in Section 1. We can now objectively test the properties of all 11 methods as described in text (section Result). There are only 2 input parameters - numbers of pictures we want to test (can be selected manualy or randomly, should be < 90) and number of classifications performed on each picture. Depending on the input parameters, this might take hours or even days. Computers with small RAM might have problems with higher number of tests.

thisClass={8,17,26,34,43,55,67,71,88};
testsForOne=50;


imageNumbers=Accumulate[ConstantArray[1,120]];
picturesTotal=Length[thisClass];
dimensions=Dimensions[uAll];
weightV=weightVector[wAll,dimensions];
d=ConstantArray[0,{11,testsForOne,picturesTotal,numPics}];
t=ConstantArray[0,{11,testsForOne,picturesTotal,numPics}];
Do[
Do[
imgTest=Flatten[readFunOne[allPics[[thisClass[[j]]]],numPatches,{patchSize,patchSize}]];
testFeatures=Table[buildFeatures[imgTest[[k]]],{k,1,numPatches}];
{uAllNew,wAllNew,v}=SingularValueDecomposition[Transpose[testFeatures],sizeSVD];

t[[1,i,j]]=Timing[d[[1,i,j]]=erosDistanceOne[uAll,uAllNew,weightV,dimensions];][[1]];
t[[2,i,j]]=Timing[d[[2,i,j]]=pcaDistanceOne[uAll, uAllNew, weightV, dimensions];][[1]];
t[[3,i,j]]=Timing[d[[3,i,j]]=cosDistanceOne[uAll, uAllNew, weightV, dimensions];][[1]];

t[[4,i,j]]=Timing[d[[4,i,j]]=1-simWI[ConstantArray[doClassification["SimWI",uAll,wAll,path,imageNumbers,thisClass[[j]],3000],numPics]][[1]];][[1]];
t[[5,i,j]]=Timing[d[[5,i,j]]=1-simWI[ConstantArray[doClassification["EROS",uAll,wAll,path,imageNumbers,thisClass[[j]],300],numPics]][[1]];][[1]];
t[[6,i,j]]=Timing[d[[6,i,j]]=1-simWI[ConstantArray[doClassification["PCA",uAll,wAll,path,imageNumbers,thisClass[[j]],300],numPics]][[1]];][[1]];
t[[7,i,j]]=Timing[d[[7,i,j]]=1-simWI[ConstantArray[doClassification["COS",uAll,wAll,path,imageNumbers,thisClass[[j]],300],numPics]][[1]];][[1]];

t[[8,i,j]]=Timing[d[[8,i,j]]=simWI2[ConstantArray[doClassification2["SimWI",uAll,wAll,path,imageNumbers,thisClass[[j]],10,200,0.8],numPics],numPics][[1]];][[1]];
t[[9,i,j]]=Timing[d[[9,i,j]]=simWI2[ConstantArray[doClassification2["EROS",uAll,wAll,path,imageNumbers,thisClass[[j]],10,50,0.8],numPics],numPics][[1]];][[1]];
t[[10,i,j]]=Timing[d[[10,i,j]]=simWI2[ConstantArray[doClassification2["PCA",uAll,wAll,path,imageNumbers,thisClass[[j]],10,50,0.8],numPics],numPics][[1]];][[1]];
t[[11,i,j]]=Timing[d[[11,i,j]]=simWI2[ConstantArray[doClassification2["COS",uAll,wAll,path,imageNumbers,thisClass[[j]],10,50,0.8],numPics],numPics][[1]];][[1]];

,{i,1,testsForOne}];
,{j,1,Length[thisClass]}];

Now the results displayed for each image separately, and then the conclusive table.

rt=ConstantArray[0,{11,picturesTotal}];
at=ConstantArray[0,{11,picturesTotal}];
methodNames={"EROS similarity","PCA similarity","COS similarity", "Voting algorithm","Voting algorithm + EROS", "Voting algorithm + PCA", "Voting algorithm + COS", "Optimized voting algorithm","Optimized voting algorithm + EROS", "Optimized voting algorithm + PCA", "Optimized voting algorithm + COS"};

Table[Grid[Table[If[k==1,{StringForm["Chosen class - ``",thisClass[[j]]],"Best match and number of times best match was classified","% of correct matches", "Average time for 1 classification"},{methodNames[[k-1]],Clear[temp];temp=Reverse[Sort[Tally[Flatten[Table[Position[d[[k-1,i,j]],Max[d[[k-1,i,j]]]][[1]],{i,1,testsForOne}]]],#1[[2]]<#2[[2]]&]]; temp[[1]],
rt[[k-1,j]]=findScore[temp,thisClass[[j]],testsForOne],at[[k-1,j]]=Total[t[[k-1,All,j]]]/testsForOne} ],{k,1,12}],
Alignment->{Center,{Bottom,Top}},Frame->All,Spacings->{2,1}]
,{j,1,Length[thisClass]}]

Grid[Table[If[k==1,{" ","Mean of correct matches [%]","Variance of correct matches","Average time for 1 classification"},{methodNames[[k-1]],Mean[Flatten[rt[[k-1]]]],Sqrt[Variance[Flatten[rt[[k-1]]]]],Total[Flatten[at[[k-1]]]]/picturesTotal}],{k,1,12}],
Alignment->{Center,{Bottom,Top}},Frame->All,Spacings->{2,1}]

6. Artificial Data set creation

Following functions can be used to generate artificial dataset consisting of images of desired size and desired number of such images. Theese two numbers are the only input parameters to all the functions.

Standard Deviation

standardDeviation[imageSize_,numberImages_]:=Module[{i},If[numberImages==1,ImageClip[RandomImage[UniformDistribution[{0.5-1/3,0.5+1/3}],{imageSize,imageSize}],{0,1}],Table[ImageClip[RandomImage[UniformDistribution[{0.5-i/40,0.5+i/40}],{imageSize,imageSize}],{0,1}],{i,1,numberImages}]]];

Vertical Sinusoids

r[f_,imageSize_]:=Table[Sin[2 Pi f t],{t,0,1,1/(imageSize-1)}];
s[f_,imageSize_]:=Table[Sin[2 Pi f t],{t,0,1,1/(imageSize-1)}];

verticalSin[imageSize_,numberImages_]:=Module[{i,t},If[numberImages==1,ImageClip[Image[Outer[Times,r[20,imageSize],s[20,imageSize]]+0.05 RandomReal[{-1,1},{imageSize,imageSize}]],{0,1}],Table[ImageClip[Image[Outer[Times,r[2*i,imageSize],s[i,imageSize]]+0.05 RandomReal[{-1,1},{imageSize,imageSize}]],{0,1}],{i,1,numberImages}]]]

Scale

scale[imageSize_,numberImages_]:=Module[{tempImage,i},If[numberImages==1,
tempImage=RandomImage[UniformDistribution[{0,1}],{imageSize,imageSize}];
ImageClip[ImageCrop[ImageResize[tempImage,imageSize 15],{imageSize,imageSize}],{0,1}],
tempImage=RandomImage[UniformDistribution[{0,1}],{imageSize,imageSize}];
Table[ImageClip[ImageCrop[ImageResize[tempImage,imageSize 1.5 i],{imageSize,imageSize}],{0,1}],{i,1,numberImages}]]]

Spatial Sinusoids

spatialSin[imageSize_,numberImages_]:=Module[{x,y,i},If[numberImages==1,ImageClip[Image[Table[Sin[Sqrt[(x/10)^2+(y/10)^2]] ,{x,-imageSize/2,imageSize/2},{y,-imageSize/2,imageSize/2}]],{0,1}],Reverse[Table[ImageClip[Image[Table[Sin[Sqrt[(x/i)^2+(y/i)^2]] ,{x,-imageSize/2,imageSize/2},{y,-imageSize/2,imageSize/2}]],{0,1}],{i,1,numberImages}]]]]

Rotated Sinusoids

rotatedSin[imageSize_,numberImages_]:=Module[{i,t},If[numberImages==1,ImageClip[ImageCrop[ImageRotate[Image[Outer[Times,r[10,imageSize+100],s[5,imageSize+100]]+0.05 RandomReal[{-1,1},{imageSize+100,imageSize+100}]],Pi/4],imageSize],{0,1}],Table[ImageClip[ImageCrop[ImageRotate[Image[Outer[Times,r[10,imageSize+100],s[5,imageSize+100]]+0.05 RandomReal[{-1,1},{imageSize+100,imageSize+100}]],i Pi/(2*(numberImages-1))],imageSize],{0,1}],{i,0,numberImages-1}]]]

Distance transform of points

pointDistTransform[imageSize_,numberImages_]:=Module[{i,j},If[numberImages==1,ImageClip[ImageResize[ImageAdjust[DistanceTransform[Image[Graphics[Point[Table[{Random[Integer,{1,imageSize-1}],Random[Integer,{1,imageSize-1}]},{i,1,200}]]]]]],{imageSize,imageSize}],{0,1}],Table[ImageClip[ImageResize[ImageAdjust[DistanceTransform[Image[Graphics[Point[Table[{Random[Integer,{1,imageSize-1}],Random[Integer,{1,imageSize-1}]},{i,1,0.4 j 50}]]]]]],{imageSize,imageSize}],{0,1}],{j,1,numberImages}] ]]

Distance transform of lines

lineDistTransform[imageSize_,numberImages_]:=Module[{j},If[numberImages==1,ImageClip[ImageResize[ImageAdjust[DistanceTransform[ColorNegate[Image[Graphics[{Point[{{0,0},{1,1}}],Table[{White,Thickness[0.01],Line[RandomReal[1,{2,2}]]},{20}]},Background->Black]]]]],{imageSize,imageSize}],{0,1}],
Table[ImageClip[ImageResize[ImageAdjust[DistanceTransform[ColorNegate[Image[Graphics[{Point[{{0,0},{1,1}}],Table[{White,Thickness[0.01],Line[RandomReal[1,{2,2}]]},{10+j}]},Background->Black]]]]],{imageSize,imageSize}],{0,1}],{j,1,numberImages}]]]

Bandpass filter of noise

bandpassFilter[imageSize_,numberImages_]:=Module[{j},If[numberImages==1,ImageClip[ImageResize[ImageAdjust[BandpassFilter[RandomImage[UniformDistribution[{0.5-1/40,0.5+1/40}],{200,200}],{0.9/(numberImages 10),1/(numberImages 10) }]],{imageSize,imageSize}],{0,1}],Table[ImageClip[ImageResize[ImageAdjust[BandpassFilter[RandomImage[UniformDistribution[{0.5-1/40,0.5+1/40}],{200,200}],{0.9/numberImages*j,1/numberImages*j}]],{imageSize,imageSize}],{0,1}],{j,1,numberImages}]]]

Distance with different slope steepness

differentSlope[imageSize_,numberImages_]:=Module[{list,interp,step,tempValue,i,j,k,x,y},If[numberImages==1,tempValue=Round[10 Log[20]];
list=Flatten[Table[{{i,j},RandomReal[{0,1}]},{i,1,tempValue},{j,1,tempValue}],1];
interp=Interpolation[list,InterpolationOrder->{2,2}];
step=1/(imageSize/((tempValue)-1));
ImageClip[Image[Table[interp[x,y],{x,1+step,tempValue,step},{y,1+step,tempValue,step}]],{0,1}],
Table[tempValue=Round[10 Log[k 2.]];
list=Flatten[Table[{{i,j},RandomReal[{0,1}]},{i,1,tempValue},{j,1,tempValue}],1];
interp=Interpolation[list,InterpolationOrder->{2,2}];
step=1/(imageSize/((tempValue)-1));
ImageClip[Image[Table[interp[x,y],{x,1+step,tempValue,step},{y,1+step,tempValue,step}]],{0,1}],{k,1,20}]]]

Standard deviation of the patch (Expanding the histogram)

HalfSTD[imageSize_,numberImages_]:=Module[{figures,patch,i},
If[numberImages==1,figures=standardDeviation[imageSize,numberImages];
patch=ColorConvert[readFunOne[LoadImageNames[path][[92]],1,{imageSize,imageSize}][[1]],"Grayscale"];
Return[HistogramTransform[patch,figures]],
figures=standardDeviation[imageSize,numberImages];
patch=ColorConvert[readFunOne[LoadImageNames[path][[92]],1,{imageSize,imageSize}][[1]],"Grayscale"];
Table[HistogramTransform[patch,figures[[i]]],{i,1,numberImages}]]]

Scale of the patch

HalfScale[imageSize_,numberImages_]:=Module[{i},If[numberImages==1,ImageCrop[ImageResize[ColorConvert[readFunOne[LoadImageNames[path][[92]],1,{imageSize,imageSize}][[1]],"Grayscale"],imageSize 3],{imageSize,imageSize}],
Table[ImageCrop[ImageResize[ColorConvert[readFunOne[LoadImageNames[path][[92]],1,{imageSize,imageSize}][[1]],"Grayscale"],imageSize 1.5 i],{imageSize,imageSize}],{i,1,numberImages}]]]

Rotation of the patch

HalfRotation[imageSize_,numberImages_]:=Module[{},
If[numberImages==1,ImageCrop[ImageRotate[ColorConvert[readFunOne[LoadImageNames[path][[92]],1,{imageSize+100,imageSize+100}][[1]],"Grayscale"],Pi],imageSize],
Table[ImageCrop[ImageRotate[ColorConvert[readFunOne[LoadImageNames[path][[92]],1,{imageSize+100,imageSize+100}][[1]],"Grayscale"],i*Pi/(2*(numberImages-1))],imageSize],{i,0,numberImages-1}]]]

BandPass of the patch

HalfBandPass[imageSize_,numberImages_]:=Module[{j},If[numberImages==1,ImageAdjust[BandpassFilter[ColorConvert[readFunOne[LoadImageNames[path][[92]],1,{imageSize,imageSize}][[1]],"Grayscale"],{0.9/(numberImages 10) ,1/(numberImages 10) }]],
Table[ImageAdjust[BandpassFilter[ColorConvert[readFunOne[LoadImageNames[path][[92]],1,{imageSize,imageSize}][[1]],"Grayscale"],{0.9/numberImages j,1/numberImages j}]],{j,1,numberImages}]]]

7. Displaying the artificial data sets

First, we need to select the number of images we want the data set to consist of, and their size. Then we can just sellect any set we want.

numberImages=20;
imageSize=200;

Manipulate[Which[type=="Standard deviation",images=standardDeviation[imageSize,numberImages],type=="Vertical sinusoids",images=verticalSin[imageSize,numberImages],type=="Scale difference",images=scale[imageSize,numberImages],
type=="Spatial sinusoids",images=spatialSin[imageSize,numberImages],
type=="Rotated sinusoids",images=rotatedSin[imageSize,numberImages],type=="Dist Transf of points",images=pointDistTransform[imageSize,numberImages],type=="Dist Transf of lines",images=lineDistTransform[imageSize,numberImages],type=="Bandpass of noise",images=bandpassFilter[imageSize,numberImages],
type=="Dist Transf with random steepness", images=differentSlope[imageSize,numberImages],
type=="Standard deviation of patch",images=HalfSTD[imageSize,numberImages],type=="Rotation of patch",images=HalfRotation[imageSize,numberImages],
type=="Scale difference of patch",images=HalfScale[imageSize,numberImages],
type=="Bandpass of noise on patch",images=HalfBandPass[imageSize,numberImages]];
GraphicsGrid[Partition[images,5],ImageSize->700],{type,{"Standard deviation","Vertical sinusoids","Scale difference","Spatial sinusoids","Rotated sinusoids","Dist Transf of points","Dist Transf of lines","Bandpass of noise","Dist Transf with random steepness","Standard deviation of patch","Rotation of patch","Scale difference of patch","Bandpass of noise on patch"}},Initialization:>(images=standardDeviation[imageSize,numberImages];)]

8. Using artificial data set to learn about sensitivity to choosen conditions

Function definitions

distances[] calculates all similarity matrices using provided pictures.
diagonalMean[] calculates means across all the diagonal of a matrix.
createSet[] creates a set of 13 images of specified size using the artificial data sets.

The rest of the functions create data sets based on one specific condition we try to simulate. Those conditions are rotation change, scale change, brightness change, overexposure sensitivity, blur sensitivity and sensitivity on data distribution, i.e. histogram.
Input parameters of those functions are allways the same - a base image and a number of images we want to generate.

distances[images_,sizeSVD_,numPatches_,patchSize_]:=Module[{uAll,wAll,dist,len,allFeatures,allPatches,u},
dist=ConstantArray[0,11];
len=Length[images];
Table[Export[If[i<10,"im0" ~~ToString[i]~~".tif","im" ~~ToString[i]~~".tif"],images[[i]]],{i,1,len}];
allPatches=Table[Flatten[readFun[images[[i]],numPatches,{patchSize,patchSize}]],{i,1,len}];allFeatures=Table[buildFeatures[allPatches[[i,j]]],{i,1,len},{j,1,numPatches}];
uAll=ConstantArray[{},len];
wAll=ConstantArray[{},len];
u=ConstantArray[{},len];
Table[{uAll[[i]],wAll[[i]],u[[i]]}=SingularValueDecomposition[Transpose[allFeatures[[i]]],sizeSVD],{i,1,len}];
dist[[1]]=erosDistance[uAll,wAll,Dimensions[uAll]];
dist[[2]]=pcaDistance[uAll,wAll,Dimensions[uAll]];
dist[[3]]=cosDistance[uAll,wAll,Dimensions[uAll]];
dist[[4]]=Table[1-simWI[ConstantArray[doClassification["SimWI",uAll,wAll,NotebookDirectory[],Accumulate[ConstantArray[1,len]],i,2000],len]][[1]],{i,1,len}];
dist[[5]]=Table[1-simWI[ConstantArray[doClassification["EROS",uAll,wAll,NotebookDirectory[],Accumulate[ConstantArray[1,len]],i,200],len]][[1]],{i,1,len}];
dist[[6]]=Table[1-simWI[ConstantArray[doClassification["PCA",uAll,wAll,NotebookDirectory[],Accumulate[ConstantArray[1,len]],i,200],len]][[1]],{i,1,len}];
dist[[7]]=Table[1-simWI[ConstantArray[doClassification["COS",uAll,wAll,NotebookDirectory[],Accumulate[ConstantArray[1,len]],i,200],len]][[1]],{i,1,len}];
dist[[8]]=Table[simWI2[ConstantArray[doClassification2["SimWI",uAll,wAll,NotebookDirectory[],Accumulate[ConstantArray[1,len]],i,10,200,0.8],len],len][[1]],{i,1,len}];
dist[[9]]=Table[simWI2[ConstantArray[doClassification2["EROS",uAll,wAll,NotebookDirectory[],Accumulate[ConstantArray[1,len]],i,10,50,0.8],len],len][[1]],{i,1,len}];
dist[[10]]=Table[simWI2[ConstantArray[doClassification2["PCA",uAll,wAll,NotebookDirectory[],Accumulate[ConstantArray[1,len]],i,10,50,0.8],len],len][[1]],{i,1,len}];
dist[[11]]=Table[simWI2[ConstantArray[doClassification2["COS",uAll,wAll,NotebookDirectory[],Accumulate[ConstantArray[1,len]],i,10,50,0.8],len],len][[1]],{i,1,len}];
DeleteFile[Table[If[i<10,"im0" ~~ToString[i]~~".tif","im" ~~ToString[i]~~".tif"],{i,1,len}]];
Return[dist]]

diagonalMean[dist_]:=Module[{len},len=Length[dist];
Table[N[Mean[Diagonal[dist,i]]],{i,-len+1,len-1}]]

createSet[imageSize_]:=Module[{i,names},
names={"rotatedSin","verticalSin","spatialSin","scale","pointDistTransform","lineDistTransform","bandpassFilter","differentSlope","standardDeviation","HalfSTD","HalfScale","HalfBandPass","HalfRotation"};
Table[ToExpression[names[[i]]][imageSize,1],{i,1,Length[names]}]]

rotateInputImage[inputImage_,numberImages_]:=Module[{i,dimensions},
dimensions=ImageDimensions[inputImage];Table[ImageCrop[ImageRotate[inputImage,i Pi/(2*(numberImages-1))],dimensions[[1]]-100],{i,0,numberImages-1}]]

scaleInputImage[inputImage_,numberImages_]:=Module[{dimensions,i},
dimensions=ImageDimensions[inputImage];Table[ImageCrop[ImageResize[inputImage,dimensions[[1]] i],dimensions],{i,1,numberImages}]]

brightnessInputImage[inputImage_,numberImages_]:=Module[{dimensions,i},
dimensions=ImageDimensions[inputImage];Table[ImageAdjust[inputImage,{0,-0.95+(1.9/numberImages (i-1))}],{i,1,numberImages}]]

overexposureInputImage[inputImage_,numberImages_]:=Module[{dimensions,i},
dimensions=ImageDimensions[inputImage];Table[ImageClip[Image[ImageData[inputImage]-0.5+(1/numberImages(i-1))]],{i,1,numberImages}]]

histogramInputImage[inputImage_,numberImages_]:=Module[{pdf,const,i,function,lambda,cdffunc,histeq},
pdf=BinCounts[Flatten[ImageData[inputImage]],{0,1,0.00025}];
const=ConstantArray[Mean[pdf],Length[pdf]];
Table[
lambda= (i-1)/(numberImages-1);
function=lambda pdf+(1-lambda) const;
cdffunc=ListInterpolation[Rescale[Accumulate[function]],{0,1}];
         histeq=Map[cdffunc,ImageData[inputImage]];
Image[histeq],{i,1,numberImages}]
]

blurInputImage[inputImage_,numberImages_]:=Module[{dimensions,i},
dimensions=ImageDimensions[inputImage];Table[GaussianFilter[inputImage,0.5 i],{i,1,numberImages}]]

Plotting the sensitivity of classification methods to selected conditions

Below is a method of displaying the sensitivity of oum methods to selected conditions defined above. The whole procedure is described in the thesis in subsection 4.3 The only input parameter to this method is number of pictures each set will be consisting of. Based on this number, the calculation might take hours or even days.

numberSteps=10;


functionNames={"rotateInputImage","scaleInputImage","brightnessInputImage","overexposureInputImage","blurInputImage","histogramInputImage"};
types={"EROS similarity","PCA similarity","Cosine similarity","Voting algorithm","Voting algorithm + EROS similarity", "Voting algorithm + PCA similarity","Voting algorithm + Cosine similarity", "Optimised voting algorithm", "Optimised voting algorithm + EROS similarity","Optimised voting algorithm + PCA similarity","Optimised voting algorithm + Cosine similarity"};
names=13;
means=ConstantArray[0,{Length[functionNames],13}];
set=createSet[200];
set2=createSet[300];
m=ConstantArray[0,{Length[functionNames],numberSteps,13}];
d=ConstantArray[0,{Length[functionNames],13}];
Table[
m[[1,All,i]]=rotateInputImage[set2[[i]],numberSteps];
m[[2,All,i]]=scaleInputImage[set[[i]],numberSteps];
m[[3,All,i]]=brightnessInputImage[set[[i]],numberSteps];
m[[4,All,i]]=overexposureInputImage[set[[i]],numberSteps];
m[[5,All,i]]=blurInputImage[set[[i]],numberSteps];
m[[6,All,i]]=histogramInputImage[set[[i]],numberSteps];
,{i,1,13}];
Table[d[[i,j]]=distances[m[[i,All,j]],sizeSVD,numPatches,patchSize];,{i,1,6},{j,1,13}];
Table[Labeled[ListLinePlot[Table[Mean[Table[diagonalMean[d[[j,i,k]]],{i,1,13}]],{j,1,6}],PlotRange->{{0,2numberSteps},{0,1}},ImageSize->400,PlotLegends->{"Rotation","Scale","Brightness","Over-exposure","Blur","Histogram equalization"},PlotLabel->types[[k]]],{"Number of diagonal [-]","Average distance [-]"},{Bottom,Left},RotateLabel->True],{k,1,11}]