python - Implementing Sobel operators with python without opencv
Question: Given a greyscale 8 bit image (2D array with values from 0 - 255 for pixel
intensity), I want to implement the Sobel operators (mask) on an image. The
Sobel function below basically loops around a given pixel,applies the
following weight to the pixels: [![enter image description
here](http://i.stack.imgur.com/1N67K.png)](http://i.stack.imgur.com/1N67K.png)

[![enter image description
here](http://i.stack.imgur.com/Ut0Aq.png)](http://i.stack.imgur.com/Ut0Aq.png)

And then aplies the given formula:

[![enter image description
here](http://i.stack.imgur.com/aBBUL.png)](http://i.stack.imgur.com/aBBUL.png)

Im trying to implement the formulas from this link:
<http://homepages.inf.ed.ac.uk/rbf/HIPR2/sobel.htm>

    
    
    import numpy as np
    import matplotlib.pyplot as plt
    import matplotlib.image as mpimg
    import Image
    
    
    def Sobel(arr,rstart, cstart,masksize, divisor):
      sum = 0;
      x = 0
      y = 0
    
      for i in range(rstart, rstart+masksize, 1):
        x = 0
        for j in range(cstart, cstart+masksize, 1):
            if x == 0 and y == 0:
                p1 = arr[i][j]
            if x == 0 and y == 1:
                p2 = arr[i][j]
            if x == 0 and y == 2:
                p3 = arr[i][j]
            if x == 1 and y == 0:
                p4 = arr[i][j]
            if x == 1 and y == 1:
                p5 = arr[i][j]           
            if x == 1 and y == 2:
                p6 = arr[i][j]
            if x == 2 and y == 0:
                p7 = arr[i][j]
            if x == 2 and y == 1:
                p8 = arr[i][j]
            if x == 2 and y == 2:
                p9 = arr[i][j]
            x +=1
        y +=1
      return np.abs((p1 + 2*p2 + p3) - (p7 + 2*p8+p9)) + np.abs((p3 + 2*p6 + p9) - (p1 + 2*p4 +p7)) 
    
    
    def padwithzeros(vector, pad_width, iaxis, kwargs):
       vector[:pad_width[0]] = 0
       vector[-pad_width[1]:] = 0
       return vector
    
    im = Image.open('charlie.jpg')
    im.show()
    img = np.asarray(im)
    img.flags.writeable = True
    p = 1
    k = 2
    m = img.shape[0]
    n = img.shape[1]
    masksize = 3
    img = np.lib.pad(img, p, padwithzeros) #this function padds image with zeros to cater for pixels on the border.
    x = 0
    y = 0
    for row in img:
      y = 0
      for col in row:
        if not (x < p or y < p or y > (n-k) or x > (m-k)):
            img[x][y] = Sobel(img, x-p,y-p,masksize,masksize*masksize)
        y = y + 1
      x = x + 1
    
    img2 = Image.fromarray(img)
    img2.show()
    

Given this greyscale 8 bit image

[![enter image description
here](http://i.stack.imgur.com/8zINU.gif)](http://i.stack.imgur.com/8zINU.gif)

I get this when applying the function:

[![enter image description
here](http://i.stack.imgur.com/MPM6y.png)](http://i.stack.imgur.com/MPM6y.png)

but should get this:

[![enter image description
here](http://i.stack.imgur.com/ECAIK.gif)](http://i.stack.imgur.com/ECAIK.gif)

I have implemented other gaussian filters with python, I'm not sure where I'm
going wrong here?


Answer: Sticking close to what your code is doing, one elegant solution is to use the
[`scipy.ndimage.filters.generic_filter()`](http://docs.scipy.org/doc/scipy-0.16.1/reference/generated/scipy.ndimage.filters.generic_filter.html)
with the formula provided above.

    
    
    import numpy as np
    from scipy.ndimage.filters import generic_filter
    from scipy.ndimage import imread
    
    # Load sample data
    with np.DataSource().open("http://i.stack.imgur.com/8zINU.gif", "rb") as f:
        img = imread(f, mode="I")
    
    # Apply the Sobel operator
    def sobel_filter(P):
        return (np.abs((P[0] + 2 * P[1] + P[2]) - (P[6] + 2 * P[7] + P[8])) +
                np.abs((P[2] + 2 * P[6] + P[7]) - (P[0] + 2 * P[3] + P[6])))
    G = generic_filter(img, sobel_filter, (3, 3))
    

Running this on the sample image takes about 400 ms. For comparison, the
`convolve2d`'s performance is about 6.5 ms.

