2013-02-08 3 views
14

Ich wollte versuchen, eine einfache Funktion zu schreiben, um ein eingegebenes Bild zu glätten. Ich habe versucht, dies mit den Image- und Numpy-Bibliotheken zu tun. Ich dachte, dass die Verwendung einer Faltungs-Maske ein Ansatz für dieses Problem wäre und ich weiß, dass numpy eine Convolve-Funktion eingebaut hat.Bildglättung in Python

Wie kann ich die numpy.convolve verwenden, um ein Bild zu glätten?

+2

Sie müssen wahrscheinlich ein 2d convolve, z.B. 'scipy.signal.convolve2d' – wim

Antwort

16

Nette Frage! tcaswell post hier ist ein großartiger Vorschlag, aber Sie werden nicht viel lernen, weil scipy die ganze Arbeit für Sie erledigt! Da Ihre Frage sagte, Sie wollten versuchen und schreiben Sie die Funktion, werde ich Ihnen ein bisschen mehr grobe und grundlegende Art und Weise, um alles manuell in der Hoffnung, dass Sie besser verstehen, die Mathematik hinter Faltung usw., und dann Sie kann es mit deinen eigenen Ideen und Bemühungen verbessern!

Hinweis: Sie erhalten unterschiedliche Ergebnisse mit verschiedenen Formen/Größen von Kernen, ein Gaussian ist der übliche Weg, aber Sie können einige andere zum Spaß ausprobieren (Kosinus, Dreieck, etc!). Ich habe das sofort erfunden, ich denke, es ist eine Art Pyramidenform.

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

im = plt.imread('example.jpg') 
im /= 255. # normalise to 0-1, it's 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

+0

Weißt du, ob es wirklich einen Unterschied zwischen' scipy.signals.convolve2d' und 'scipy.ndimage.convolve' gibt, da beide scheinbar dasselbe mit nur leicht unterschiedlichen Argumenten machen. – tacaswell

+0

Ich denke, dass letzteres zu höheren Dimensionen verallgemeinert wird, ersteres wird zu 2d-Arrays spezifiziert. Normalerweise möchten Sie die Farbkanäle jedoch nicht miteinander verschmieren, daher wäre es komisch, einen 3D-Kernel für ein Bild zu verwenden. – wim

+0

Entschuldigung, blöde Frage, nachdem ich in meiner Antwort kommentiert habe, dass "Convolve" zu höheren Dimensionen geht ..... denke, es ist Zeit, ins Bett zu gehen. – tacaswell

16

Sie möchten ndimage ansehen, das ist ein Modul in scipy. Es hat eine Reihe von Filtern alle als Funktionen eingerichtet, und nette Wrapper zum Falten beliebiger Kernel.

Zum Beispiel

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

faltet Ihr Bild mit einem Gauß- mit Sigma von 2.

Wenn Sie einen beliebigen Kernel convolve wollen, sagen Sie ein Kreuz

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

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

Diese Funktionen eignen sich auch für höhere Dimensionen, sodass Sie fast identischen Code verwenden können (indem Sie einfach die Dimension Ihres Kernels vergrößern), um Daten in höheren Dimensionen zu glätten. Die Parameter mode und cval steuern, wie die Faltungen mit Pixeln am Rand Ihres Bildes umgehen (für einen Pixel am Rand existiert die Hälfte des Bereichs, den der Kernel sehen muss, nicht, also müssen Sie wählen.) etwas, mit dem du dein Bild auffüllen kannst.

4

Wenn Sie nicht scipy verwenden möchten, haben Sie drei Möglichkeiten:

1) Sie Faltungstheorem mit Fourier kombiniert verwenden können, verwandelt sich seit numpy eine 2D-FFT hat.

2) Sie können einen separablen Kernel verwenden und dann können Sie zwei 1D-Faltungen auf abgeflachten Arrays machen, eins in x-Richtung und das andere in y-Richtung (ravel die Transponierte), und das ergibt dasselbe Ergebnis als 2D-Faltung.

3) Wenn Sie einen kleinen Kernel haben, sagen wir 3x3, ist es einfach genug, die Faltung als Multiplikationen und Summen auszugeben. Das klingt nach einem Streit, aber es ist nicht so schlimm.

Wenn Sie scipy verwenden möchten, können Sie ngimage verwenden, wie tcaswell vorschlägt. scipy hat auch convolve2d.