Une histoire sur le filtrage par convolution uniquement par calcul matriciel sans s'appuyer sur la bibliothèque de traitement d'image. Également possible avec Pythonista
** Cliquez ici pour les informations de base **
Au lieu de m'appuyer sur Open CV ou Pillow, j'écrirai en fait divers traitements d'images en utilisant numpy et matplotlib. C'est une combinaison qui peut également être utilisée avec l'application iOS Pythonista.
import numpy as np
import matplotlib.pyplot as plt
De plus, les fonctions suivantes sont pratiques pour afficher des images. (Pour plus de détails, Basics)
def img_show(img : np.ndarray, cmap = 'gray', vmin = 0, vmax = 255, interpolation = 'none') -> None:
'''np.Afficher une image avec un tableau comme argument.'''
#Définissez dtype sur uint8
img = np.clip(img,vmin,vmax).astype(np.uint8)
#Afficher l'image
plt.imshow(img, cmap = cmap, vmin = vmin, vmax = vmax, interpolation = interpolation)
plt.show()
plt.close()
Filtrage spatial est facile à comprendre pour le filtre par convolution.
Tout d'abord, créez une fonction de convolution d'un tableau à deux dimensions.
def convolve2d(img, kernel):
#Calculer la taille de la sous-matrice
sub_shape = tuple(np.subtract(img.shape, kernel.shape) + 1)
#Le nom de la fonction étant long, il est omis une fois
strd = np.lib.stride_tricks.as_strided
#Créer une matrice sous-matrice
submatrices = strd(img,kernel.shape + sub_shape,img.strides * 2)
#Calculer la somme d'Einstein de la sous-matrice et du noyau
convolved_matrix = np.einsum('ij,ijkl->kl', kernel, submatrices)
return convolved_matrix
Le code ci-dessus est alambiqué en utilisant la matrice de la sous-matrice de img. Voir enseignant stackoverflow pour plus de détails. Dans cet algorithme, la partie périphérique peut être supprimée.
[Découpage] 'tiger.jpeg'(http://qiita.com/secang0/items/1229212a37d8c9922901#%E5%9B%9B%E8%A7%92% E5% BD% A2% E3% 81% AB% E3% 83% 88% E3% 83% AA% E3% 83% 9F% E3% 83% B3% E3% 82% B0330% E8% BF% BD% E5% 8A% A0) image [moyenne pondérée par coefficient NTSC](http://qiita.com/secang0/items/6fba02d7cc3ef34c0c31#ntsc-%E4%BF%82%E6%95%B0%E3%81%AB % E3% 82% 88% E3% 82% 8B% E5% 8A% A0% E9% 87% 8D% E5% B9% B3% E5% 9D% 87% E6% B3% 95) En revanche, divers filtres ont été utilisés.
img = plt.imread('tiger.jpeg')[1200:1500,1400:1700]
img = (0.298912 * img[...,0] + 0.586611 * img[...,1] + 0.114478 * img[...,2])
img_show(img)
Un filtre passe-bas est un filtre qui a tendance à laisser une partie basse fréquence plutôt qu'une partie haute fréquence d'une image. (Haut / bas est la fréquence) En bref, cela s'estompe en réduisant les changements soudains. Ce processus est souvent utilisé pour supprimer le bruit.
img_show(convolve2d(img, kernel))
Dans le tableau ci-dessous, la concaténation est utilisée pour s'aligner sur l'image d'origine.
Nom de la méthode | Noyau / image originale / image de filtre | Remarques |
---|---|---|
Filtre de moyenne mobile simple | kernel = np.ones((5,5)/25 |
Le filtre passe-bas le plus simple |
Filtre gaussien | kernel = gaussian_kernel(5) |
Excellent filtre passe-bas basé sur une distribution normale |
Dans l'image d'origine, la partie gris clair (vert jaunâtre dans l'image couleur) au centre est pointillée. Cependant, l'application d'un filtre passe-bas rend la confirmation difficile.
Dans le tableau, la matrice gaussienne suivante est utilisée. Référence
def gaussian_kernel(n : int) -> np.ndarray:
'''(n,n)Faire une matrice gaussienne de'''
#[nC0, nC1, ..., nCn]Créer
combs = [1]
for i in range(1,n):
ratio = (n-i)/(i)
combs.append(combs[-1]*ratio)
combs = np.array(combs).reshape(1,n)/(2**(n-1))
#Créer une matrice gaussienne avec le produit des vecteurs verticaux et horizontaux
result = combs.T.dot(combs)
return result
Un filtre passe-haut est un filtre qui a tendance à laisser une partie haute fréquence plutôt qu'une partie basse fréquence d'une image. Cela rend les zones variées plus accentuées et affine l'image.
Un filtre de netteté typique est pour $ k> 0 $
1.\hspace{5pt}
\left(
\begin{matrix}
0&-k&0\\
-k&1+4k&-k\\
0&-k&0\\
\end{matrix}
\right)
\\
\mbox{Ou}
\\
2.\hspace{5pt}
\left(
\begin{matrix}
-k&-k&-k\\
-k&1+8k&-k\\
-k&-k&-k\\
\end{matrix}
\right)
sharp_kernel_1 = lambda k : np.matrix('0,{0},0;{0},{1},{0};0,{0},0'.format(-k,1+4*k))
sharp_kernel_2 = lambda k : np.matrix('{0},{0},{0};{0},{1},{0};{0},{0},{0}'.format(-k,1+8*k))
Appel. Référence Plus la valeur de k est élevée, plus le filtre est puissant. De plus, si k est le même, 2 est plus fort.
L'image est filtrée gaussienne 3 * 3 et l'affichage est normalisé comme décrit ci-dessous.
img_gaussian = convolve2d(img, gaussian(3))
img_show(norm_img(convolve2d(img_gaussian, kernel)))
Dans le tableau ci-dessous, la concaténation est utilisée pour s'aligner sur l'image d'origine. La partie gris clair ci-dessous (vert jaunâtre dans une image couleur) est à l'origine pointillée et comporte de nombreuses composantes haute fréquence. Veuillez prêter une attention particulière.
Noyau / image originale / image de filtre |
---|
kernel = sharp_kernel_1(1) |
kernel = sharp_kernel_1(10) |
kernel = sharp_kernel_1(1) |
kernel = sharp_kernel_2(10) |
Étant donné que la valeur de pixel de l'image de filtre ne rentre pas entre 0 et 255, elle est normalisée par la fonction suivante. Cela correspond à l'intervalle de $ average \ pm n_ {std} \ fois l'écart type $ à 0 ~ 255. (En fait $ n_ {std} = 2 $) Il s'agit d'un processus qui est également utilisé pour l'image d'origine à des fins de comparaison, et est légèrement différent de l'image du haut.
def norm_img(img_filtered,n_std):
'''img_Standardiser filtré'''
mean = img_filtered.mean() #moyenne
std = img_filtered.std() #écart-type
img_norm = 256*((img_filtered - mean)/std + n_std)/(n_std*2)
return np.clip(img_norm,0,255).astype(np.uint8)
Des filtres différentiels sont utilisés pour l'extraction des contours. En effet, en trouvant la différence par rapport au pixel adjacent, vous pouvez savoir où le changement est important.
référence: ** Le résultat réel est affiché ** ** Explication des différentes différences de filtre **
L'image est filtrée gaussienne 3 * 3. En outre, [Section filtre passe-haut](http://qiita.com/secang0/items/f3a3ff629988dc660d87#%E3%83%8F%E3%82%A4%E3%83%91%E3%82%B9 % E3% 83% 95% E3% 82% A3% E3% 83% AB% E3% 82% BF% E3% 83% BC) Le processus de normalisation décrit en) a été appliqué.
img_gaussian = convolve2d(img, gaussian(3))
img_show(norm_img(convolve2d(img_gaussian, kernel)))
Contenu | Noyau / image originale / image de filtre | Remarques | Lien de référence |
---|---|---|---|
Filtre différentiel simple du premier ordre de bas en haut | kernel = np.matrix('0,-1,0;0,1,0;0,0,0') |
Sensibleaubruit | Avecexplication |
Filtre Prewitt de bas en haut | kernel = np.matrix('-1,-1,-1;0,0,0;1,1,1') |
Avecl'imagederésultat&Avecexplication | |
Filtre Sobel de bas en haut | kernel = np.matrix('-1,-2,-1;0,0,0;1,2,1') |
np.matrix('-1,-1,-1;0,0,0;1,1,1')*1.33 Ladifférenceavec |
Avecl'imagederésultat&Avecexplication |
Filtre laplacien | kernel = np.matrix('-1,-1,-1;-1,8,-1;-1,-1,-1') |
Différentieldesecondordredanstouteslesdirections |
Avecl'imagederésultat&Avecexplication |
Contenu | Noyau / image originale / image de filtre | Remarques | Lien de référence |
---|---|---|---|
Gaufrage | kernel = np.matrix('-2,-1,0;-1,1,1;0,1,2') |
1aucentredeSobel | Imagederésultatenbas |
Recommended Posts