[OpenCV-Python] 23 Transformation d'image

OpenCV-Python: Traitement d'image IV dans OpenCV

23 Transformation d'image

23.1 Transformée de Fourier

Objectifs Dans
cette section, nous allons apprendre:
  • Utiliser OpenCV pour transformer une image
  • Utiliser la fonction FFT (Fast Fourier Transform) dans Numpy
  • Quelques utilisations de la Transformée de Fourier
  • Les fonctions que nous allons apprendre sont: cv2.dft (), cv2 .idft () et autres
principes La
  transformée de Fourier est souvent utilisée pour analyser les caractéristiques de fréquence de différents filtres. Nous pouvons utiliser la transformée de Fourier discrète 2D (DFT) pour analyser les caractéristiques du domaine fréquentiel de l'image. Un algorithme rapide qui implémente DFT est appelé Fast Fourier Transform (FFT). Les connaissances détaillées sur la transformée de Fourier peuvent être trouvées dans n'importe quel livre sur le traitement d'image ou le traitement du signal. Consultez la section plus de ressources dans cette section.
Pour un signal sinusoïdal: x (t) = Asin (2πft), sa fréquence est f. Si ce signal est converti en sa représentation dans le domaine fréquentiel, nous verrons un pic de fréquence f. Si notre signal est composé de signaux discrets générés par échantillonnage, nous obtiendrons un spectrogramme similaire, sauf que le précédent était continu, et maintenant il est discret. Vous pouvez considérer une image comme un signal collecté dans deux directions. Par conséquent, en effectuant la transformée de Fourier des directions X et Y sur l'image en même temps, nous obtiendrons la représentation du domaine fréquentiel (spectrogramme) de cette image.
Pour être plus intuitif, pour un signal sinusoïdal, si son amplitude change très rapidement, on peut dire que c'est un signal haute fréquence, s'il change très lentement, on l'appelle un signal basse fréquence. Vous pouvez appliquer cette idée à une image, où l'amplitude de l'image change beaucoup? Points limites ou bruit. Nous disons donc que la frontière et le bruit sont les composantes haute fréquence de l'image (notez que la haute fréquence fait ici référence au changement très rapide, plutôt qu'au nombre d'occurrences). S'il n'y a pas de changement d'amplitude aussi important, nous l'appelons la composante basse fréquence.
Nous voyons maintenant comment effectuer la transformée de Fourier.

23.1.1 Transformée de Fourier dans Numpy

Voyons d'abord comment utiliser Numpy pour effectuer une transformation de Fourier. Le package FFT de Numpy peut nous aider à implémenter une transformation de Fourier rapide. La fonction np.fft.fft2 () peut effectuer une conversion de fréquence sur le signal, et le résultat de sortie est un tableau complexe. Le premier paramètre de cette fonction est l'image d'entrée, qui doit être au format en niveaux de gris. Le deuxième paramètre est facultatif et détermine la taille du tableau de sortie. La taille du tableau de sortie est la même que la taille de l'image d'entrée. Si le résultat de sortie est plus grand que l'image d'entrée, l'image d'entrée doit être remplie avec 0 avant la FFT. Si le résultat de sortie est plus petit que l'image d'entrée, l'image d'entrée sera coupée.

Nous avons maintenant le résultat, la partie avec une fréquence de 0 (composante CC) est dans le coin supérieur gauche de l'image de sortie. Si nous voulons qu'il (le composant DC) soit au centre de l'image de sortie, nous devons également traduire le résultat par -N / 2 dans les deux sens. La fonction np.fft.fftshift () peut nous aider à réaliser cette étape. (Cela facilite l'analyse).
Après avoir effectué la transformation de fréquence, nous pouvons construire le spectre d'amplitude.

import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('messi5.jpg',0)
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
# 这里构建振幅图的公式没学过
magnitude_spectrum = 20*np.log(np.abs(fshift))
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()

Les résultats sont les suivants:

Spectre de magnitude
Nous pouvons voir que la partie centrale de la sortie est plus blanche (plus brillante), ce qui signifie qu'il y a plus de composants basse fréquence.
Maintenant que nous pouvons effectuer une transformation du domaine fréquentiel, nous pouvons effectuer certaines opérations sur l'image dans le domaine fréquentiel, comme le filtrage passe-haut et la reconstruction de l'image (la transformée inverse de DFT). Par exemple, nous pouvons utiliser une fenêtre rectangulaire 60x60 pour masquer l'image afin de supprimer les composants basse fréquence. Ensuite, utilisez la fonction np.fft.ifftshift () pour effectuer l'opération de décalage inverse, donc maintenant le composant DC est de retour dans le coin supérieur gauche, et utilisez la fonction np.ifft2 () pour effectuer la transformation FFT inverse sur la gauche. Obtenez également un tas de nombres compliqués, nous pouvons en prendre la valeur absolue:

rows, cols = img.shape
crow,ccol = rows/2 , cols/2
fshift[crow-30:crow+30, ccol-30:ccol+30] = 0
f_ishift = np.fft.ifftshift(fshift)
img_back = np.fft.ifft2(f_ishift)
img_back = np.abs(img_back)

plt.subplot(131),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(132),plt.imshow(img_back, cmap = 'gray')
plt.title('Image after HPF'), plt.xticks([]), plt.yticks([])
plt.subplot(133),plt.imshow(img_back)
plt.title('Result in JET'), plt.xticks([]), plt.yticks([])

plt.show()

Les résultats sont les suivants:

Filtrage passe-haut

Le résultat de la figure ci-dessus montre que le filtrage passe-haut est en fait une opération de détection de limite. C'est ce que nous avons vu dans le chapitre précédent sur les dégradés d'image. Dans le même temps, nous avons également constaté que la plupart des données de l'image sont concentrées dans la région des basses fréquences du spectrogramme. Nous savons maintenant comment utiliser Numpy pour effectuer des DFT et IDFT, puis examinons comment utiliser OpenCV pour effectuer ces opérations.
Si vous observez attentivement, en particulier l'image couleur JET dans le dernier chapitre, vous verrez des choses non naturelles (comme la zone que j'ai marquée avec une flèche rouge). Regardez l'image ci-dessus où il y a des structures rayées, ce que l'on appelle l'effet de sonnerie. Cela est dû au fait que nous utilisons des fenêtres rectangulaires comme masques. Ce problème se produit lorsque le masque est converti en une forme sinusoïdale. Donc, généralement, nous n'appliquons pas de filtrage de fenêtre rectangulaire. Le meilleur choix est la fenêtre gaussienne.

23.1.2 Transformée de Fourier dans OpenCV

Les fonctions correspondantes dans OpenCV sont cv2.dft () et cv2.idft (). Le résultat est le même que la sortie précédente, mais il s'agit d'un double canal. Le premier canal est la partie réelle du résultat et le second canal est la partie imaginaire du résultat. L'image d'entrée doit d'abord être convertie au format np.float32. Voyons comment faire.

import numpy as np
import cv2
from matplotlib import pyplot as plt

img = cv2.imread('messi5.jpg',0)

dft = cv2.dft(np.float32(img),flags = cv2.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)

magnitude_spectrum = 20*np.log(cv2.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))

plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()

Remarque: vous pouvez utiliser la fonction cv2.cartToPolar (), qui retournera l'amplitude et la phase en même temps.
Maintenant, faisons DFT inverse. Dans la partie précédente, nous avons implémenté un HPF (filtre passe-haut), maintenant nous allons faire du LPF (filtre passe-bas) pour supprimer la partie haute fréquence. En fait, c'est pour brouiller l'image. Tout d'abord, nous devons construire un masque, définir le lieu correspondant à la zone basse fréquence à 1 et le lieu correspondant à la zone haute fréquence à 0.

rows, cols = img.shape
crow,ccol = rows/2 , cols/2

# create a mask first, center square is 1, remaining all zeros
mask = np.zeros((rows,cols,2),np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1

# apply mask and inverse DFT
fshift = dft_shift*mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv2.idft(f_ishift)
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])

plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()

Les résultats sont les suivants:

Spectre de magnitude

Remarque: les fonctions cv2.dft () et cv2.idft () dans OpenCV sont plus rapides que Numpy. Mais la fonction Numpy est plus conviviale. Pour une description des performances, veuillez consulter les chapitres suivants.

23.1.3 Optimisation des performances DFT

Les performances DFT seront meilleures lorsque la taille du tableau est une certaine valeur. DFT est plus efficace lorsque la taille du tableau est un exposant de 2. L'efficacité est également élevée lorsque la taille de la matrice est un multiple de 2, 3 ou 5. Donc, si vous souhaitez améliorer l'efficacité du code, vous pouvez modifier la taille de l'image d'entrée (complétée à 0). Pour OpenCV, vous devez remplir 0 manuellement. Mais avec Numpy, il vous suffit de spécifier la taille de l'opération FFT, et elle remplira automatiquement 0.
Comment déterminer la taille optimale? OpenCV fournit une fonction: cv2.getOptimalDFTSize ().
Il peut être utilisé à la fois par cv2.dft () et np.fft.fft2 () en même temps. Utilisons la commande magique% timeit d'IPython pour le tester.

In [16]: img = cv2.imread('messi5.jpg',0)
In [17]: rows,cols = img.shape
In [18]: print rows,cols
342 548

In [19]: nrows = cv2.getOptimalDFTSize(rows)
In [20]: ncols = cv2.getOptimalDFTSize(cols)
In [21]: print nrows, ncols
360 576

Comme vous pouvez le voir, la taille du tableau est passée de (342 548) à (360 576). Maintenant, nous le remplissons avec 0, puis voyons si les performances se sont améliorées. Vous pouvez créer un grand tableau 0 et copier nos données, ou utiliser la fonction cv2.copyMakeBoder ().

nimg = np.zeros((nrows,ncols))
nimg[:rows,:cols] = img

ou:

right = ncols - cols
bottom = nrows - rows
#just to avoid line breakup in PDF file
bordertype = cv2.BORDER_CONSTANT
nimg = cv2.copyMakeBorder(img,0,bottom,0,right,bordertype, value = 0)

Maintenant, nous regardons les performances de Numpy:

In [22]: %timeit fft1 = np.fft.fft2(img)
10 loops, best of 3: 40.9 ms per loop
In [23]: %timeit fft2 = np.fft.fft2(img,[nrows,ncols])
100 loops, best of 3: 10.4 ms per loop

La vitesse est multipliée par 4. Jetons un coup d'œil aux performances d'OpenCV:

In [24]: %timeit dft1= cv2.dft(np.float32(img),flags=cv2.DFT_COMPLEX_OUTPUT)
100 loops, best of 3: 13.5 ms per loop
In [27]: %timeit dft2= cv2.dft(np.float32(nimg),flags=cv2.DFT_COMPLEX_OUTPUT)
100 loops, best of 3: 3.11 ms per loop

Il a également été multiplié par 4, et nous verrons également qu'OpenCV est 3 fois plus rapide que Numpy.
Vous pouvez également tester les performances de la FFT inverse.

23.1.4 Pourquoi l'opérateur laplacien est-il un filtre passe-haut?

J'ai rencontré un problème similaire dans le forum. Pourquoi l'opérateur laplacien est-il un filtre passe-haut?
  Pourquoi Sobel est-il un HPF? et beaucoup plus. La réponse à la première question est donnée sous forme de transformée de Fourier. Réalisons ensemble une transformation de Fourier sur différents opérateurs et analysons-les:

import cv2
import numpy as np
from matplotlib import pyplot as plt
# simple averaging filter without scaling parameter
mean_filter = np.ones((3,3))
# creating a guassian filter
x = cv2.getGaussianKernel(5,10)
#x.T 为矩阵转置
gaussian = x*x.T
# different edge detecting filters
# scharr in x-direction
scharr = np.array([[-3, 0, 3],
[-10,0,10],
[-3, 0, 3]])
# sobel in x direction
sobel_x= np.array([[-1, 0, 1],
[-2, 0, 2],
[-1, 0, 1]])
# sobel in y direction
sobel_y= np.array([[-1,-2,-1],
[0, 0, 0],
[1, 2, 1]])
# laplacian
laplacian=np.array([[0, 1, 0],
[1,-4, 1],
[0, 1, 0]])
filters = [mean_filter, gaussian, laplacian, sobel_x, sobel_y, scharr]
filter_name = ['mean_filter', 'gaussian','laplacian', 'sobel_x', \
'sobel_y', 'scharr_x']
fft_filters = [np.fft.fft2(x) for x in filters]
fft_shift = [np.fft.fftshift(y) for y in fft_filters]
mag_spectrum = [np.log(np.abs(z)+1) for z in fft_shift]
for i in xrange(6):
plt.subplot(2,3,i+1),plt.imshow(mag_spectrum[i],cmap = 'gray')
plt.title(filter_name[i]), plt.xticks([]), plt.yticks([])
plt.show()

résultat:

Spectre de fréquences de différents noyaux
À partir de l'image, nous pouvons voir que chaque opérateur laisse passer ces signaux. À partir de ces informations,
nous pouvons savoir que ce sont des HPF et des LPF.
Plus de ressources

  1. Une explication intuitive de la théorie de Fourier par Steven Lehar
  2. Transformat de Fourier HIPR
  3. Que désigne le domaine fréquentiel dans le cas des images?

Pour plus d'informations, veuillez faire attention au compte officiel:
img

Je suppose que tu aimes

Origine blog.csdn.net/yegeli/article/details/113430475
conseillé
Classement