Comment puis-je rendre une image floue gaussienne sans utiliser de gaussiennes en fonctions intégrées?

StackOverflow https://stackoverflow.com/questions/1696113

Question

Je veux brouiller mon image en utilisant la formule de flou gaussien natif. Je lis l'article de Wikipedia , mais je ne suis pas sûr de savoir comment mettre en œuvre.

Comment puis-je utiliser la formule pour décider des poids?

Je ne veux pas utiliser les fonctions intégrées comme ce qui a Matlab

Était-ce utile?

La solution

L'écriture d'un flou gaussien naïf est en fait assez facile. Il se fait exactement de la même façon que tout autre filtre de convolution. La seule différence entre une boîte et un filtre gaussienne est la matrice que vous utilisez.

Imaginez que vous avez une image définie comme suit:

 0  1  2  3  4  5  6  7  8  9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32 33 34 35 36 37 38 39
40 41 42 43 44 45 46 47 48 49
50 51 52 53 54 55 56 57 58 59
60 61 62 63 64 65 66 67 68 69
70 71 72 73 74 75 76 77 78 79
80 81 82 83 84 85 86 87 88 89
90 91 92 93 94 95 96 97 98 99

Une matrice de filtre de boîte 3x3 est définie comme suit:

0.111 0.111 0.111
0.111 0.111 0.111
0.111 0.111 0.111

Pour appliquer le flou gaussienne vous procédez comme suit:

Pour pixel 11 vous devez charger pixels 0, 1, 2, 10, 11, 12, 20, 21, 22.

vous puis multiplier pixel 0 par la partie supérieure gauche du filtre de flou 3x3. Pixel 1 par le milieu, en haut, pixel 2, 3 par pixel en haut à droite, 10 par pixel au milieu à gauche et ainsi de suite.

Ensuite, les ajouter au total et écrire le résultat pixel 11. Comme vous pouvez le voir Pixel 11 est maintenant la moyenne de lui-même et les pixels environnants.

cas Edge obtiennent un peu plus complexe. Quelles sont les valeurs que vous utilisez pour les valeurs du bord de la texture? Une façon peut être d'envelopper autour de l'autre côté. Cela semble bon pour une image qui est ensuite carrelée. Une autre façon est de pousser le pixel dans les lieux environnants.

Donc, pour en haut à gauche, vous pouvez placer les échantillons comme suit:

 0  0  1
 0  0  1
10 10 11

J'espère que vous pouvez voir comment cela peut facilement être étendu aux gros grains de filtre (c.-à-5x5 ou 9x9, etc.).

La différence entre un filtre gaussien et un filtre de boîte est le nombre qui vont dans la matrice. Un filtre gaussien utilise une distribution gaussienne sur une ligne et une colonne.

pour un filtre par exemple défini arbitrairement (à savoir ce n'est pas une gaussienne, mais probablement pas loin)

0.1 0.8 0.1

la première colonne serait le même, mais multiplié dans le premier élément de la ligne au-dessus.

0.01 0.8 0.1
0.08 
0.01 

La deuxième colonne serait le même, mais les valeurs serait multiplié par 0,8 dans la ligne ci-dessus (et ainsi de suite).

0.01 0.08 0.01
0.08 0.64 0.08
0.01 0.08 0.01

Le résultat de l'addition de ce qui précède ensemble doit être égale à 1. La différence entre le filtre ci-dessus et le filtre de boîte d'origine serait que le pixel d'extrémité écrit aurait une pondération plus lourde vers le pixel central (par exemple celui qui est dans cette position déjà). Le flou se produit parce que les pixels environnants ne brouillent dans ce pixel, mais pas autant. En utilisant ce type de filtre vous obtenez un flou mais qui ne détruit pas autant de la haute fréquence (c.-à changement rapide de la couleur du pixel à pixel) des informations.

Ce genre de filtres peut faire beaucoup de choses intéressantes. Vous pouvez faire une détection de bord en utilisant ce type de filtre en soustrayant les pixels voisins du pixel courant. Cela laissera seulement les changements vraiment grands en couleur (hautes fréquences) derrière.

Edit:. Un noyau de filtre 5x5 est définie exactement comme ci-dessus

Par exemple, si votre ligne est de 0,1 0,2 0,4 0,2 0,1 puis si on multiplie chaque valeur de leur par le premier élément pour former une colonne, puis de multiplier chacun par le second élément pour former la deuxième colonne et ainsi de suite vous finirez avec un filtre de

0.01 0.02 0.04 0.02 0.01
0.02 0.04 0.08 0.04 0.02
0.04 0.08 0.16 0.08 0.04
0.02 0.04 0.08 0.04 0.02
0.01 0.02 0.04 0.02 0.01

prendre des positions arbitraires, vous pouvez voir que la position 0, 0 est simple 0.1 * 0.1. Position 0, 2 * est de 0,1 à 0,4, en position 2, la figure 2 est 0,4 * 0,4 et la position 1, 2 est de 0,2 * 0,4.

J'espère que vous donne une assez bonne explication.

Autres conseils

Voici le pseudo-code pour le code je en C # pour calculer le noyau. Je n'ose pas dire que je les traite finaux conditions correctement, cependant:

double[] kernel = new double[radius * 2 + 1];
double twoRadiusSquaredRecip = 1.0 / (2.0 * radius * radius);
double sqrtTwoPiTimesRadiusRecip = 1.0 / (sqrt(2.0 * Math.PI) * radius);
double radiusModifier = 1.0;

int r = -radius;
for (int i = 0; i < kernel.Length; i++)
{
    double x = r * radiusModifier;
    x *= x;
    kernel[i] =
    sqrtTwoPiTimesRadiusRecip * Exp(-x * sqrtTwoPiTimesRadiusRecip);
    r++;
}

double div = Sum(kernel);
for (int i = 0; i < kernel.Length; i++)
{
    kernel[i] /= div;
}

Espérons que cela peut aider.

Pour utiliser le noyau de filtre discuté dans l'article de Wikipedia vous devez implémenter (discret) convolution . L'idée est que vous avez une petite matrice de valeurs (le noyau), vous déplacez ce noyau de pixel à pixel dans l'image (par exemple pour que le centre de la matrice est sur le pixel), il faut multiplier les éléments de la matrice avec l'image chevauchée éléments, la somme de toutes les valeurs du résultat et de remplacer l'ancienne valeur de pixel avec cette somme.

flou gaussien peut être séparé en deux convolutions 1D (une verticale et l'autre horizontale) au lieu d'une convolution 2D, ce qui accélère aussi les choses un peu.

Je ne suis pas certain que vous voulez limiter ce certaines technologies, mais sinon SVG (ScalableVectorGraphics) a une implémentation de flou gaussien. Je crois qu'il applique à toutes les primitives y compris pixels. SVG a l'avantage d'être un standard ouvert et largement mis en œuvre.

Eh bien, noyau gaussien est un noyau séparable.
D'où tout ce que vous avez besoin est une fonction qui prend en charge 2D Séparables Convolution comme - ImageConvolutionSeparableKernel().

Une fois que vous l'avez, tout besoin est un wrapper pour générer du noyau 1D gaussienne et l'envoyer à la fonction que fait dans ImageConvolutionGaussianKernel() .

Le code est une implémentation en avant droite C de circonvolution d'image 2D accélérée par SIMD (SSE) et Multi Threading (OpenMP).

L'ensemble du projet est donnée par - image Convolution - GitHub <. / p>

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top