1

I would like to create a large, weighted adjacency matrix from an image (so lots of vertices... in the order of > 10^5 vertices) in python. Weights between adjacent pixels are color gradients (I take care of this). Doing it by iterating through pixels is very slow... it takes over 4 minutes. :-( Are there any libraries that can do this nicely in reasonable time?

The following is my code which runs very slowly:

def indToCoord(ind, w, h):
    x = ind % w
    y = (ind - x)/h
    return (x,y)

def isAdj(p1, p2, im):
    adj = []
    w, h = im.size
    x1, y1 = p1
    x2, y2 = p2
    if (x1, y1) == (x2, y2):
        return 0
    elif abs(x1 - x2) > 1:
        return 0
    elif abs(y1 - y2) > 1:
        return 0
    elif abs(x1 - x2) + abs(y1 - y2) >= 2:
        return 0

    return util.colorGradient(im, p1, p2)

def adjForPixel(pixels, p1, im):
    return [isAdj(p1,p2,im) for p2 in pixels]

# The following is the function I use to create an Adjacency Matrix from an image
def getAdjMatrix(im):
    width, height = im.size 
    pixels = [(x,y) for x in xrange(width) for y in xrange(height)]

    pixelAdjMatr = [adjForPixel(pixels, p, im) for p in pixels]
    return pixelAdjMatr

adj_matrix = getAdjMatrix(im)

Thank you!

nargles324
  • 613
  • 1
  • 6
  • 10
  • Please post your current code (iteration) along with a sample of your output – Bob Haffner Dec 21 '14 at 04:33
  • A pixel can have 2, 3, or 4 adjacent pixels and each pixel has a color gradient value for each of its *neighbors*? Is the color gradient value for ```p1,p2``` different than ```p2,p1```? – wwii Dec 21 '14 at 07:59
  • That's right, they can have 2, 3, or 4 adjacent pixels. The color gradient value for p1, p2 is not different than p2, p1, although computing color gradient is not so computationally expensive. – nargles324 Dec 21 '14 at 19:07
  • Your implementation is very inefficient. When you do "[isAdj(p1,p2,im) for p2 in pixels]", you are iterating over every pixel in the image and checking if it's adjacent to p1. But you don't need to do this - there are at most 4 pixels that are adjacent to p1, and you can easily create the list of them directly. I would guess that if you did that, your routine would run in a reasonable time without needing to use an external library. – N. Virgo Jan 09 '16 at 04:59

2 Answers2

1

img_to_graph will do the trick. This creates a so-called "connectivity matrix". The adjacency matrix is such a ubiquitous and important term that sklearn's departure here is not awesome.

But this function will do the trick. I found that networkx's function, cited above, was only useful for graphs. In order to convert an image to a networkx graph from a numpy array, you are pretty much reduced to interpreted for loop writing. This is because the networkx library does provide an optimized numpy->graph function, but that function assumes the numpy array is already an adjacency matrix.

This is a compiled -O3 --simd --omp only loop scenario for any reasonably sized images, and may even benefit from some cache optimization strategies (ruling out python3's numba Just-In-Time compiler).

That makes the networkx answer another problem. I'd go ahead and use the sklearn function there:

sklearn.feature_extraction.image.img_to_graph(your_img)  
# returns scipy.sparse.coo.coo_matrix
Chris
  • 28,822
  • 27
  • 83
  • 158
0

Python module/library NetworkX has an adjacency matrix implementation. It returns a scipy matrix

https://networkx.github.io/documentation/latest/reference/generated/networkx.linalg.graphmatrix.adjacency_matrix.html

import networkx as nx
import scipy as sp
g = nx.Graph([(1,1)])
a = nx.adjacency_matrix(g)
print a, type(a)

returns

(0, 0)  1 <class 'scipy.sparse.csr.csr_matrix'>
Bob Haffner
  • 8,235
  • 1
  • 36
  • 43