2016-08-19 3 views
2

Учитывая 8-битное изображение в серой шкале (2D-массив со значениями от 0 до 255 для интенсивности пикселей), я хочу реализовать операторы Sobel (маска) на изображении. Функция Собела ниже в основном петли вокруг данного пикселя, применяется следующий вес к пикселям: enter image description herepython - реализация операторов Sobel с python без opencv

enter image description here

А потом aplies данной формулы:

enter image description here

Im пытается реализовать формулы по этой ссылке: http://homepages.inf.ed.ac.uk/rbf/HIPR2/sobel.htm

import numpy as np 
import matplotlib.pyplot as plt 
import matplotlib.image as mpimg 
import Image 


def Sobel(arr,rstart, cstart,masksize, divisor): 
    sum = 0; 
    x = 0 
    y = 0 

    for i in range(rstart, rstart+masksize, 1): 
    x = 0 
    for j in range(cstart, cstart+masksize, 1): 
     if x == 0 and y == 0: 
      p1 = arr[i][j] 
     if x == 0 and y == 1: 
      p2 = arr[i][j] 
     if x == 0 and y == 2: 
      p3 = arr[i][j] 
     if x == 1 and y == 0: 
      p4 = arr[i][j] 
     if x == 1 and y == 1: 
      p5 = arr[i][j]   
     if x == 1 and y == 2: 
      p6 = arr[i][j] 
     if x == 2 and y == 0: 
      p7 = arr[i][j] 
     if x == 2 and y == 1: 
      p8 = arr[i][j] 
     if x == 2 and y == 2: 
      p9 = arr[i][j] 
     x +=1 
    y +=1 
    return np.abs((p1 + 2*p2 + p3) - (p7 + 2*p8+p9)) + np.abs((p3 + 2*p6 + p9) - (p1 + 2*p4 +p7)) 


def padwithzeros(vector, pad_width, iaxis, kwargs): 
    vector[:pad_width[0]] = 0 
    vector[-pad_width[1]:] = 0 
    return vector 

im = Image.open('charlie.jpg') 
im.show() 
img = np.asarray(im) 
img.flags.writeable = True 
p = 1 
k = 2 
m = img.shape[0] 
n = img.shape[1] 
masksize = 3 
img = np.lib.pad(img, p, padwithzeros) #this function padds image with zeros to cater for pixels on the border. 
x = 0 
y = 0 
for row in img: 
    y = 0 
    for col in row: 
    if not (x < p or y < p or y > (n-k) or x > (m-k)): 
     img[x][y] = Sobel(img, x-p,y-p,masksize,masksize*masksize) 
    y = y + 1 
    x = x + 1 

img2 = Image.fromarray(img) 
img2.show() 

Учитывая это оттенки серого 8 бит изображения

enter image description here

я получаю это при применении функции:

enter image description here

но должны получить это:

enter image description here

I внедрили другие гау ssian фильтры с python, я не уверен, где я ошибаюсь?

ответ

1

Придерживаясь близко к тому, что делает ваш код, один элегантное решение заключается в использовании scipy.ndimage.filters.generic_filter() с формулой, представленной выше.

import numpy as np 
from scipy.ndimage.filters import generic_filter 
from scipy.ndimage import imread 

# Load sample data 
with np.DataSource().open("http://i.stack.imgur.com/8zINU.gif", "rb") as f: 
    img = imread(f, mode="I") 

# Apply the Sobel operator 
def sobel_filter(P): 
    return (np.abs((P[0] + 2 * P[1] + P[2]) - (P[6] + 2 * P[7] + P[8])) + 
      np.abs((P[2] + 2 * P[6] + P[7]) - (P[0] + 2 * P[3] + P[6]))) 
G = generic_filter(img, sobel_filter, (3, 3)) 

Выполнение этого на образце составляет около 400 мс. Для сравнения, производительность convolve2d составляет около 6,5 мс.

0

Если вы используете NumPy ans SciPy, это не проблема, тогда простое решение - использовать SciPy's convolve2d().

import numpy as np 
from scipy.signal import convolve2d 
from scipy.ndimage import imread 

# Load sample data 
with np.DataSource().open("http://i.stack.imgur.com/8zINU.gif", "rb") as f: 
    img = imread(f, mode="I") 

# Prepare the kernels 
a1 = np.matrix([1, 2, 1]) 
a2 = np.matrix([-1, 0, 1]) 
Kx = a1.T * a2 
Ky = a2.T * a1 

# Apply the Sobel operator 
Gx = convolve2d(img, Kx, "same", "symm") 
Gy = convolve2d(img, Ky, "same", "symm") 
G = np.sqrt(Gx**2 + Gy**2) 
# or using the absolute values 
G = np.abs(Gx) + np.abs(Gy)