5

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

enter image description here

And then aplies the given formula:

enter image description here

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

I get this when applying the function:

enter image description here

but should get this:

enter image description here

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

2
  • 1
    There are (at least) two bugs in the code: (2) You cannot do this filter in-place. You overwrite a value in the input matrix, and for the next pixel you read this new value instead of the original one. You must have a separate output array. (2) The equation is likely to produce values that don’t fit in the 8-bit range, when assigning the value into the array, larger values wrap around. You might want to clip or scale the values before writing them into the output array. Commented Aug 31, 2024 at 19:59
  • here too I should point out that I've been grave-digging in the [vision] tag and this question is 8 years old Commented Aug 31, 2024 at 23:10

3 Answers 3

4

Sticking close to what your code is doing, one elegant solution is to use the scipy.ndimage.filters.generic_filter() 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("https://i.sstatic.net/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.

Sign up to request clarification or add additional context in comments.

Comments

3

If using NumPy ans SciPy is not a problem, then a simple solution is to use the SciPy's convolve2d().

import numpy as np
from scipy.signal import convolve2d
from scipy.ndimage import imread

# Load sample data
with np.DataSource().open("https://i.sstatic.net/8zINU.gif", "rb") as f:
    img = imread(f, mode="I")

# Prepare the kernels
a1 = np.matrix([1, 2, 1])
a2 = np.matrix([-1, 0, 1])
Kx = a1.T * a2
Ky = a2.T * a1

# Apply the Sobel operator
Gx = convolve2d(img, Kx, "same", "symm")
Gy = convolve2d(img, Ky, "same", "symm")
G = np.sqrt(Gx**2 + Gy**2)
# or using the absolute values
G = np.abs(Gx) + np.abs(Gy)

Comments

0

I met the same problem as you. I fix it by reading the image of format 'gray', you could see below

import PIL.Image
img = PIL.Image.open('image.gif').convert('L')

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.