From ce3ae125b4801f853d3691dbae1914a79944819b Mon Sep 17 00:00:00 2001 From: Jervis Muindi Date: Mon, 12 Dec 2011 00:11:31 -0500 Subject: [PATCH] Added code to classify handwritten digits using nearest neighbor with MNIST dataset as the training set --- approach1.m | 189 +++++++++++++++++++++++++++++++++++++++++++++++++++ approach2.m | 189 +++++++++++++++++++++++++++++++++++++++++++++++++++ approach3.m | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++++ binarize.m | 21 ++++++ darken.m | 21 ++++++ extract.m | 27 ++++++++ pca.m | 129 +++++++++++++++++++++++++++++++++++ proc.m | 22 ++++++ proc2.m | 23 +++++++ procTD.m | 33 +++++++++ testhnd.m | 188 +++++++++++++++++++++++++++++++++++++++++++++++++++ thicken.m | 46 +++++++++++++ 12 files changed, 1078 insertions(+) create mode 100644 approach1.m create mode 100644 approach2.m create mode 100644 approach3.m create mode 100644 binarize.m create mode 100644 darken.m create mode 100644 extract.m create mode 100644 pca.m create mode 100644 proc.m create mode 100644 proc2.m create mode 100644 procTD.m create mode 100644 testhnd.m create mode 100644 thicken.m diff --git a/approach1.m b/approach1.m new file mode 100644 index 0000000..11612fd --- /dev/null +++ b/approach1.m @@ -0,0 +1,189 @@ +% Jervis Muindi +% Biometrics Final Project +% 11th December 2011 + +% Does classification on test data set. +% By applying nearest neighbor directly +% on extracted features. +function approach1() +% Does a test for classifying the handwritten images. + +disp('reading data'); +% assume, we have loaded +[train_data, train_labels ] = readDATA(); + +[test_data, test_labels] = loadHndDATA(); + +sizeTrain = size(train_data,2); +sizeTest = size(test_data,2); +sizeTest = 50; + +%Do a quick nearest neighbor test classification. +errors = 0; +for i = 1:sizeTest + + fprintf('test %d - ', i); + tv = test_data{i}; + tv = tv(:); + + minIdx = 0; + minDist = Inf; + + for j = 1:sizeTrain + + av = train_data{j}; + av = av(:); + diff = tv - av; + dist = norm(diff,2); + + if(dist < minDist) + minDist = dist; + %disp(j); + minIdx = j; + end + %disp('running'); + %disp(dist); + + end + %error('s'); + + %save result; + + result(i) = train_labels{minIdx}; + + + %do accuracy checking in line + if( test_labels(i) ~= result(i) ) + errors = errors + 1; + + end + + tot = i; + curr_acc = (tot - errors) / tot; + + if( test_labels(i) ~= result(i) ) + + fprintf('Curr Accuracy: %f | %d,%d.\n', curr_acc, test_labels(i),result(i) ); + figure; + im = [test_data{i} train_data{minIdx} ]; + imshow(im); + continue; + end + + fprintf('Curr Accuracy: %f.\n', curr_acc); + +end + + + +end + + + + + + + + + + + +%{ +K NEaREST NEIGHTBOR + +function testhnd() +% Does a test for classifying the handwritten images. + +disp('reading data'); +% assume, we have loaded +[train_data, train_labels ] = readDATA(); + +[test_data, test_labels] = loadHndDATA(); + +sizeTrain = size(train_data,2); +%sizeTrain = 10000; +sizeTest = size(test_data,2); +sizeTest = 200; +%Do a quick nearest neighbor test classification. +errors = 0; + + + +for i = 1:sizeTest + + fprintf('test %d - ', i); + tv = test_data{i}; + tv = tv(:); + + + minIdx = 0; + minDist = Inf; + + arr(1) = 0; + arr(2) = 0; + arr(3) = 0; + for j = 1:sizeTrain + + av = train_data{j}; + av = av(:); + diff = tv - av; + dist = norm(diff,2); + + if(dist < minDist) + minDist = dist; + %disp(j); + minIdx = j; + + prev_first = arr(1); + prev_sec = arr(2); + + arr(1) = minIdx; + arr(2) = prev_first; + arr(3) = prev_sec; + + end + %disp('running'); + %disp(dist); + + end + + num = [train_labels{arr(1)};train_labels{arr(2)} ;train_labels{arr(3)}]; + indices = zeros(10,1); + + for ii = 1:3 + indices(num(ii)+1) = indices(num(ii)+1) + 1; + end + + [x,number] = max(indices); + + %error('s'); + + %save result; + result(i) = number - 1; + + %result(i) = train_labels{minIdx}; + + + %do accuracy checking in line + if( test_labels(i) ~= result(i) ) + errors = errors + 1; + + end + tot = i; + curr_acc = (tot - errors) / tot; + + if( test_labels(i) ~= result(i) ) + + fprintf('Curr Accuracy: %f | %d,%d.\n', curr_acc, test_labels(i),result(i) ); + figure; + continue; + end + fprintf('Curr Accuracy: %f.\n', curr_acc ); + +end + + + +end + +%} diff --git a/approach2.m b/approach2.m new file mode 100644 index 0000000..d791393 --- /dev/null +++ b/approach2.m @@ -0,0 +1,189 @@ +% Jervis Muindi +% Does classification on test data set. +% By applying nearest neighbor directly +% on extracted digits that have been bounded to +% a box. +function approach2() +% Does a test for classifying the handwritten images. + +disp('reading data'); +% assume, we have loaded +[train_data, train_labels ] = readDATA(); +train_data = procTD(train_data);% Process the trainig data to bound image to a bounding box. + +[test_data, test_labels] = loadHndDATA(); + +sizeTrain = size(train_data,2); +sizeTest = size(test_data,2); +sizeTest = 200; + +%Do a quick nearest neighbor test classification. +errors = 0; +for i = 1:sizeTest + + fprintf('test %d - ', i); + tv = test_data{i}; + tv = proc(tv); %process the test image so that it's also bound to a box of 28 x 28. + tv = tv(:); + + minIdx = 0; + minDist = Inf; + + for j = 1:sizeTrain + + av = train_data{j}; + av = av(:); + diff = tv - av; + dist = norm(diff,2); + + if(dist < minDist) + minDist = dist; + %disp(j); + minIdx = j; + end + %disp('running'); + %disp(dist); + + end + %error('s'); + + %save result; + + result(i) = train_labels{minIdx}; + + + %do accuracy checking in line + if( test_labels(i) ~= result(i) ) + errors = errors + 1; + + end + + tot = i; + curr_acc = (tot - errors) / tot; + + if( test_labels(i) ~= result(i) ) + + fprintf('Curr Accuracy: %f | %d,%d.\n', curr_acc, test_labels(i),result(i) ); + %figure; + im = [test_data{i} train_data{minIdx} ]; + %imshow(im); + continue; + end + + fprintf('Curr Accuracy: %f.\n', curr_acc); + +end + + + +end + + + + + + + + + + + +%{ +K NEaREST NEIGHTBOR + +function testhnd() +% Does a test for classifying the handwritten images. + +disp('reading data'); +% assume, we have loaded +[train_data, train_labels ] = readDATA(); + +[test_data, test_labels] = loadHndDATA(); + +sizeTrain = size(train_data,2); +%sizeTrain = 10000; +sizeTest = size(test_data,2); +sizeTest = 200; +%Do a quick nearest neighbor test classification. +errors = 0; + + + +for i = 1:sizeTest + + fprintf('test %d - ', i); + tv = test_data{i}; + tv = tv(:); + + + minIdx = 0; + minDist = Inf; + + arr(1) = 0; + arr(2) = 0; + arr(3) = 0; + for j = 1:sizeTrain + + av = train_data{j}; + av = av(:); + diff = tv - av; + dist = norm(diff,2); + + if(dist < minDist) + minDist = dist; + %disp(j); + minIdx = j; + + prev_first = arr(1); + prev_sec = arr(2); + + arr(1) = minIdx; + arr(2) = prev_first; + arr(3) = prev_sec; + + end + %disp('running'); + %disp(dist); + + end + + num = [train_labels{arr(1)};train_labels{arr(2)} ;train_labels{arr(3)}]; + indices = zeros(10,1); + + for ii = 1:3 + indices(num(ii)+1) = indices(num(ii)+1) + 1; + end + + [x,number] = max(indices); + + %error('s'); + + %save result; + result(i) = number - 1; + + %result(i) = train_labels{minIdx}; + + + %do accuracy checking in line + if( test_labels(i) ~= result(i) ) + errors = errors + 1; + + end + tot = i; + curr_acc = (tot - errors) / tot; + + if( test_labels(i) ~= result(i) ) + + fprintf('Curr Accuracy: %f | %d,%d.\n', curr_acc, test_labels(i),result(i) ); + figure; + continue; + end + fprintf('Curr Accuracy: %f.\n', curr_acc ); + +end + + + +end + +%} diff --git a/approach3.m b/approach3.m new file mode 100644 index 0000000..e204546 --- /dev/null +++ b/approach3.m @@ -0,0 +1,190 @@ +% Jervis Muindi +% Does classification on test data set. +% By applying nearest neighbor directly +% on extracted digits that have been bounded to +% a box and also thickening the test images by 2 pixels. +function approach3() +% Does a test for classifying the handwritten images. + +disp('reading data'); +% assume, we have loaded +[train_data, train_labels ] = readDATA(); +train_data = procTD(train_data);% Process the trainig data to bound image to a bounding box. + +[test_data, test_labels] = loadHndDATA(); + +sizeTrain = size(train_data,2); +sizeTest = size(test_data,2); +sizeTest = 50; + +%Do a quick nearest neighbor test classification. +errors = 0; +for i = 1:sizeTest + + fprintf('test %d - ', i); + tv = test_data{i}; + %process the test image so that it's also bound to a box of 28 x 28 and also thicken it by adding 2 pixels to digit outline.. + tv = proc2(tv); + tv = tv(:); + + minIdx = 0; + minDist = Inf; + + for j = 1:sizeTrain + + av = train_data{j}; + av = av(:); + diff = tv - av; + dist = norm(diff,2); + + if(dist < minDist) + minDist = dist; + %disp(j); + minIdx = j; + end + %disp('running'); + %disp(dist); + + end + %error('s'); + + %save result; + + result(i) = train_labels{minIdx}; + + + %do accuracy checking in line + if( test_labels(i) ~= result(i) ) + errors = errors + 1; + + end + + tot = i; + curr_acc = (tot - errors) / tot; + + if( test_labels(i) ~= result(i) ) + + fprintf('Curr Accuracy: %f | %d,%d.\n', curr_acc, test_labels(i),result(i) ); + figure; + im = [test_data{i} train_data{minIdx} ]; + %imshow(im); + continue; + end + + fprintf('Curr Accuracy: %f.\n', curr_acc); + +end + + + +end + + + + + + + + + + + +%{ +K NEaREST NEIGHTBOR + +function testhnd() +% Does a test for classifying the handwritten images. + +disp('reading data'); +% assume, we have loaded +[train_data, train_labels ] = readDATA(); + +[test_data, test_labels] = loadHndDATA(); + +sizeTrain = size(train_data,2); +%sizeTrain = 10000; +sizeTest = size(test_data,2); +sizeTest = 200; +%Do a quick nearest neighbor test classification. +errors = 0; + + + +for i = 1:sizeTest + + fprintf('test %d - ', i); + tv = test_data{i}; + tv = tv(:); + + + minIdx = 0; + minDist = Inf; + + arr(1) = 0; + arr(2) = 0; + arr(3) = 0; + for j = 1:sizeTrain + + av = train_data{j}; + av = av(:); + diff = tv - av; + dist = norm(diff,2); + + if(dist < minDist) + minDist = dist; + %disp(j); + minIdx = j; + + prev_first = arr(1); + prev_sec = arr(2); + + arr(1) = minIdx; + arr(2) = prev_first; + arr(3) = prev_sec; + + end + %disp('running'); + %disp(dist); + + end + + num = [train_labels{arr(1)};train_labels{arr(2)} ;train_labels{arr(3)}]; + indices = zeros(10,1); + + for ii = 1:3 + indices(num(ii)+1) = indices(num(ii)+1) + 1; + end + + [x,number] = max(indices); + + %error('s'); + + %save result; + result(i) = number - 1; + + %result(i) = train_labels{minIdx}; + + + %do accuracy checking in line + if( test_labels(i) ~= result(i) ) + errors = errors + 1; + + end + tot = i; + curr_acc = (tot - errors) / tot; + + if( test_labels(i) ~= result(i) ) + + fprintf('Curr Accuracy: %f | %d,%d.\n', curr_acc, test_labels(i),result(i) ); + figure; + continue; + end + fprintf('Curr Accuracy: %f.\n', curr_acc ); + +end + + + +end + +%} diff --git a/binarize.m b/binarize.m new file mode 100644 index 0000000..332989c --- /dev/null +++ b/binarize.m @@ -0,0 +1,21 @@ + +function r = binarize(A) + + r = size(A,1); + c = size(A,2); + + for i=1:r + for j = 1:c + + if(A(i,j) > 0.1) + A(i,j) = 1; + else + A(i,j) = 0; + end + + end + end + + r=A; + +end diff --git a/darken.m b/darken.m new file mode 100644 index 0000000..ef35f2a --- /dev/null +++ b/darken.m @@ -0,0 +1,21 @@ + + +function r = darken(A) +%convert from white background to black background + + rows = size(A,1); + cols = size(A,2); + + for i = 1:rows + for j = 1:cols + if(A(i,j) == 1) + A(i,j) = 0; + else + A(i,j) = 1; %prev was : 1 - A(i,j). right now we're binarizing img. + end + end + end + + r = A; +end + diff --git a/extract.m b/extract.m new file mode 100644 index 0000000..9d4afb1 --- /dev/null +++ b/extract.m @@ -0,0 +1,27 @@ + +%extracts just the outline of the number. find find the topleft pixel and +% the bottom right pixel. +function r = extract(A) + r = size(A,1); + c = size(A,2); + + x = []; + y = []; + for i=1:r + for j=1:c + if(A(i,j) == 1) + x = [x; i]; + y = [y; j]; + end + end + end + + minx = min(x); + maxx = max(x); + miny = min(y); + maxy = max(y); + + r = A(minx:maxx,miny:maxy); + +end + diff --git a/pca.m b/pca.m new file mode 100644 index 0000000..2d75d23 --- /dev/null +++ b/pca.m @@ -0,0 +1,129 @@ +function [ signals, PC, V ] = pca( data ) +% Perform PCA. +% Data is the data matrix having dimensions in the columns and each image vector in the rows +% data - of size M by N +% PC - the principal components +% V - M by 1 of variances +% proj - the projected data +% + + +% Create the mean vector. This contains the means of each dimension +% of the data matrix (the cols) + +[M,N] = size(data); +mn = mean(data,2); +%mn = mn'; %covnert to column vector + +% subtract the mean of each dimension from the data matrix +disp('subtracting means..'); +size(mn) +data = data - repmat(mn,1,N); + +%calculate the convariance matrix. +size(data) +disp('computing conv'); + +covariance = 1 / (N-1) * (data * data') ; + +disp('finding eig vals'); +%find the eigen vectors and eigen values +[PC, V] = eig(covariance); + +%extract diagonal of matrix as vector which has the eigen values. +V = diag(V); + +%sort the eigen values in decreasing order +[sorted, rindices] = sort(V, 'descend'); + + +V = sorted; +disp(' e v'); +V +rindices = rindices(1:10, :); +%size(rindices) + +%PC = PC(:, rindices); + +disp('doing projections'); +%project the original data set. +signals = PC' * data; + +%{ +disp('orig data'); +size(data) +disp('proj data'); +size(signals) + +error('xxxxxxx'); +%} + + + +end + +%{ +function [ signals, PC, V ] = pca( data ) +% Perform PCA. +% Data is the data matrix having dimensions in the columns and each image vector in the rows +% data - of size M by N +% PC - the principal components +% V - M by 1 of variances +% proj - the projected data +% + + +% Create the mean vector. This contains the means of each dimension +% of the data matrix (the cols) + +[M,N] = size(data); +mn = mean(data,2); + +% subtract the mean of each dimension from the data matrix +disp('subtracting means..'); + +data = data - repmat(mn,1,N); + +%calculate the convariance matrix. +size(data) +disp('computing conv'); + +covariance = 1 / (N-1) * (data * data') ; + +disp('finding eig vals'); +%find the eigen vectors and eigen values +[PC, V] = eig(covariance); + +%extract diagonal of matrix as vector which has the eigen values. +V = diag(V); + +%sort the eigen values in decreasing order +[sorted, rindices] = sort(V, 'descend'); + + +V = sorted; + +%rindices = rindices(1:20, :); +%size(rindices) + +PC = PC(:, rindices); + +disp('doing projections'); +%project the original data set. +signals = PC' * data; + + +disp('orig data'); +size(data) +disp('proj data'); +size(signals) + +error('xxxxxxx'); + + + + +end + + +%} \ No newline at end of file diff --git a/proc.m b/proc.m new file mode 100644 index 0000000..c9ab221 --- /dev/null +++ b/proc.m @@ -0,0 +1,22 @@ +% Jervis Muindi +% Biometrics Final Project +% 11th December 2011 + +function r = proc( image ) +%Process given image by bouding digits to bounding box. +% this also thickens the image. should be used for handwrittend +% self gathered test images. + + + %process img sample. + + img_sample = image; + img_sample = binarize(img_sample); + img_sample = extract(img_sample); % bound it + img_sample = imresize(img_sample, [28 28]); % resize + img_sample = binarize(img_sample); % re-binarize + + r = img_sample; + +end + diff --git a/proc2.m b/proc2.m new file mode 100644 index 0000000..1146808 --- /dev/null +++ b/proc2.m @@ -0,0 +1,23 @@ +% Jervis Muindi +% Biometrics Final Project +% 11th December 2011 + +function r = proc2( image ) + %Process given image by bouding digits to bounding box. + % this also thickens the image. should be used for handwrittend + % self gathered test images. + + + %process img sample. + + img_sample = image; + img_sample = binarize(img_sample); + img_sample = extract(img_sample); % bound it + img_sample = imresize(img_sample, [28 28]); % resize + img_sample = binarize(img_sample); % re-binarize + img_sample = thicken(img_sample); % thicken + + r = img_sample; + +end + diff --git a/procTD.m b/procTD.m new file mode 100644 index 0000000..ef2c60b --- /dev/null +++ b/procTD.m @@ -0,0 +1,33 @@ +% Jervis Muindi +% Biometrics Final Project +% 11th December 2011 + +function r = procTD( images ) +% Process the traing data (image cell array) by bouding digits to bounding box. +% this is for trainig data. + + + length = size(images,2); + + %process all img samples. + disp('Processing images in Training Set...'); + for i = 1:length + + if(mod(i,1000) == 0) + fprintf('Processed %d of 60000 training samples\n',i); + end + + img_sample = images{i}; + img_sample = binarize(img_sample); + img_sample = extract(img_sample); % bound it + img_sample = imresize(img_sample, [28 28]); % resize + img_sample = binarize(img_sample); % re-binarize + + images{i} = img_sample; + + end + + r = images; + +end + diff --git a/testhnd.m b/testhnd.m new file mode 100644 index 0000000..2e4f9bc --- /dev/null +++ b/testhnd.m @@ -0,0 +1,188 @@ +function testhnd() +% Does a test for classifying the handwritten images. + +disp('reading data'); +% assume, we have loaded +[train_data, train_labels ] = readDATA(); + +[test_data, test_labels] = loadHndDATA(); + +train_data = preprocTD(train_data); % convert pixel to bounded box + +sizeTrain = size(train_data,2); +sizeTest = size(test_data,2); +sizeTest = 200; +%Do a quick nearest neighbor test classification. +errors = 0; + + + +for i = 1:sizeTest + + fprintf('test %d - ', i); + tv = test_data{i}; + tv = preproc(tv); % pre process and bind it to box + tv = tv(:); + + + minIdx = 0; + minDist = Inf; + + for j = 1:sizeTrain + + av = train_data{j}; + av = av(:); + diff = tv - av; + dist = norm(diff,2); + + if(dist < minDist) + minDist = dist; + %disp(j); + minIdx = j; + end + %disp('running'); + %disp(dist); + + end + %error('s'); + + %save result; + + result(i) = train_labels{minIdx}; + + + %do accuracy checking in line + if( test_labels(i) ~= result(i) ) + errors = errors + 1; + + end + tot = i; + curr_acc = (tot - errors) / tot; + + + if( test_labels(i) ~= result(i) ) + + fprintf('Curr Accuracy: %f | %d,%d.\n', curr_acc, test_labels(i),result(i) ); + %figure; + im = [test_data{i} train_data{minIdx} ]; + %imshow(im); + continue; + end + + fprintf('Curr Accuracy: %f.\n', curr_acc); + +end + + + +end + + + + + + + + + + + +%{ +K NEaREST NEIGHTBOR + +function testhnd() +% Does a test for classifying the handwritten images. + +disp('reading data'); +% assume, we have loaded +[train_data, train_labels ] = readDATA(); + +[test_data, test_labels] = loadHndDATA(); + +sizeTrain = size(train_data,2); +%sizeTrain = 10000; +sizeTest = size(test_data,2); +sizeTest = 200; +%Do a quick nearest neighbor test classification. +errors = 0; + + + +for i = 1:sizeTest + + fprintf('test %d - ', i); + tv = test_data{i}; + tv = tv(:); + + + minIdx = 0; + minDist = Inf; + + arr(1) = 0; + arr(2) = 0; + arr(3) = 0; + for j = 1:sizeTrain + + av = train_data{j}; + av = av(:); + diff = tv - av; + dist = norm(diff,2); + + if(dist < minDist) + minDist = dist; + %disp(j); + minIdx = j; + + prev_first = arr(1); + prev_sec = arr(2); + + arr(1) = minIdx; + arr(2) = prev_first; + arr(3) = prev_sec; + + end + %disp('running'); + %disp(dist); + + end + + num = [train_labels{arr(1)};train_labels{arr(2)} ;train_labels{arr(3)}]; + indices = zeros(10,1); + + for ii = 1:3 + indices(num(ii)+1) = indices(num(ii)+1) + 1; + end + + [x,number] = max(indices); + + %error('s'); + + %save result; + result(i) = number - 1; + + %result(i) = train_labels{minIdx}; + + + %do accuracy checking in line + if( test_labels(i) ~= result(i) ) + errors = errors + 1; + + end + tot = i; + curr_acc = (tot - errors) / tot; + + if( test_labels(i) ~= result(i) ) + + fprintf('Curr Accuracy: %f | %d,%d.\n', curr_acc, test_labels(i),result(i) ); + figure; + continue; + end + fprintf('Curr Accuracy: %f.\n', curr_acc ); + +end + + + +end + +%} diff --git a/thicken.m b/thicken.m new file mode 100644 index 0000000..451d86e --- /dev/null +++ b/thicken.m @@ -0,0 +1,46 @@ + +%thickens number outline +function r = thicken(A) + + %essentially binarize image. + rows = size(A,1); + cols = size(A,2); + + A = binarize(A); + + + %then we add a 1-px to outline to thicken it. + + thickness = 3; + + for i = 1:rows + for j = 1:cols + if(A(i,j) == 0) % at a zero pixel + %check if border pixel ahead to the east. + if( j+thickness <= cols && A(i,j+thickness) == 1) % check east + + for x = 1:thickness + A(i,j+x-1) = 1; + end + %A(i,j) = 1; + + end + + if( i+thickness <= rows && A(i+thickness,j) == 1) % check south + + for x = 1:thickness + A(i+x-1,j) = 1; + end + %A(i,j) = 1; + + end + + + end + end + end + + + + r = A; +end