Home > Software engineering >  Finding a multi-value submatrix with wildcards
Finding a multi-value submatrix with wildcards

Time:10-10

I have a matrix with these values (if it helps, this an rgb image):

mat = np.array([
    [[0, 0, 0], [123, 0, 255], [0, 0, 0]],
    [[0, 0, 0], [123, 0, 255], [45, 0, 54]],
    [[0, 0, 0], [100, 0, 100], [45, 0, 54]],
])

I'm trying to find index locations of a pattern like:

pattern = np.array([
    [[123, 0, 255], [*, *, *]],
    [[*, *, *], [45, 0, 54],
])

So in this example, I'm trying to find the coordinates of [0, 1] and [1, 1]. I can do this with simple nested list iteration, but I'm trying to do this as quickly as possible and hoping there's some numpy method that will let me do this efficiently.

What's the fastest way to accomplish this?

Bonus points if the answer also allows me to specify value ranges, so instead of looking for the exact values of [123, 0, 255], I can look for [120-125, 0, 255].

EDIT

To clarify, here's a working example. I'm looking for some faster method.

mat = np.array([
    [[0, 0, 0], [123, 0, 255], [0, 0, 0]],
    [[0, 0, 0], [123, 0, 255], [45, 0, 54]],
    [[0, 0, 0], [100, 0, 100], [45, 0, 54]],
])
# Look for any any 2x2 sub-matrix such that the upper left pixel is [123, 0, 255]
# and the lower right pixel is [45, 0, 54].
pixels_to_match = [
    (0, 0, [123, 0, 255]),
    (1, 1, [45, 0, 54]),
]

results = []
for row_ix, row in enumerate(mat):
    for col_ix, col in enumerate(row):
        view = mat[row_ix:row_ix 2, col_ix:col_ix 2]
        found = True
        for vals in pixels_to_match:
            if not (view[vals[0], vals[1]] == vals[2]).all():
                found = False
                break
        if found:
            results.append((row_ix, col_ix))

print(results)

CodePudding user response:

How about this:

from scipy.signal import correlate2d
import numpy as np

mat = np.array([
    [[0, 0, 0], [123, 0, 255], [0, 0, 0]],
    [[45, 0, 54], [124, 0, 255], [45, 0, 54]],
    [[127, 0, 255], [45, 0, 54], [45, 0, 54]],
])

# Find all of the places in the matrix where each condition is satisfied.
cond_1 = np.all(mat >= [120, 0, 255], axis=-1)
cond_1 &= np.all(mat <= [125, 0, 255], axis=-1)
cond_2 = np.all(mat == [45, 0, 54], axis=-1)

# Mark where in the submatrix we want each condition to apply to.
cond_1_map = np.array([[1, 0], [0, 0]])
cond_2_map = np.array([[0, 0], [0, 1]])

# Determine if each condition is in the correct location in the search matrix
matches_1 = correlate2d(cond_1, cond_1_map, mode='same')
matches_2 = correlate2d(cond_2, cond_2_map, mode='same')
matches = matches_1 & matches_2

print("mat:\n", mat)
print("cond_1:\n", cond_1)
print("cond_2:\n", cond_2)
print("matches_1:\n", matches_1)
print("matches_2:\n", matches_2)
print("matches:\n", matches)

First reduce the input array into binary array based on our conditions. Then for each condition we associate a separate submatrix to represent its proper location in a submatrix.

We can use correlate2d to test that the conditions are in the correct submatrix locations for each index in the original matrix.

Once we have matches for each condition, we can "and" the different matches together to get out final value.

mat:
 [[[  0   0   0]
  [123   0 255]
  [  0   0   0]]

 [[ 45   0  54]
  [124   0 255]
  [ 45   0  54]]

 [[127   0 255]
  [ 45   0  54]
  [ 45   0  54]]]
cond_1:
 [[False  True False]
 [False  True False]
 [False False False]]
cond_2:
 [[False False False]
 [ True False  True]
 [False  True  True]]
matches_1:
 [[0 1 0]
 [0 1 0]
 [0 0 0]]
matches_2:
 [[0 1 0]
 [1 1 0]
 [0 0 0]]
matches:
 [[0 1 0]
 [0 1 0]
 [0 0 0]]
  • Related