在 python 中可视化索贝尔梯度
Visualizing sobel gradient in python
我正在尝试在 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 等
所以我想做的是可视化该渐变,但我不确定如何。大多数在线资源只提到计算梯度角度和幅度,但没有提到如何在图像中表示它。
使用@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()
将值置于特定范围内的最简单方法是归一化。对于 n 个值,找出所有这些值中的最小值和最大值。对于范围 [a, b],将每个值 x 归一化为:-
x' = a + (b-a) * (x-min)/(max-min)
对于 OP 的场景,此梯度大小方程为:-
x' = 255 * (x-min)/(max-min)
我正在尝试在 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 等
所以我想做的是可视化该渐变,但我不确定如何。大多数在线资源只提到计算梯度角度和幅度,但没有提到如何在图像中表示它。
使用@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()
将值置于特定范围内的最简单方法是归一化。对于 n 个值,找出所有这些值中的最小值和最大值。对于范围 [a, b],将每个值 x 归一化为:-
x' = a + (b-a) * (x-min)/(max-min)
对于 OP 的场景,此梯度大小方程为:-
x' = 255 * (x-min)/(max-min)