├── getFilterParameters.m ├── chi2dist.m ├── filter_response2histogram.m ├── get_texton_map.m ├── get_image.m ├── makeSfilters.m ├── im2filter_response.m ├── LICENSE ├── classify_images.m ├── makeRFSfilters.m ├── makeLMfilters.m ├── README.md ├── knn_calc_dist.m ├── demo_curet.m └── fuf.m /getFilterParameters.m: -------------------------------------------------------------------------------- 1 | function [scale, elongate] = getFilterParameters(mode) 2 | 3 | tmp = regexp(mode,'_','split'); 4 | match = cellfun(@(x) strcmp(x, 'malik'), tmp); 5 | matchIdx = find(match); 6 | 7 | scaleStr = tmp{matchIdx+1}; 8 | scaleStr = strrep(scaleStr, 'x', '.'); 9 | scale = str2double(scaleStr); 10 | 11 | elongateStr = tmp{matchIdx+2}; 12 | elongateStr = strrep(elongateStr, 'x', '.'); 13 | elongate = str2double(elongateStr); 14 | -------------------------------------------------------------------------------- /chi2dist.m: -------------------------------------------------------------------------------- 1 | function d = chi2dist(h1, h2) 2 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 3 | % Compute the chi^2 distance between two histograms 4 | % 5 | % Input: 6 | % h1, h2, input histograms 7 | % Output: 8 | % d, distance between histograms 9 | % 10 | % ---------------- 11 | % Aleksandrs Ecins 12 | %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 13 | 14 | % Normalize the histograms 15 | h1 = h1 ./ (sum(h1) + eps); 16 | h2 = h2 ./ (sum(h2) + eps); 17 | 18 | % Compute distance 19 | d = 1/2 * ((h1-h2).^2)' * (1./(h1+h2+eps)); 20 | -------------------------------------------------------------------------------- /filter_response2histogram.m: -------------------------------------------------------------------------------- 1 | function [ histogram ] = filter_response2histogram( filter_response,training_class_centroid,NUM_BINS) 2 | image_size = size(filter_response,1); 3 | 4 | texton_map = zeros(image_size ,1); 5 | 6 | hist_start = 1; 7 | bins_ranges = hist_start:NUM_BINS ; 8 | 9 | for k=1:image_size 10 | pixel = filter_response(k,:); 11 | [~, assign] = min(vl_alldist(pixel', training_class_centroid')); 12 | texton_map(k) = assign; 13 | end 14 | %figure;imagesc(reshape(texton_map,patch_height,patch_width)); 15 | histogram = histc(texton_map,bins_ranges); 16 | %% Normalize 17 | histogram = histogram ./ sum(histogram); 18 | %max_v = max(histogram) 19 | %sum_v = sum(histogram) 20 | %histogram = histogram ./ max(histogram); 21 | %figure;bar(histogram); 22 | end 23 | 24 | -------------------------------------------------------------------------------- /get_texton_map.m: -------------------------------------------------------------------------------- 1 | function texelMap = get_texton_map(im) 2 | global textonData; 3 | texMode = '1_1_0_0_1_tex_texton128_malik_0x5_3_universal_intensity_8.mat'; 4 | 5 | [scale, elongate] = getFilterParameters(texMode); 6 | 7 | % Filterbank parameters 8 | fbParams.no = 12; 9 | fbParams.ns = 1; 10 | fbParams.sc = sqrt(2); 11 | 12 | 13 | fb = fbCreate(fbParams.no, scale, fbParams.ns, fbParams.sc, elongate); 14 | 15 | % Filter image 16 | fim = fbRun(fb, im); 17 | 18 | %% Universal 19 | if ~isempty(strfind(texMode, 'universal')) 20 | 21 | % Assign universal textons 22 | % Load universal texton dictionary 23 | textons = textonData.tex; 24 | nTexels = size(textons, 2); 25 | texelMap = assignTextons(fim, textons); % Assign textons 26 | end 27 | texelMap = texelMap (1:200,1:200); 28 | end -------------------------------------------------------------------------------- /get_image.m: -------------------------------------------------------------------------------- 1 | function [ im ] = get_image( image_path ,patch_width,patch_height,options) 2 | %% get_image , will load the image from image_path 3 | % - patch_width,patch_height can be used to crop certain part of an 4 | % image. 5 | % If you want to load the whole image, set these values to -1 6 | % 7 | % - options can be used to pass extra parameters, like applying a 8 | % particular transformation to the image after being loaded 9 | 10 | im = imread(image_path); 11 | 12 | if(size(im,3)>1) 13 | im =double(rgb2gray(im)); 14 | else 15 | im =double(im); 16 | end 17 | 18 | 19 | if(patch_width ~= -1) 20 | row_index = round((size(im,1)-patch_width)/2); 21 | col_index = round((size(im,2)-patch_height)/2); 22 | im = im(row_index:row_index+patch_width-1,col_index:col_index+patch_height-1); 23 | end 24 | 25 | im_mean = mean(im(:)); 26 | im_std = std(im(:)); 27 | im = im - im_mean; 28 | im = im / im_std; 29 | 30 | end 31 | 32 | -------------------------------------------------------------------------------- /makeSfilters.m: -------------------------------------------------------------------------------- 1 | function F=makeSfilters 2 | % Returns the S filter bank of size 49x49x13 in F. To convolve an 3 | % image I with the filter bank you can either use the matlab function 4 | % conv2, i.e. responses(:,:,i)=conv2(I,F(:,:,i),'valid'), or use the 5 | % Fourier transform. 6 | 7 | NF=13; % Number of filters 8 | SUP=49; % Support of largest filter (must be odd) 9 | F=zeros(SUP,SUP,NF); 10 | 11 | F(:,:,1)=makefilter(SUP,2,1); 12 | F(:,:,2)=makefilter(SUP,4,1); 13 | F(:,:,3)=makefilter(SUP,4,2); 14 | F(:,:,4)=makefilter(SUP,6,1); 15 | F(:,:,5)=makefilter(SUP,6,2); 16 | F(:,:,6)=makefilter(SUP,6,3); 17 | F(:,:,7)=makefilter(SUP,8,1); 18 | F(:,:,8)=makefilter(SUP,8,2); 19 | F(:,:,9)=makefilter(SUP,8,3); 20 | F(:,:,10)=makefilter(SUP,10,1); 21 | F(:,:,11)=makefilter(SUP,10,2); 22 | F(:,:,12)=makefilter(SUP,10,3); 23 | F(:,:,13)=makefilter(SUP,10,4); 24 | return 25 | 26 | function f=makefilter(sup,sigma,tau) 27 | hsup=(sup-1)/2; 28 | [x,y]=meshgrid([-hsup:hsup]); 29 | r=(x.*x+y.*y).^0.5; 30 | f=cos(r*(pi*tau/sigma)).*exp(-(r.*r)/(2*sigma*sigma)); 31 | f=f-mean(f(:)); % Pre-processing: zero mean 32 | f=f/sum(abs(f(:))); % Pre-processing: L_{1} normalise 33 | return 34 | -------------------------------------------------------------------------------- /im2filter_response.m: -------------------------------------------------------------------------------- 1 | function [ filter_response ] = im2filter_response( image_name,patch_width,patch_height,filter,options) 2 | 3 | %image_name 4 | training_im = get_image(image_name,patch_width,patch_height,options); 5 | 6 | filter_response = zeros(size(training_im,1)*size(training_im,2),size(filter,3)); 7 | for k=1:size(filter,3) 8 | tmp = conv2(double(training_im ),filter(:,:,k),'same'); 9 | filter_response(:,k)=tmp(:); 10 | end; 11 | if strfind(options, 'MR8') 12 | filter_response_MR8 = zeros(size(training_im,1)*size(training_im,2),8); 13 | 14 | % pick the *absolute* maximum response 15 | filter_response_MR8(:,1) = max(abs(filter_response(:,1:6)),[],2); 16 | filter_response_MR8(:,2) = max(abs(filter_response(:,7:12)),[],2); 17 | filter_response_MR8(:,3) = max(abs(filter_response(:,13:18)),[],2); 18 | filter_response_MR8(:,4) = max(abs(filter_response(:,19:24)),[],2); 19 | filter_response_MR8(:,5) = max(abs(filter_response(:,25:30)),[],2); 20 | filter_response_MR8(:,6) = max(abs(filter_response(:,31:36)),[],2); 21 | 22 | filter_response_MR8(:,7:8) = filter_response(:,37:38); 23 | filter_response = filter_response_MR8; 24 | end 25 | L = sum(filter_response' .^2)'; 26 | L = sqrt(L); 27 | sc = log(1 + L / 0.03); 28 | numerator = bsxfun(@times,filter_response,sc); 29 | filter_response = bsxfun(@rdivide,numerator,L); 30 | 31 | 32 | end 33 | 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2018, Ahmed Taha 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /classify_images.m: -------------------------------------------------------------------------------- 1 | function [test_histogram,test_classes, accuracy ] = classify_images( params ) 2 | %% classify_images will classify a particular set of images to a pre-defined classes using training models 3 | % 4 | 5 | patch_width = params.patch_width; 6 | patch_height = params.patch_height; 7 | filter_bank = params.filter_bank; 8 | training_class_centroid = params.training_class_centroid ; 9 | NUM_BINS = params.NUM_BINS; 10 | classification_options = params.classification_options; 11 | no_classes = params.no_classes; 12 | training_histogram = params.training_histogram; 13 | training_classes = params.training_classes; 14 | test_images = params.test_images; 15 | test_per_class = params.test_per_class; 16 | KNN = params.KNN; 17 | 18 | test_histogram = zeros(test_per_class,NUM_BINS); 19 | test_classes = zeros(test_per_class,1); 20 | 21 | test_index = 1; 22 | dist_type = 'chi'; 23 | pret_type = 'none'; 24 | 25 | accuracy = zeros(no_classes ,no_classes ); 26 | for i=1:no_classes 27 | fprintf('Start: Classification for class %d\n',i); 28 | for j=1:test_per_class 29 | image_name = test_images{j,i}; 30 | filter_response = im2filter_response( image_name,patch_width,patch_height,filter_bank,classification_options); 31 | histogram= filter_response2histogram( filter_response,training_class_centroid,NUM_BINS); 32 | 33 | test_histogram(test_index,:) = histogram; 34 | test_classes(test_index,:) = i; 35 | test_index = test_index + 1; 36 | 37 | pred = knnpred(histogram',training_histogram,training_classes,KNN,dist_type,pret_type); 38 | 39 | 40 | accuracy(i,pred.class_pred) = accuracy(i,pred.class_pred) + 1; 41 | end 42 | fprintf('End: Classification for class %d\n',i); 43 | end 44 | 45 | 46 | end 47 | 48 | -------------------------------------------------------------------------------- /makeRFSfilters.m: -------------------------------------------------------------------------------- 1 | function F=makeRFSfilters 2 | % Returns the RFS filter bank of size 49x49x38 in F. The MR8, MR4 and 3 | % MRS4 sets are all derived from this filter bank. To convolve an 4 | % image I with the filter bank you can either use the matlab function 5 | % conv2, i.e. responses(:,:,i)=conv2(I,F(:,:,i),'valid'), or use the 6 | % Fourier transform. 7 | 8 | SUP=49; % Support of the largest filter (must be odd) 9 | SCALEX=[1,2,4]; % Sigma_{x} for the oriented filters 10 | NORIENT=6; % Number of orientations 11 | 12 | NROTINV=2; 13 | NBAR=length(SCALEX)*NORIENT; 14 | NEDGE=length(SCALEX)*NORIENT; 15 | NF=NBAR+NEDGE+NROTINV; 16 | F=zeros(SUP,SUP,NF); 17 | hsup=(SUP-1)/2; 18 | [x,y]=meshgrid([-hsup:hsup],[hsup:-1:-hsup]); 19 | orgpts=[x(:) y(:)]'; 20 | 21 | count=1; 22 | for scale=1:length(SCALEX), 23 | for orient=0:NORIENT-1, 24 | angle=pi*orient/NORIENT; % Not 2pi as filters have symmetry 25 | c=cos(angle);s=sin(angle); 26 | rotpts=[c -s;s c]*orgpts; 27 | F(:,:,count)=makefilter(SCALEX(scale),0,1,rotpts,SUP); 28 | F(:,:,count+NEDGE)=makefilter(SCALEX(scale),0,2,rotpts,SUP); 29 | count=count+1; 30 | end; 31 | end; 32 | F(:,:,NBAR+NEDGE+1)=normalise(fspecial('gaussian',SUP,10)); 33 | F(:,:,NBAR+NEDGE+2)=normalise(fspecial('log',SUP,10)); 34 | return 35 | 36 | function f=makefilter(scale,phasex,phasey,pts,sup) 37 | gx=gauss1d(3*scale,0,pts(1,:),phasex); 38 | gy=gauss1d(scale,0,pts(2,:),phasey); 39 | f=normalise(reshape(gx.*gy,sup,sup)); 40 | return 41 | 42 | function g=gauss1d(sigma,mean,x,ord) 43 | % Function to compute gaussian derivatives of order 0 <= ord < 3 44 | % evaluated at x. 45 | 46 | x=x-mean;num=x.*x; 47 | variance=sigma^2; 48 | denom=2*variance; 49 | g=exp(-num/denom)/sqrt(pi*denom); 50 | switch ord, 51 | case 1, g=-g.*(x/variance); 52 | case 2, g=g.*((num-variance)/(variance^2)); 53 | end; 54 | return 55 | 56 | function f=normalise(f), f=f-mean(f(:)); f=f/sum(abs(f(:))); return -------------------------------------------------------------------------------- /makeLMfilters.m: -------------------------------------------------------------------------------- 1 | function F=makeLMfilters 2 | % Returns the LML filter bank of size 49x49x48 in F. To convolve an 3 | % image I with the filter bank you can either use the matlab function 4 | % conv2, i.e. responses(:,:,i)=conv2(I,F(:,:,i),'valid'), or use the 5 | % Fourier transform. 6 | 7 | SUP=49; % Support of the largest filter (must be odd) 8 | SCALEX=sqrt(2).^[1:3]; % Sigma_{x} for the oriented filters 9 | NORIENT=6; % Number of orientations 10 | 11 | NROTINV=12; 12 | NBAR=length(SCALEX)*NORIENT; 13 | NEDGE=length(SCALEX)*NORIENT; 14 | NF=NBAR+NEDGE+NROTINV; 15 | F=zeros(SUP,SUP,NF); 16 | hsup=(SUP-1)/2; 17 | [x,y]=meshgrid([-hsup:hsup],[hsup:-1:-hsup]); 18 | orgpts=[x(:) y(:)]'; 19 | 20 | count=1; 21 | for scale=1:length(SCALEX), 22 | for orient=0:NORIENT-1, 23 | angle=pi*orient/NORIENT; % Not 2pi as filters have symmetry 24 | c=cos(angle);s=sin(angle); 25 | rotpts=[c -s;s c]*orgpts; 26 | F(:,:,count)=makefilter(SCALEX(scale),0,1,rotpts,SUP); 27 | F(:,:,count+NEDGE)=makefilter(SCALEX(scale),0,2,rotpts,SUP); 28 | count=count+1; 29 | end; 30 | end; 31 | 32 | count=NBAR+NEDGE+1; 33 | SCALES=sqrt(2).^[1:4]; 34 | for i=1:length(SCALES), 35 | F(:,:,count)=normalise(fspecial('gaussian',SUP,SCALES(i))); 36 | F(:,:,count+1)=normalise(fspecial('log',SUP,SCALES(i))); 37 | F(:,:,count+2)=normalise(fspecial('log',SUP,3*SCALES(i))); 38 | count=count+3; 39 | end; 40 | return 41 | 42 | function f=makefilter(scale,phasex,phasey,pts,sup) 43 | gx=gauss1d(3*scale,0,pts(1,:),phasex); 44 | gy=gauss1d(scale,0,pts(2,:),phasey); 45 | f=normalise(reshape(gx.*gy,sup,sup)); 46 | return 47 | 48 | function g=gauss1d(sigma,mean,x,ord) 49 | % Function to compute gaussian derivatives of order 0 <= ord < 3 50 | % evaluated at x. 51 | 52 | x=x-mean;num=x.*x; 53 | variance=sigma^2; 54 | denom=2*variance; 55 | g=exp(-num/denom)/(pi*denom)^0.5; 56 | switch ord, 57 | case 1, g=-g.*(x/variance); 58 | case 2, g=g.*((num-variance)/(variance^2)); 59 | end; 60 | return 61 | 62 | function f=normalise(f), f=f-mean(f(:)); f=f/sum(abs(f(:))); return -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Statistical Approach to Texture Classification from Single Images 3 | ----------------------------------------------------------------- 4 | 5 | This repos provides an implementation for the "[Statistical Approach to Texture Classification from Single Images](http://www.robots.ox.ac.uk/~vgg/publications/2005/Varma05/)" paper by Varma et. al. 6 | 7 | The filters (RFS, LM, S) used in this repos are from [this link](http://www.robots.ox.ac.uk/~vgg/research/texclass/filters.html) 8 | 9 | It is not documented yet. Since I know that it will take me some time to write the documentation, I decided to provide this initial version of the code. There is a lot of work that can help make this code better. So any contributions will be welcomed. 10 | 11 | Libraries 12 | --------- 13 | To be able to run this code, you need to download the following libraries 14 | - [VLFeat open source library](http://www.vlfeat.org/) 15 | - [Classification toolbox for MATLAB, by Milano Chemometrics and QSAR Research Group](http://michem.disat.unimib.it/chm/download/softwares/help_classification/web.htm). 16 | 17 | VLFeat Library is used to calculate K-means (vl_kmeans) and the distance between new nodes and pre-computed centroids (vl_alldist). 18 | Classification toolbox is used to find the nearest neighbor during the classification phase. 19 | 20 | Setup 21 | ----- 22 | 23 | 1. Download the code. 24 | 2. Download the [Classification toolbox for 25 | 3. MATLAB, by Milano Chemometrics and QSAR Research Group](http://michem.disat.unimib.it/chm/download/softwares/help_classification/web.htm). 26 | 3. Update the knn_calc_dist.m file with the file inside this repos, to support chi-square distance 27 | 4. Update the "rootpath" variable in demo_curet.m to point to Columbia-Utrecht dataset folder on your machine. 28 | 5. Run demo_curet.m to test the performance over Columbia-Utrecht dataset. 29 | 30 | I will try to update the documentation incrementally to provide more instructions to make using this code easier. 31 | 32 | Contributor list 33 | ---------------- 34 | 1. [Ahmed Taha](http://ahmed-taha.com/) 35 | 2. [Aleksandrs Ecins](http://www.umiacs.umd.edu/~aecins/) 36 | 37 | ## License 38 | TextureClassification_FilterBank is released under the BSD 2-Clause license. The code is released for unrestricted use. 39 | -------------------------------------------------------------------------------- /knn_calc_dist.m: -------------------------------------------------------------------------------- 1 | function D = knn_calc_dist(X,Xnew,dist_type) 2 | 3 | % calculation of distances between samples of X and Xnew 4 | % dist_type: 'euclidean' Euclidean distance 5 | % 'mahalanobis' Mahalanobis distance 6 | % 'cityblock' City Block metric 7 | % 'minkowski' Minkowski metric 8 | % 'sm' sokal-michener for binary data 9 | % 'rt' rogers-tanimoto for binary data 10 | % 'jt' jaccard-tanimoto for binary data 11 | % 'gle' gleason-dice sorenson for binary data 12 | % 'ct4' consonni todeschini for binary data 13 | % 'ac' austin colwell for binary data 14 | % 15 | % The main routine is class_gui 16 | % 17 | % Note that a detailed HTML help is provided with the toolbox. 18 | % See the HTML HELP files (help.htm) for futher details and examples 19 | % 20 | % Classification toolbox for MATLAB 21 | % version 4.0 - October 2015 22 | % Davide Ballabioabout 23 | % Milano Chemometrics and QSAR Research Group 24 | % http://michem.disat.unimib.it/chm/ 25 | 26 | % fast euclidean distance 27 | % D_squares_x = (sum(Xnew'.^2))'*ones(1,size(X,1)); 28 | % D_squares_w = ones(1,size(Xnew,1))'*sum(X'.^2); 29 | % D_product = - 2*(Xnew*X'); 30 | % D = (D_squares_x2 + D_squares_w2 + D_product2).^0.5; 31 | 32 | if strcmp(dist_type,'mahalanobis') 33 | inv_covX = pinv(cov(X)); 34 | end 35 | for i=1:size(Xnew,1) 36 | if strcmp(dist_type,'euclidean') 37 | x_in = Xnew(i,:); 38 | D_squares_x = (sum(x_in'.^2))'*ones(1,size(X,1)); 39 | D_squares_w = sum(X'.^2); 40 | D_product = - 2*(x_in*X'); 41 | D(i,:) = (D_squares_x + D_squares_w + D_product).^0.5; 42 | elseif strcmp(dist_type,'chi') 43 | for j=1:size(X,1) 44 | D(i,j) = chi2dist(Xnew',X(j,:)'); 45 | end 46 | %D2 = chi_square_statistics_fast(Xnew',X(:,:)'); 47 | else 48 | for j=1:size(X,1) 49 | x = Xnew(i,:); 50 | y = X(j,:); 51 | if strcmp(dist_type,'mahalanobis') 52 | D(i,j) = ((x - y)*inv_covX*(x - y)')^0.5; 53 | elseif strcmp(dist_type,'cityblock') 54 | D(i,j) = sum(abs(x - y)); 55 | elseif strcmp(dist_type,'minkowski') 56 | p = 2; 57 | D(i,j) = (sum((abs(x - y)).^p))^(1/p); 58 | else 59 | [a,bc,d,p] = calcbinary(x,y); 60 | if strcmp(dist_type,'sm') 61 | D(i,j)=1-((a+d)/p); 62 | elseif strcmp(dist_type,'rt') 63 | D(i,j)=1-((a+d)/(p+bc)); 64 | elseif strcmp(dist_type,'jt') 65 | D(i,j)=1-(a/(a+bc)); 66 | elseif strcmp(dist_type,'gle') 67 | D(i,j)=1-(2*a/(2*a+bc)); 68 | elseif strcmp(dist_type,'ct4') 69 | D(i,j)=1-(log2(1+a)/log2(1+a+bc)); 70 | elseif strcmp(dist_type,'ac') 71 | D(i,j)=1-((2/pi)*asin(sqrt((a+d)/p))); 72 | end 73 | end 74 | end 75 | end 76 | end 77 | 78 | % ------------------------------------------------ 79 | function [a,bc,d,p] = calcbinary(x,y) 80 | p = length(x); 81 | s = sum([x; y]); 82 | a = length(find(s==2)); 83 | bc = length(find(s==1)); 84 | d = length(find(s==0)); -------------------------------------------------------------------------------- /demo_curet.m: -------------------------------------------------------------------------------- 1 | clear all; 2 | close all; 3 | 4 | addpath(genpath('classification_toolbox_4.0')) 5 | rootpath = '/Users/ahmedtaha/Documents/MATLAB/Datasets/curetcol/sample' 6 | patch_width = -1;patch_height = -1; 7 | training_Dataset = []; 8 | 9 | no_classes = 3; %% Should be 61. This is the number of classes you are going to used during the modeling and classification phase 10 | no_training_classes = 2; %% Should be 20. This is the number of classes you are going to used during the texton dictionary phase 11 | training_classes = [1,4,6,10,12,14,16,18,20,22,25,27,30,33,35,41,45,48,50,59]; 12 | 13 | total_images_per_class = 92; %% Total number of images per texture class 14 | training_per_class = 46; %% Number of images used per texture to build histogram models 15 | test_per_class = total_images_per_class-training_per_class; %% Number of images used per texture to be classified 16 | 17 | %% Specify the filter to be used. 18 | %filter_bank = makeLMfilters; %% to use LM Filter bank 19 | %filter_bank = makeSfilters; %% to use S Filter bank 20 | 21 | filter_bank = makeRFSfilters; %% to use RFS Filter bank 22 | training_options = 'MR8'; %% To indicate that you are going to extract the MR-8 from RFS repos. 23 | classification_options = 'MR8'; 24 | 25 | numOfFilters = size(filter_bank,3); 26 | if strfind(training_options, 'MR8') 27 | numOfFilters =8; 28 | end 29 | 30 | 31 | KNN = 1; 32 | 33 | 34 | numClustersPerClass = 10; 35 | NUM_BINS = numClustersPerClass * no_classes; 36 | 37 | total_images = cell(total_images_per_class,no_training_classes); 38 | 39 | 40 | for c=1:no_training_classes 41 | i = training_classes(c); 42 | folderPath = [rootpath sprintf('%02d',i) '/']; 43 | filenames = [fuf(folderPath ,'detail')]; 44 | total_images(1:total_images_per_class,c) = filenames(1:total_images_per_class ,:); 45 | 46 | end 47 | 48 | 49 | 50 | 51 | 52 | params = {}; 53 | params.numOfFilters = numOfFilters; 54 | params.numClustersPerClass = numClustersPerClass; 55 | params.no_training_classes = no_training_classes; 56 | params.patch_width = patch_width; 57 | params.patch_height = patch_height; 58 | params.filter_bank = filter_bank; 59 | params.training_options = training_options; 60 | params.total_images_per_class = total_images_per_class; 61 | params.total_images = total_images; 62 | 63 | [ training_class_centroid ] = build_texton_dictionary( params ); 64 | 65 | 66 | 67 | classes = 1:no_classes; 68 | training_images = cell(training_per_class,no_classes); 69 | test_images = cell(test_per_class,no_classes); 70 | total_images = cell(total_images_per_class,no_classes); 71 | for c=1:no_classes 72 | i = classes(c); 73 | folderPath = [rootpath sprintf('%02d',i) '/']; 74 | filenames = [fuf(folderPath ,'detail')]; 75 | total_images(1:total_images_per_class,c) = filenames(1:total_images_per_class ,:); 76 | 77 | %% Taking images by order 78 | %training_images(1:training_per_class ,c) = filenames(1:training_per_class ,:); 79 | %test_images(1:test_per_class,c) = filenames(training_per_class+1:total_images_per_class,:); 80 | 81 | %% Alternative images 82 | %training_images(1:training_per_class ,c) = filenames(1:2:total_images_per_class ,:); 83 | %test_images(1:test_per_class,c) = filenames(2:2:total_images_per_class,:); 84 | 85 | perm = randperm(total_images_per_class); 86 | sel = perm(1:training_per_class); 87 | %% Random Images 88 | training_images(1:training_per_class ,c) = filenames(sel); 89 | test_images(1:test_per_class,c) = filenames(setdiff(1:total_images_per_class,sel)); 90 | end 91 | 92 | 93 | 94 | 95 | params = {}; 96 | params.patch_width = patch_width; 97 | params.patch_height = patch_height; 98 | params.filter_bank = filter_bank; 99 | params.training_options = training_options; 100 | params.training_images = training_images; 101 | params.training_class_centroid = training_class_centroid; 102 | params.NUM_BINS = NUM_BINS; 103 | params.training_per_class = training_per_class; 104 | params.no_classes = no_classes; 105 | 106 | [ training_histogram,training_classes ] = build_histogram_models( params); 107 | 108 | 109 | params = {}; 110 | params.patch_width = patch_width; 111 | params.patch_height = patch_height; 112 | params.filter_bank = filter_bank; 113 | params.classification_options = classification_options; 114 | params.training_class_centroid = training_class_centroid; 115 | params.NUM_BINS = NUM_BINS; 116 | params.no_classes = no_classes; 117 | params.training_histogram = training_histogram; 118 | params.training_classes = training_classes; 119 | params.test_images = test_images; 120 | params.test_per_class = test_per_class; 121 | params.KNN = KNN; 122 | [test_histogram,test_classes, accuracy ] = classify_images( params ); 123 | 124 | 125 | 126 | figure;imagesc(accuracy); 127 | mean(diag(accuracy) * 100 / test_per_class) 128 | per_class_accuracy = diag(accuracy) * 100 / test_per_class; -------------------------------------------------------------------------------- /fuf.m: -------------------------------------------------------------------------------- 1 | function srtlist = fuf (folders,reclev,opt) 2 | %FUF recursively retrieves files under specified folder(s). 3 | % 4 | % Syntax: srtlist = fuf (folders,reclev,opt) 5 | % 6 | % INPUT ARGUMENTS 7 | % - folders can be a character array or a cell array of strings. Valid strings 8 | % are matlab path; 9 | % - reclev {1} optional scalar/numeric array of booleans: 1 stands for recursive 10 | % search, whilst 0 limit the search to the specified folder. 11 | % reclev can be either a scalar, or a 1 X length(folders) array. 12 | % Use the 2nd option to specify the search rule on a folder-basis. 13 | % Default is 1, i.d., each folder is searched for recursively. 14 | % - opt {'normal'} | 'detail' is an optional field: when it's set to 'detail', 15 | % FUF returns the full path of files searched for, while, when set to 16 | % normal, it returns file names only. 17 | % 18 | % 19 | % OUTPUT ARGUMENT 20 | % - srtlist is a sorted cell array of strings containing the name or the full path 21 | % of files recursively found under the given folders. 22 | % 23 | % FUF applies the wildcard * for searching files through all the directories beneath the given folder(s) 24 | % if the reclev parameter is set to 1. If you want to have different wildcards for folders belonging 25 | % to the same tree root, you need to pass them separately as input arguments. 26 | % 27 | % REMARKS 28 | % - Folders don't have to belong to the same directory, therefore this function doesn't 29 | % have to be invoked from a particular directory. 30 | % - Matlab partial paths are not valid input arguments. 31 | % - Wildcard * can be used to narrow the search. 32 | % - To get the full path of a given file, FUF doesn't use the which command, 33 | % therefore it normally works also with java function that are not loaded. 34 | % - After completion, the working directory is set to the current directory at the time 35 | % of the function call. 36 | % 37 | % EXAMPLES 38 | % 39 | % To retrieve all files under the folder Utils: 40 | % 41 | % >> dir('C:\matlabR12\work\Interface\Utils') 42 | % 43 | % . Contents.m 44 | % .. my_interface_evalmcw.m 45 | % 46 | % To retrieve recursively the full path of all .m files starting with Cont under the folder work: 47 | % 48 | % >> fuf('C:\matlabR12\work\Con*.m','detail') 49 | % 50 | % 'C:\matlabR12\work\Laboratorio_modellistica\DTT\Contents.m' 51 | % 'C:\matlabR12\work\Laboratorio_modellistica\SDF\Contents.m' 52 | % 'C:\matlabR12\work\PREPOSTGUIS\Contents.m' 53 | % 'C:\matlabR12\work\PREPOSTGUIS\Utils\Contents.m' 54 | % 'C:\matlabR12\work\Pavia\Contents.m' 55 | % 'C:\matlabR12\work\TwoLe_front_end\Contents.m' 56 | % [1x74 char] 57 | % 'C:\matlabR12\work\TwoLe_front_end\My_Classes\@Sector\Contents.m' 58 | % 'C:\matlabR12\work\TwoLe_front_end\Utils\Contents.m' 59 | % 'C:\matlabR12\work\Utils\Contents.m' 60 | % 61 | % To retrieve recursively under the folder PREPOSTGUIS all .fig files and non recursively, under 62 | % the folder MatlabR12 all .txt files: 63 | % 64 | % >> fuf({'C:\matlabR12\work\PREPOSTGUIS\*.fig','C:\matlabR12\*.txt'},[1,0],'detail') 65 | % 66 | % 'C:\matlabR12\license.txt' 67 | % 'C:\matlabR12\work\PREPOSTGUIS\Private\MV_Manager.fig' 68 | % 'C:\matlabR12\work\PREPOSTGUIS\R_h.fig' 69 | % 'C:\matlabR12\work\PREPOSTGUIS\TSA.fig' 70 | % 'C:\matlabR12\work\PREPOSTGUIS\Visual_3D.fig' 71 | 72 | % -$-$-$- 73 | % 74 | % Author: Francesco di Pierro Reasearch Assistant 75 | % Center for Water Systems (CWS) 76 | % Dep. of Engineering and Computer Science 77 | % University of Exeter 78 | % e-mail: 79 | % 80 | % -$-$-$- 81 | 82 | 83 | 84 | 85 | %--------------------CHECK INPUT ARGUMENT TYPE AND SET DEFAULT VALUES------------------------% 86 | 87 | %argument cheking and parsing default parameters 88 | 89 | error(nargchk(1,3,nargin)); 90 | error(nargoutchk(0,1,nargout)); 91 | INITIAL_DIR = pwd; 92 | if nargin==1 93 | if ischar(folders) 94 | folders = cellstr(folders); 95 | elseif ~iscellstr(folders) 96 | error('The 1st argument to the function fuf must be either a string or a cellstring!') 97 | end 98 | reclev = ones(size(folders)); 99 | opt = 'normal'; 100 | elseif nargin==2 101 | if ischar(folders) 102 | folders = cellstr(folders); 103 | elseif ~iscellstr(folders) 104 | error('The 1st argument to the function fuf must be either a string or a cellstring!') 105 | end 106 | if isnumeric(reclev) 107 | if ~all(ismember(reclev,[0,1])) 108 | error('The 2nd argument to the function must be a scalar/vector of booleans!') 109 | end 110 | if prod(size(reclev))==1 111 | reclev = reclev*ones(size(folders)); 112 | elseif prod(size(reclev))~=prod(size(folders)) 113 | error('The 2nd argument to the function must be a either a scalar or a 1 X length(1st argument) array!') 114 | end 115 | opt = 'normal'; 116 | elseif ~ischar(reclev) | ~any(strcmp(reclev,{'normal','detail'})) 117 | error('Mismatched argument specification; the 3rd argument can be either set to ''normal'' or ''detail'''); 118 | else 119 | opt = reclev; 120 | reclev = ones(size(folders)); 121 | end 122 | else 123 | if ischar(folders) 124 | folders = cellstr(folders); 125 | elseif ~iscellstr(folders) 126 | error('The 1st argument to the function fuf must be either a string or a cellstring!') 127 | end 128 | if isnumeric(reclev) 129 | if ~all(ismember(reclev,[0,1])) 130 | error('The 2nd argument to the function must be a scalar/vector of booleans!') 131 | end 132 | if prod(size(reclev))==1 133 | reclev = reclev*ones(size(folders)); 134 | elseif prod(size(reclev))~=prod(size(folders)) 135 | error('The 2nd argument to the function must be a either a scalar or a 1 X length(1st argument) array!') 136 | end 137 | else 138 | error('The 2nd argument to the function must be a scalar/vector of booleans!') 139 | end 140 | if ~ischar(opt) | ~any(strcmp(opt,{'normal','detail'})) 141 | error('Mismatched argument specification: Tte 3rd argument to the function must be either set to ''normal'' or ''detail'''); 142 | end 143 | end 144 | 145 | %scan folders searching for incorrect folder names and partialpaths!!! 146 | EXIT = 0; 147 | for i=1:length(folders) 148 | [d,f,e] = fileparts(folders{i}); 149 | if (~isdir(d) & ~isempty(e)) 150 | warning(['"',d,'" is not a valid folder name!']) 151 | EXIT = 1; 152 | elseif (~isdir(fullfile(d,f,'')) & isempty(e)) 153 | warning(['"',fullfile(d,f,''),'" is not a valid folder name!']) 154 | EXIT = 1; 155 | elseif (isempty(dir(d)) & ~isempty(e)) | (isempty(dir(fullfile(d,f,''))) & isempty(e)) 156 | warning('Matlab PARTIALPATHS not allowed!') 157 | EXIT = 1; 158 | else %this cheks the very unlike event arising 159 | sub = dir(pwd); %when the partial path provided is a directory 160 | [subel{1:length(sub)}] = deal(sub.name); %under the current one: this, in fact, is the 161 | [subtype{1:length(sub)}] = deal(sub.isdir); %only situation where the dir command handles 162 | testel1 = strcmp(subel,fullfile(d,f,'')); %partialpaths!!! 163 | testel2 = strcmp(subel,d); 164 | if ~isempty(subtype(testel1)) | ~isempty(subtype(testel2)) 165 | warning('Matlab PARTIALPATHS not allowed!') 166 | EXIT = 1; 167 | end 168 | end 169 | end 170 | if EXIT 171 | disp('') 172 | error(strvcat('One or more not valid folder names encountered! Function aborted!')) 173 | end 174 | 175 | 176 | %--------------------------------CORE FUNCTION--------------------------------% 177 | 178 | sorted_list = []; %initialize the output list 179 | 180 | sorted_list = rec(sorted_list,folders,reclev,opt); %call the function 181 | 182 | sorted_list = sortrows(sorted_list); %sort the list 183 | 184 | if nargout, srtlist = sorted_list; else disp (' '),disp(sorted_list), end 185 | 186 | cd(INITIAL_DIR); %and set current directory back to the initial one 187 | 188 | %--------------------------------RECURSIVE FUNCTION--------------------------------% 189 | 190 | function sorted_list = rec(sorted_list,folders,reclev,opt) 191 | 192 | for i=1:length(folders) 193 | %first build the new search condition made of all files satistying the 194 | %search condition and all directories under the current one 195 | val = []; val1 = []; val2 = []; cnval1 = {}; cnval2 = {}; cdval = {}; cdva2 = {}; %initialize helper variables 196 | [pth,fname,ext] = fileparts(folders{i}); 197 | cd(pth); %move to the directory: isdir only recognizes directories on the Matlab search path or the current one! 198 | if isdir(fname) 199 | wild = ''; 200 | cd(fname) 201 | pth = fullfile(pth,fname); 202 | val = dir; 203 | else 204 | %get the filenames satisfying the search condition 205 | val1 = dir(folders{i}); 206 | wild = [fname,ext]; 207 | if isempty(val1) 208 | cnval1 = []; cdval1 = []; 209 | else 210 | [cnval1{1:length(val1)}] = deal(val1.name); [cdval1{1:length(val1)}] = deal(val1.isdir); 211 | end 212 | %and the directory/ies under the current one 213 | val2 = dir; 214 | wo = logical(zeros(size(val2))); 215 | for k=1:length(val2) 216 | if val2(k).isdir 217 | wo(k) = 1; 218 | end 219 | end 220 | val2(~wo) = []; 221 | %and build the new search structure 222 | [cnval2{1:length(val2)}] = deal(val2.name); [cdval2{1:length(val2)}] = deal(val2.isdir); 223 | cnval = [cnval1,cnval2]; cdval = [cdval1,cdval2]; 224 | [val(1:length(cnval)).name] = deal(cnval{:}); [val(1:length(cdval)).isdir] = deal(cdval{:}); 225 | end 226 | for j=1:length(val) 227 | if (val(j).isdir) & not(strcmp(val(j).name,'.')) & not(strcmp(val(j).name,'..')) %if the jth object under the ith folder is a valid folder name(directory)... 228 | new_path = fullfile(pth,val(j).name); %set the current directory to that one: 229 | cd(new_path); 230 | if reclev(i) %recursively call the function keeping in mind the search condition 231 | sorted_list = rec(sorted_list,{fullfile(new_path,wild)},reclev(i),opt); 232 | end 233 | cd .. %get back to the previous directory 234 | elseif not(strcmp(val(j).name,'.')) & not(strcmp(val(j).name,'..')) %if the jth object under the ith folder is a valid file name 235 | if strcmp(opt,'detail') 236 | sorted_list =[sorted_list; cellstr(fullfile(pwd,val(j).name))]; 237 | else 238 | sorted_list =[sorted_list; cellstr(val(j).name)]; 239 | end 240 | end 241 | end 242 | end --------------------------------------------------------------------------------