2017-03-13 61 views
1

我正試圖在Python中實現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等

所以我想要做的是可視化該漸變,但我不知道如何。網上的大多數資源只提到計算梯度角度和大小,而不是如何在圖像中表示它。

+1

嘗試正火到0-255使用的最大和最小值的值梯度幅度圖像,即'displayableGradMagnitude = 255 *(gradMagnitude-minGradMagnitude)/(maxGradMagnitude-minGradMagnitude)'。 – saurabheights

+0

謝謝你,完美的工作。也許發佈作爲答案,所以我可以給你你的信用 – fbailey

+0

還要注意,Solbel卷積內核是可分離的。你可以用[-1,0,1]應用卷積,然後用[1,2,1]的轉置對結果進行第二次卷積。這總是更高效,而且實施起來也更容易。這兩個操作的順序是無關緊要的。通過轉置兩個內核來計算y導數。 –

回答

1

使值進入特定範圍的最簡單方法是規範化。對於n個值,找到所有這些值的最小值和最大值。爲範圍[A,B],正常化每個值x作爲: -

X」 = A +(BA)*(X-分鐘)/(最大值 - 最小值)

爲OP的情況下,此方程梯度大小將是: -

X」 = 255 *(X-分鐘)/(最大值 - 最小值)

2

使用@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()