Line descriptors matching demo

This example shows the functionalities of line descriptors matching furnished by cv.BinaryDescriptorMatcher class.

This module shows how to extract line segments from an image by 2 different methods: First segmenting lines with Line Segment Detector cv.LSDDetector, and then (or just) using the Binary Descriptor to get the lines and give them a descriptor cv.BinaryDescriptor. Finally, we can then match line segments using the cv.BinaryDescriptorMatcher class.

Sources:

Contents

Matching among descriptors

If we have extracted descriptors from two different images, it is possible to search for matches among them. One way of doing it is matching exactly a descriptor to each input query descriptor, choosing the one at closest distance.

Sometimes, we could be interested in searching for the closest k descriptors, given an input one. See cv.BinaryDescriptorMatcher.knnMatch

In some cases, we could have a search radius and look for all descriptors distant at the most r from input query. See cv.BinaryDescriptorMatcher.radiusMatch

Images

% load images
if false
    img1 = cv.imread(fullfile(mexopencv.root(),'test','books_left.jpg'), 'Color',true);
    img2 = cv.imread(fullfile(mexopencv.root(),'test','books_right.jpg'), 'Color',true);
else
    im = which('cameraman.tif');
    if isempty(im), im = fullfile(mexopencv.root(),'test','blox.jpg'); end
    img1 = cv.imread(im, 'Color',true);
    M = cv.getRotationMatrix2D(round([size(img1,2) size(img1,1)]./2), -20, 0.9);
    img2 = cv.warpAffine(img1, M);
end

% create binary masks
mask1 = ones(size(img1,1), size(img1,2), 'uint8');
mask2 = ones(size(img2,1), size(img2,2), 'uint8');

subplot(121), imshow(img1)
subplot(122), imshow(img2)
whos img1 img2 mask1 mask2
  Name         Size                Bytes  Class    Attributes

  img1       256x256x3            196608  uint8              
  img2       256x256x3            196608  uint8              
  mask1      256x256               65536  uint8              
  mask2      256x256               65536  uint8              

BinaryDescriptor: Detect and Compute

% create a BinaryDescriptor object with default parameters
bd = cv.BinaryDescriptor();

% compute lines and descriptors
[keylines1, descr1] = bd.detectAndCompute(img1, 'Mask',mask1);
[keylines2, descr2] = bd.detectAndCompute(img2, 'Mask',mask2);
whos keylines1 keylines2 descr1 descr2

% select keylines from first octave and their descriptors
idx = ([keylines1.octave] == 0);
keylines1 = keylines1(idx);
descr1 = descr1(idx,:);

idx = ([keylines2.octave] == 0);
keylines2 = keylines2(idx);
descr2 = descr2(idx,:);
  Name            Size            Bytes  Class     Attributes

  descr1         53x32             1696  uint8               
  descr2         46x32             1472  uint8               
  keylines1       1x53            79208  struct              
  keylines2       1x46            68848  struct              

BinaryDescriptor: Match

% create a BinaryDescriptorMatcher object
bdm = cv.BinaryDescriptorMatcher();

% require match
matches = bdm.match(descr1, descr2)

% select best matches
MATCHES_DIST_THRESHOLD = 25;
good_matches = ([matches.distance] < MATCHES_DIST_THRESHOLD);
fprintf('number of good matches = %d\n', nnz(good_matches));

% plot matches
outImg = cv.drawLineMatches(img1, keylines1, img2, keylines2, matches, ...
    'MatchesMask',good_matches);
figure, imshow(outImg)
title('Matches in octave 0')
matches = 
  1×53 struct array with fields:
    queryIdx
    trainIdx
    imgIdx
    distance
number of good matches = 12

LSDDetector: Detect and Compute

% create an LSD detector
lsd = cv.LSDDetector();

% detect lines
keylines1 = lsd.detect(img1, 'Scale',2, 'NumOctaves',2, 'Mask',mask1);
keylines2 = lsd.detect(img2, 'Scale',2, 'NumOctaves',2, 'Mask',mask2);
whos keylines1 keylines2

% compute descriptors for lines
descr1 = bd.compute(img1, keylines1);
descr2 = bd.compute(img2, keylines2);
whos descr1 descr2

% select lines and descriptors from second octave
idx = ([keylines1.octave] == 1);
keylines1 = keylines1(idx);
descr1 = descr1(idx,:);

idx = ([keylines2.octave] == 1);
keylines2 = keylines2(idx);
descr2 = descr2(idx,:);
  Name           Size              Bytes  Class     Attributes

  keylines1      1x230            341168  struct              
  keylines2      1x208            308608  struct              

  Name          Size            Bytes  Class    Attributes

  descr1      230x32             7360  uint8              
  descr2      208x32             6656  uint8              

LSDDetector: Match

% compute matches
matches = bdm.match(descr1, descr2)

% select best matches
good_matches = ([matches.distance] < MATCHES_DIST_THRESHOLD);
fprintf('number of good matches = %d\n', nnz(good_matches));

% plot matches
img1 = cv.resize(img1, 0.5, 0.5);
img2 = cv.resize(img2, 0.5, 0.5);
outImg = cv.drawLineMatches(img1, keylines1, img2, keylines2, matches, ...
    'MatchesMask',good_matches);
figure, imshow(outImg)
title('LSD Matches in octave 1')
matches = 
  1×64 struct array with fields:
    queryIdx
    trainIdx
    imgIdx
    distance
number of good matches = 16