2015-01-14 3 views
3

Я пытаюсь использовать код, который я нашел для реализации локальной настройки контраста LeCun, но получаю неверный результат. Код находится в Python и использует библиотеку theano.Реализация локальной настройки контраста LeCun с помощью Theano

def lecun_lcn(input, img_shape, kernel_shape, threshold=1e-4): 
    """ 
    Yann LeCun's local contrast normalization 
    Orginal code in Theano by: Guillaume Desjardins 
    """ 
    input = input.reshape(input.shape[0], 1, img_shape[0], img_shape[1]) 
    X = T.matrix(dtype=theano.config.floatX) 
    X = X.reshape(input.shape) 

    filter_shape = (1, 1, kernel_shape, kernel_shape) 
    filters = gaussian_filter(kernel_shape).reshape(filter_shape) 

    convout = conv.conv2d(input=X, 
          filters=filters, 
          image_shape=(input.shape[0], 1, img_shape[0], img_shape[1]), 
          filter_shape=filter_shape, 
          border_mode='full') 

    # For each pixel, remove mean of 9x9 neighborhood 

    mid = int(np.floor(kernel_shape/2.)) 
    centered_X = X - convout[:, :, mid:-mid, mid:-mid] 
    # Scale down norm of 9x9 patch if norm is bigger than 1 
    sum_sqr_XX = conv.conv2d(input=centered_X ** 2, 
          filters=filters, 
          image_shape=(input.shape[0], 1, img_shape[0], img_shape[1]), 
          filter_shape=filter_shape, 
          border_mode='full') 

    denom = T.sqrt(sum_sqr_XX[:, :, mid:-mid, mid:-mid]) 
    per_img_mean = denom.mean(axis=[1, 2]) 
    divisor = T.largest(per_img_mean.dimshuffle(0, 'x', 'x', 1), denom) 
    divisor = T.maximum(divisor, threshold) 

    new_X = centered_X/divisor 
    new_X = new_X.dimshuffle(0, 2, 3, 1) 
    new_X = new_X.flatten(ndim=3) 

    f = theano.function([X], new_X) 
    return f(input) 

Вот код тестирования:

x_img_origin = plt.imread("..//data//Lenna.png") 
x_img = plt.imread("..//data//Lenna.png") 
x_img_real_result = plt.imread("..//data//Lenna_Processed.png") 

x_img = x_img.reshape(1, x_img.shape[0], x_img.shape[1], x_img.shape[2]) 
for d in range(3): 
    x_img[:, :, :, d] = tools.lecun_lcn(x_img[:, :, :, d], (x_img.shape[1], x_img.shape[2]), 9) 
x_img = x_img[0] 

pylab.subplot(1, 3, 1); pylab.axis('off'); pylab.imshow(x_img_origin) 
pylab.gray() 
pylab.subplot(1, 3, 2); pylab.axis('off'); pylab.imshow(x_img) 
pylab.subplot(1, 3, 3); pylab.axis('off'); pylab.imshow(x_img_real_result) 
pylab.show() 

Вот результат:

Example image processing results

(слева направо: происхождение, мой результат, ожидаемый результат)

Может ли кто-либо связаться Что я сделал с кодом?

+0

я сделал нечто подобное один раз, но, к сожалению, не может запустить свой код, потому что это не самодостаточным. Не могли бы вы сделать его работоспособным и, следовательно, отлаживаемым? Помимо прочего, вам нужно указать, какую функцию фильтра Гаусса вы используете. – eickenberg

+0

Hi eickenberg, Укажите код, который вы хотите изменить при необходимости. http://pastebin.com/x6WREp7D Вот изображение: http://upload.wikimedia.org/wikipedia/en/2/24/Lenna.png Позвольте мне знать, если вам нужно что-нибудь еще. Я думаю, что порог является виновником. Если я увеличу порог, он будет больше похож на ожидаемый результат. –

ответ

1

Я думаю, что эти две строки могут иметь некоторые ошибки на матрицу осей:

per_img_mean = denom.mean(axis=[1, 2]) 
divisor = T.largest(per_img_mean.dimshuffle(0, 'x', 'x', 1), denom) 

и его следует переписать в виде:

per_img_mean = denom.mean(axis=[2, 3]) 
divisor = T.largest(per_img_mean.dimshuffle(0, 1, 'x', 'x'), denom) 
6

Вот как я реализовал локальный контраст нормализации, как сообщалось в Jarrett и др. (http://yann.lecun.com/exdb/publis/pdf/jarrett-iccv-09.pdf). Вы можете использовать его как отдельный слой.

Я проверил его по коду из учебника LeNet по анатону, в котором я применил LCN к входу и каждому сверточному слою, что дает несколько лучшие результаты.

Вы можете найти полный код здесь: https://github.com/jostosh/theano_utils/blob/master/lcn.py

class LecunLCN(object): 
def __init__(self, X, image_shape, threshold=1e-4, radius=9, use_divisor=True): 
    """ 
    Allocate an LCN. 

    :type X: theano.tensor.dtensor4 
    :param X: symbolic image tensor, of shape image_shape 

    :type image_shape: tuple or list of length 4 
    :param image_shape: (batch size, num input feature maps, 
         image height, image width) 
    :type threshold: double 
    :param threshold: the threshold will be used to avoid division by zeros 

    :type radius: int 
    :param radius: determines size of Gaussian filter patch (default 9x9) 

    :type use_divisor: Boolean 
    :param use_divisor: whether or not to apply divisive normalization 
    """ 

    # Get Gaussian filter 
    filter_shape = (1, image_shape[1], radius, radius) 

    self.filters = theano.shared(self.gaussian_filter(filter_shape), borrow=True) 

    # Compute the Guassian weighted average by means of convolution 
    convout = conv.conv2d(
     input=X, 
     filters=self.filters, 
     image_shape=image_shape, 
     filter_shape=filter_shape, 
     border_mode='full' 
    ) 

    # Subtractive step 
    mid = int(numpy.floor(filter_shape[2]/2.)) 

    # Make filter dimension broadcastable and subtract 
    centered_X = X - T.addbroadcast(convout[:, :, mid:-mid, mid:-mid], 1) 

    # Boolean marks whether or not to perform divisive step 
    if use_divisor: 
     # Note that the local variances can be computed by using the centered_X 
     # tensor. If we convolve this with the mean filter, that should give us 
     # the variance at each point. We simply take the square root to get our 
     # denominator 

     # Compute variances 
     sum_sqr_XX = conv.conv2d(
      input=T.sqr(centered_X), 
      filters=self.filters, 
      image_shape=image_shape, 
      filter_shape=filter_shape, 
      border_mode='full' 
     ) 


     # Take square root to get local standard deviation 
     denom = T.sqrt(sum_sqr_XX[:,:,mid:-mid,mid:-mid]) 

     per_img_mean = denom.mean(axis=[2,3]) 
     divisor = T.largest(per_img_mean.dimshuffle(0, 1, 'x', 'x'), denom) 
     # Divisise step 
     new_X = centered_X/T.maximum(T.addbroadcast(divisor, 1), threshold) 
    else: 
     new_X = centered_X 

    self.output = new_X 


def gaussian_filter(self, kernel_shape): 
    x = numpy.zeros(kernel_shape, dtype=theano.config.floatX) 

    def gauss(x, y, sigma=2.0): 
     Z = 2 * numpy.pi * sigma ** 2 
     return 1./Z * numpy.exp(-(x ** 2 + y ** 2)/(2. * sigma ** 2)) 

    mid = numpy.floor(kernel_shape[-1]/2.) 
    for kernel_idx in xrange(0, kernel_shape[1]): 
     for i in xrange(0, kernel_shape[2]): 
      for j in xrange(0, kernel_shape[3]): 
       x[0, kernel_idx, i, j] = gauss(i - mid, j - mid) 

    return x/numpy.sum(x) 
+0

Было бы здорово, если бы вы также добавили пример того, как вызвать функцию. Я очень новичок в этих методах, и результатом, который я получаю от вызова LecunLCN, является 'Elemwise {true_div, no_inplace} .0', и я не знаю, правильно ли это и как извлечь из него изображение. –

+0

Для таких, как я, которые ничего не знают о анано, вывод функции - это объект, который еще предстоит скомпилировать, оценив объект. Следовательно, если вы хотите извлечь свернутое изображение, вам нужно написать 'LecunLCN (X) .output.eval() [0] [0]' –