Clear Filters
Clear Filters

Find matrix inside larger matrix with tolerance

2 views (last 30 days)
How can I write a script to find a smaller matrix B inside a larger matrix A with a specified tolerance and return the index/indices where B starts in A? For example, with a tolerance of 0.1:
A =
8 1 4 8 8 5
8 3 10 2 3 10
4 1 1 5 7 4
7 1 5 5 7 6
2 9 4 7 2 3
8 7 8 8 2 8
B =
0.9 1.1 5
1.1 5 4.9
9 3.9 7.1
index = (2,3)
  1 Comment
DGM
DGM on 21 Jun 2021
Edited: DGM on 21 Jun 2021
You'll need to define your testing criteria before a tolerance metric has meaning. A tolerance of 0.1 might mean any number of things depending on what the goal was. Consider the matrix B and the corresponding region in A at any given point during evaluation (Ax)
  • Match occurs if all(abs(Ax-B)<0.1) (probably what you want?)
  • Match occurs if all(rms(Ax-B)<0.1)
  • Match occurs if mean2(Ax-B)<0.1
  • Match occurs if sum(Ax-B)<0.1
Depending on how loose your requirements are, you may simply be able to use normxcorr2() if you just want to find the closest, if inexact match.
A logical filter as described above could otherwise be implemented using nlfilter() and a user-defined function to make the comparison. That said, if it's something you need to use often, you might find nlfilter() to be inconveniently slow. Replacing it with a simple sliding window routine is often faster.

Sign in to comment.

Accepted Answer

DGM
DGM on 21 Jun 2021
As I mentioned, you can do this with nlfilter()
A = [8 1 4 8 8 5;
8 3 10 2 3 10;
4 1 1 5 7 4;
7 1 5 5 7 6;
2 9 4 7 2 3;
8 7 8 8 2 8];
B = [0.9 1.1 5;
1.1 5 4.9;
9 3.9 7.1];
tol = 0.1;
% use nlfilter()
F = @(x) all(abs(x-B)<=(tol+eps),'all');
map = nlfilter(A,size(B),F) % logical map of matches
[row col] = find(map) % if you really want subscripts instead
% can't run nlfilter() in the browser, so there are no example outputs here
Or you could just do the same process without nlfilter()
filtsize = size(B);
s0 = size(A);
padsize = floor(filtsize/2);
% nlfilter() uses zero-padding, but you could replicate, etc
A = padarray(A,padsize,0,'both');
s = size(A);
matches = false(s0);
osm = filtsize(1)-1;
osn = filtsize(2)-1;
for n = 1:(s(2)-2*padsize(2))
for m = 1:(s(1)-2*padsize(1))
sample = A(m:(m+osm),n:(n+osn));
matches(m,n) = all(abs(sample-B)<=(tol+eps),'all');
end
end
matches % logical map of matches
matches = 6×6 logical array
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
[row col] = find(matches) % if you really want subscripts instead
row = 4
col = 3

More Answers (0)

Categories

Find more on Multidimensional Arrays in Help Center and File Exchange

Tags

Products


Release

R2019a

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!