Shape context for shape matching

This program demonstrates a method for shape comparison based on Shape Context.

We use 20 sample images from OpenCV: https://github.com/opencv/opencv/tree/3.1.0/samples/data/shape_sample/*.png

Sources:

Read set of images

fpath = fullfile(mexopencv.root(),'test');
files = dir(fullfile(fpath,'shape*.png'));
imgs = cell(1, numel(files));
for i=1:numel(files)
    imgs{i} = cv.imread(fullfile(fpath, files(i).name), 'Grayscale',true);
end

Extract contours

contours = cell(size(imgs));
for i=1:numel(imgs)
    cont = cv.findContours(imgs{i}, 'Mode','List', 'Method','None');
    cont = [cont{:}];
    cont = cat(1,cont{:});
    contours{i} = cont;    % flattened 2D points
end

use the same number of points for all images

[NN,~] = cellfun(@size, contours);
npts = min(NN);  % 300
for i=1:numel(contours)
    cont = contours{i};
    N = size(cont,1);

    % uniformly sample same number of points
    idx = randperm(N, npts);
    cont = cont(sort(idx),:);

    % reshaped into 2-channels as 1xNx2
    contours{i} = permute(cont, [3 1 2]);
end

query image (provide any number between 1 and 20 for selecting an image in the folder)

indexQuery = 11;

compute distance between query and all images

if true
    sc = cv.ShapeContextDistanceExtractor();
else
    sc = cv.HausdorffDistanceExtractor();
end
dist = zeros(size(contours));
hWait = waitbar(0, 'Calculating distances');
for i=1:numel(contours)
    if i == indexQuery
        continue;
    end
    waitbar(i/numel(contours), hWait);
    tic
    dist(i) = sc.computeDistance(contours{indexQuery}, contours{i});
    toc
end
close(hWait)

% sorted matches
[~,ord] = sort(dist);
Elapsed time is 5.400297 seconds.
Elapsed time is 5.340579 seconds.
Elapsed time is 5.337628 seconds.
Elapsed time is 5.352275 seconds.
Elapsed time is 5.587719 seconds.
Elapsed time is 5.510961 seconds.
Elapsed time is 5.550998 seconds.
Elapsed time is 5.539079 seconds.
Elapsed time is 5.418877 seconds.
Elapsed time is 5.475764 seconds.
Elapsed time is 5.526154 seconds.
Elapsed time is 5.485514 seconds.
Elapsed time is 5.548504 seconds.
Elapsed time is 5.548055 seconds.
Elapsed time is 5.555361 seconds.
Elapsed time is 5.491198 seconds.
Elapsed time is 5.485358 seconds.
Elapsed time is 5.436754 seconds.
Elapsed time is 5.491954 seconds.

show all distances (sorted)

if ~mexopencv.isOctave()
    %HACK: not implemented in Octave
    t = array2table(dist(:), 'VariableNames',{'Distance'}, ...
        'RowNames',cellstr(num2str((1:numel(dist))')));
    display(sortrows(t))
end
  20×1 table
           Distance 
          __________
    11             0
    12        3.4207
    1         4.0969
    9         88.539
    5         242.81
    15        263.47
    10        274.33
    6         421.81
    16        486.32
    2         565.28
    8         1669.6
    7         2154.4
    20         30147
    18         38864
    19         55634
    13         88106
    14         97760
    17    1.0517e+05
    4     1.2892e+05
    3     1.8379e+05

show best 3 image matches

subplot(221), imshow(imgs{indexQuery}), title('query')
for i=(1:3)+1
    subplot(2,2,i), imshow(imgs{ord(i)})
    title(sprintf('match #%d = %.3f', i-1, dist(ord(i))))
end