在python中可视化sobel梯度

时间:2017-03-13 20:19:51

标签: python image-processing threshold sobel

我试图用Python实现sobel运算符并将其可视化。但是,我正在努力解决这个问题。我有以下代码,目前计算每个像素的渐变。

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()

现在,gradient_magnitude通常是一个远远超出0-255范围的值,例如990.0,1002.0,778等

所以我想做的是想象这个渐变,但我不确定如何。大多数在线资源仅提及计算梯度角度和幅度,而不是如何在图像中表示它。

2 个答案:

答案 0 :(得分:3)

使用@saurabheights建议我能够可视化渐变的幅度。我还纠正的一个错误是,我在计算每个像素后计算其梯度。这是不正确的,因为当内核移动一个像素时,它现在使用刚编辑的像素的值。更正的代码发布在下面:

from PIL import Image, ImageFilter
import math


def run():

    try:

        image = Image.open("geo.jpg")
        image = image.convert('LA')
        image = image.filter(ImageFilter.GaussianBlur(radius=1))
        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
    gradient_magnitudes = [[0 for x in range(width)] for y in range(height)]
    gradient_max = None
    gradient_min = None

    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)
            )

            gradient_magnitude = math.ceil(math.sqrt(pow(gradient_x, 2) + pow(gradient_y, 2)))

            if gradient_max is None:
                gradient_max = gradient_magnitude
                gradient_min = gradient_magnitude

            if gradient_magnitude > gradient_max:
                gradient_max = gradient_magnitude

            if gradient_magnitude < gradient_min:
                gradient_min = gradient_magnitude

            gradient_magnitudes[y][x] = gradient_magnitude

    # Visualize the gradients
    for y in range(0, height):

        for x in range(0, width):

            gradient_magnitude = gradient_magnitudes[y][x]
            pixel_value = int(math.floor(255 * (gradient_magnitude - gradient_min) / (gradient_max - gradient_min)))

            image.putpixel((x, y), pixel_value)

    image.show()


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

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

    except IndexError, e:
        return 0


run()

答案 1 :(得分:2)

将值放入特定范围的最简单方法是规范化。对于n值,找到所有这些值的最小值和最大值。对于范围[a,b],将每个值x标准化为: -

  

X&#39; = a +(b-a)*(x-min)/(max-min)

对于OP的情景,梯度幅度的这个等式将是: -

  

X&#39; = 255 *(x-min)/(max-min)