Here is some partially-hardcoded easy-to-understand-approach.
- Edit: faster version due to preprocessing
- Edit 2: one more final speedup (symmetry-reduction in preprocessing)
- Edit 3: okay; added one more symmetry-reduction step in preprocessing
Approach
- get a block-view by skimage
- preprocess the neighborhood-logic once:
- create a list of all indices to look up pairs (which are connected) in the given window
- some symmetry-reduction used
- iterate all blocks; grab pairs
- add if some symmetry-constraint is true
Code
import numpy as np
from skimage.util.shape import view_as_blocks, view_as_windows
img = np.array([[1,1,2,2,3,3,3],
[1,1,1,1,2,4,4],
[1,1,2,2,5,5,5]])
#img = np.random.random_integers(1, 10, size=(256,256))
WINDOW_SIZE = 3
img_windowed = view_as_windows(img, window_shape=(WINDOW_SIZE,WINDOW_SIZE)) # overlapping
# Preprocessing: generate valid index_pairs
index_pairs = []
for x in range(WINDOW_SIZE):
for y in range(WINDOW_SIZE):
if y>=x: # remove symmetries
if x>0:
index_pairs.append(((x,y), (x-1,y)))
if x<2:
index_pairs.append(((x,y), (x+1,y)))
if y>0:
index_pairs.append(((x,y), (x,y-1)))
if y<2:
index_pairs.append(((x,y), (x,y+1)))
if x>0 and y>0:
index_pairs.append(((x,y), (x-1,y-1)))
if x<2 and y<2:
index_pairs.append(((x,y), (x+1,y+1)))
if x>0 and y<2:
index_pairs.append(((x,y), (x-1,y+1)))
if x<2 and y>0:
index_pairs.append(((x,y), (x+1,y-1)))
index_pairs = list(filter(lambda x: x[0] < x[1], index_pairs)) # remove symmetries
pairs = []
def reason_pair(a,b): # remove symmetries
if a<b:
pairs.append((a,b))
elif a>b:
pairs.append((b,a))
for a in range(img_windowed.shape[0]):
for b in range(img_windowed.shape[1]):
block = img_windowed[a,b]
for i in index_pairs:
reason_pair(block[i[0]], block[i[1]])
print(set(pairs))
Output
set([(1, 2), (1, 3), (4, 5), (1, 5), (2, 3), (2, 5), (3, 4), (2, 4)])