2017-03-13 12 views
1

저는 파이썬에서 sobel 연산자를 구현하고 시각화하려고합니다. 그러나, 나는 그것을하는 방법에 고투하고있다. 현재 각 픽셀에 대한 그래디언트를 계산하는 다음 코드가 있습니다.파이썬에서 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

시도의 정규화 값의 최대 및 최소값을 이용하여 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()