Search code examples
pythonimage-processingthresholdsobel

Visualizing sobel gradient in python


I'm trying to implement the sobel operator in Python and visualize it. However, I'm struggling with how to do that. I have the following code, which currently calculates the gradient for each pixel.

from PIL import Image
import math


def run():

    try:

        image = Image.open("brick-wall-color.jpg")
        image = image.convert('LA')

        apply_sobel_masks(image)

    except RuntimeError, e:
        print e


def apply_sobel_masks(image):

    gx = [
        [-1, 0, 1],
        [-2, 0, 2],
        [-1, 0, 1]
    ]

    gy = [
        [1, 2, 1],
        [0, 0, 0],
        [-1, -2, -1]
    ]

    width, height = image.size

    for y in range(0, height):

        for x in range(0, width):

            gradient_y = (
                gy[0][0] * get_pixel_safe(image, x - 1, y - 1, 0) +
                gy[0][1] * get_pixel_safe(image, x, y - 1, 0) +
                gy[0][2] * get_pixel_safe(image, x + 1, y - 1, 0) +
                gy[2][0] * get_pixel_safe(image, x - 1, y + 1, 0) +
                gy[2][1] * get_pixel_safe(image, x, y + 1, 0) +
                gy[2][2] * get_pixel_safe(image, x + 1, y + 1, 0)
            )

            gradient_x = (
                gx[0][0] * get_pixel_safe(image, x - 1, y - 1, 0) +
                gx[0][2] * get_pixel_safe(image, x + 1, y - 1, 0) +
                gx[1][0] * get_pixel_safe(image, x - 1, y, 0) +
                gx[1][2] * get_pixel_safe(image, x + 1, y, 0) +
                gx[2][0] * get_pixel_safe(image, x - 1, y - 1, 0) +
                gx[2][2] * get_pixel_safe(image, x + 1, y + 1, 0)
            )

            print "Gradient X: " + str(gradient_x) + " Gradient Y: " + str(gradient_y)
            gradient_magnitude = math.sqrt(pow(gradient_x, 2) + pow(gradient_y, 2))

            image.putpixel((x, y), #tbd)


    image.show()


def get_pixel_safe(image, x, y, layer):

    try:
        return image.getpixel((x, y))[layer]

    except IndexError, e:
        return 0


run()

Now the gradient_magnitude is often a value well outside of the 0-255 range e.g. 990.0, 1002.0, 778, etc.

So what I'd like to do is visualize that gradient, but I'm not sure how. Most resources online only mention calculating the gradient angle and magnitude but not how to represent it in an image.


Solution

  • The simplest way to bring values into a specific range is to normalize. For n values, find minimum and maximum of all these values. For range [a, b], normalize each value x as:-

    x' = a + (b-a) * (x-min)/(max-min)

    For OP's scenario, this equation for gradient magnitude will be:-

    x' = 255 * (x-min)/(max-min)