Сглаживание изображений в Python

Я хотел попытаться написать простую функцию для сглаживания введенного изображения. Я пытался сделать это, используя библиотеки Image и numpy. Я думал, что использование маски свертки будет подходом к этой проблеме, и я знаю, что numpy имеет встроенную функцию convolve.

Как я могу использовать numpy.convolve, чтобы сгладить изображение?

Ответы

Ответ 1

Хороший вопрос! tcaswell сообщение здесь большое предложение, но вы не будете многому научиться, потому что Scipy делает всю работу за вас! Поскольку в вашем вопросе говорилось, что вы хотите попробовать написать эту функцию, я покажу вам немного более грубый и простой способ сделать все это вручную, надеясь, что вы лучше поймете математику за сверткой и т.д., А затем вы сможете улучшить это с вашими собственными идеями и усилиями!

Примечание. Вы получите разные результаты с разными формами/размерами ядер, гауссовский обычным способом, но вы можете попробовать некоторые другие для удовольствия (косинус, треугольник и т.д.!). Я просто сделал это на месте, я думаю, что это своего рода пирамида.

import scipy.signal
import numpy as np
import matplotlib.pyplot as plt

im = plt.imread('example.jpg')
im /= 255.   # normalise to 0-1, it easier to work in float space

# make some kind of kernel, there are many ways to do this...
t = 1 - np.abs(np.linspace(-1, 1, 21))
kernel = t.reshape(21, 1) * t.reshape(1, 21)
kernel /= kernel.sum()   # kernel should sum to 1!  :) 

# convolve 2d the kernel with each channel
r = scipy.signal.convolve2d(im[:,:,0], kernel, mode='same')
g = scipy.signal.convolve2d(im[:,:,1], kernel, mode='same')
b = scipy.signal.convolve2d(im[:,:,2], kernel, mode='same')

# stack the channels back into a 8-bit colour depth image and plot it
im_out = np.dstack([r, g, b])
im_out = (im_out * 255).astype(np.uint8) 

plt.subplot(2,1,1)
plt.imshow(im)
plt.subplot(2,1,2)
plt.imshow(im_out)
plt.show()

enter image description here

Ответ 2

Вы хотите посмотреть ndimage, который является модулем в scipy. Он имеет ряд фильтров все они настроены как функции и хорошие обертки для свертки произвольных ядер.

Например,

img_gaus = ndimage.filters.gaussian_filter(img, 2, mode='nearest')

свертывает ваше изображение с гуасином с сигмой 2.

Если вы хотите свернуть произвольное ядро, скажем, крест

k = np.array([[0, 1, 0],
              [1, 1, 1],
              [0, 1, 0]])

img2 = ndimage.convolve(img, k, mode='constant')

Эти функции также хороши для более высоких измерений, поэтому вы можете использовать почти идентичный код (просто увеличивая размер вашего ядра), чтобы сгладить данные в более высоких измерениях.

Параметры mode и cval управляют тем, как свертки имеют дело с пикселями на краю вашего изображения (для пикселя на краю половина области, в которой нужно посмотреть, не существует, поэтому вы нужно выбрать что-то, чтобы скомпоновать ваш образ).

Ответ 3

Если вы не хотите использовать scipy, у вас есть три варианта:

1) вы можете использовать теорему свертки в сочетании с преобразованиями Фурье, поскольку numpy имеет двумерный БПФ.

2) вы можете использовать разделяемое ядро, а затем вы можете сделать две одномерные свертки на сплющенных массивах, одну в направлении x, а другую в направлении y (ravel transpose), и это даст тот же результат как двумерная свертка.

3), если у вас есть небольшое ядро, скажем, 3x3, достаточно просто написать свертку как умножения и суммы. Это звучит как хлопот, но это не так уж плохо.

Если вы хотите использовать scipy, вы можете использовать ngimage, как предлагает tcaswell. scipy также имеет convolve2d.