Salut:)
je travail avec c++ Builder 6, et cherche un code pour bruiter une image bmp par un bruit gaussien, est ce que vous pouvez m'aider
Merci d'avance:)
Version imprimable
Salut:)
je travail avec c++ Builder 6, et cherche un code pour bruiter une image bmp par un bruit gaussien, est ce que vous pouvez m'aider
Merci d'avance:)
L'image que tu lis finit dans un tableau dont le format est lié à celui de ton image (en noir et blanc, tu n'auras qu'une composante, en RGB, trois).
Chaque composante varie de 0 à max (max = 255 dans la plupart des cas)
Il te faut un générateur de nombres aléatoires qui te produise des nombres aléatoires selon une loi gaussienne (je ne sais pas ce que produit le générateur par défaut).
Ensuite pour chaque pixel, il faut générer un bruit d'amplitude A (A = 20 par exemple). Tu auras dont un bruit B de allant de -20 à 20.
A chaque composante de chaque pixel, tu ajoutes ce bruit (en écrétant à [0..255]) et tu sauvegardes la nouvelle image ainsi obtenue.
Sinon il y a la solution d'utiliser la librairie CImg de l'Inria qui contient des fonctions déjà codées pour le traitement des images...
Salut kaji :),
Merci pour ta réponse, tu ma donné une idée pour commencer, maintenant je trouve une difficulté pour la formule de la loi de gausse qui est f(x)=exp[-1/2((x-m)/écart type))²]/[écart type(sqrt(2pi)], j'aimerai bien que quelqu'un m'explique cette formule dans le cadre du géneration d'un bruit gaussien afin de bruiter une image.
merci d'avace :)
Ta courbe f(x) est la fameuse "courbe en cloche" de Gauss, aussi appelée "Loi Normale". Tu peux la voir ici http://fr.wikipedia.org/wiki/Loi_normale
Déjà il faut savoir ce que te donne le générateur de nombres aléatoires de C++...
Je ne savais pas non plus et j'ai écrit un petit programme qui tire 100000 nombres de 0 à 100 et je compte le nombre dans le tableau tabNbSorties, le nombre de sorties. Par exemple, si le 50 et tiré une première fois, tabNbSorties[50] vaut 1. Si il sort une seconde fois, tabNbSorties[50] vaudra 2, etc.
A la fin j'enregistre tous les compteurs du tableau tabNbSorties dans un fichier texte au format lisible par Scilab (il est gratuit). Il suffit de copier-coller le texte "y = [4 5 6 ... 7 5 4]; bar(y);" dans Scilab et tu obtiens un magnifique histogramme !
Mon programme (C++ standard)
En sortie, j'obtiens le tableau suivant par exemple :Code:
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 #include <stdlib.h> #include <iostream> #include <fstream> using namespace std; // // Renvoie un nombre aléatoire entre nMin et nMax // int getNbAleatoire(int nMin, int nMax) { return (int)(nMin + ((float) rand() / RAND_MAX * (nMax - nMin + 1))); }// getNbAleatoire int main(int argc, char *argv[]) { int nAmorce = 2;// amorce (vaut 1 par défaut) srand(nAmorce); const int ncMin = 0; const int ncMax = 99; const int ncTirages = 100000; // Raz du tableau de comptage int tabNbSorties[ ncMax + 1]; for (int nI = ncMin; nI <= ncMax; ++nI ) { tabNbSorties[ nI ] = 0; } // Tirages et enregistrements for (int nI = 1; nI <= ncTirages; ++ nI) { int nbAleat = getNbAleatoire( ncMin, ncMax ); tabNbSorties[ nbAleat ]++; } // Enregistrement de l'histogramme ofstream f_out; f_out.open("histo.txt", ios::out ); f_out << "y = ["; for (int nI = ncMin; nI <= ncMax; ++nI ) { f_out << tabNbSorties[ nI ] << " "; } f_out << "]; bar(y);"; f_out.close(); // fin system("PAUSE"); return EXIT_SUCCESS; }// main
Et là, on voit grâce à Scilab que l'histogramme est à peu-près plat.Code:
1
2 y = [1059 1037 976 937 1006 1023 990 983 1023 1034 1010 1008 982 1019 944 1011 1005 951 960 1050 1049 981 973 1024 1003 1008 976 917 1047 976 1014 1041 967 1011 943 928 1019 1050 1029 998 1009 975 960 1050 992 992 1044 1014 1000 1053 964 947 993 950 1055 1017 1000 1047 985 1018 1012 1028 1029 1018 973 1024 1012 1027 1009 1005 1026 991 968 966 960 987 938 935 963 1017 1058 1057 965 1007 1007 954 1021 1013 978 1039 1010 986 975 984 1000 999 996 1053 972 1009 ]; bar(y);
Et donc tu peux te servir du générateur de nombres aléatoires standard pour générer des valeurs de "x".
Préalablement, tu calcules un histogramme (un tableau, donc) y = f(x) qui suive ta loi nomale Par exemple de x = 0 à x = 20 avec un maxi en x = 10 (y = f(10) = 20 par exemple) (La "cloche est centrée en x = 10 avec un mini en x = 0 et x = 20).
Ensuite, pour chaque pixel, tu génères un nombre aléatoire x entre 0 et 20. Le bruit correspondant vaut B = y = f(x) et tu l'ajoutes aux composantes de ton pixel. Ecrétage éventuel à [0 .. 255], et le tour est joué.
Eventuellement, tu calcules B = y - 10 pour avoir un bruit de -10 à 10...
Salut kaji :)
Résumant se que j'ai compris:
- Je doit calculer un tableau histogramme selon la loi de gauss "cloche de gauss", donc j'aurai un tableau H allant du min jusqu'au max , je procède comme tu a fait dans ton code:
sauf pour la formule retournée j'utilise celle de gauss.Code:
1
2
3
4
5 Renvoie un nombre aléatoire entre nMin et nMax // int getNbAleatoire(int nMin, int nMax) { return (int)(nMin + ((float) rand() / RAND_MAX * (nMax - nMin + 1))); }// getNbAleatoire
- Pour chaque pixel Générer un nombre aléatoire x entre min et max par le générateur de builder; et trouver le bruit B correspondant dans le tableau H[x] tel que B=H[x]
- En fin ajouter ce bruit B aux composantes de chaque pixel.
Est ce que j'ai bien compris là?
Merci d'avance :)
Bonjour,
si tu regardes parmi les plugins d'ImageJ, tu en trouveras un qui fait ce que tu demandes. Le code est disponible :)
Salut ToTo13 :)
Je voie que ImageJ concerne java; rappelant que je travaille avec c++ builder, ainsi que ma question été sur l'algorithme à suivre pour faire l'ajout d'un bruit gaussien à une image
Dans les discussions précédentes, kaji ma proposé une solution
j'ai résumé après ce que j'ai retenuCitation:
..Déjà il faut savoir ce que te donne le générateur de nombres aléatoires de C++...
Je ne savais pas non plus et j'ai écrit un petit programme qui tire 100000 nombres de 0 à 100 et je compte le nombre dans le tableau tabNbSorties, le nombre de sorties. Par exe........
Et j'ai demandé est ce q j'ai bien compris l'algorithme?:(Citation:
Résumant se que j'ai compris:
* Je doit calculer un tableau histogramme selon la loi de gauss "cloche de gauss", donc j'aurai un tableau H allant du min jusqu'au max , je pr..........
j'ai cherché sur le forum et j'ai pas trouvé, merci ToTo de me donné un lien précis ou de m'expliquer le procédé.
Merci d'avance :)
Bonjour,
je sais lire merci... mais la partie d'ajout du bruit ressemble plus à du C que du Java.
Voilà ce que l'on trouve en cherchant "Gaussian" ou "Noise" dans la page.
Salut :)
désolez ToTo si j'ai mal exprimé la dernière foi :oops:, j'ai téléchargé le code contenu dans le lien que tu ma donné, mais j'arrive pas à lire, car j'ai pas le compilateur java sur mon pc, Est ce que tu peut me le donner sous format texte ici dans le forum??
Merci d'avance :)
Oui, c'est ça, tu remplis un tableau
Avec tabH[0], la première valeur de ta courbe en cloche, tabH[49], le maxi (20 par exemple) et tabH[99], la dernière valeur.Code:float tabH[100];//par exemple
Pour chaque pixel, tu tires un nombre aléatoire x dans l'intervalle [0, 99] (la taille de ton histogramme) et le bruit gaussien aléatoire correspondant sera B = tabH[x].
Exactement. A chaque pixel, tu tires un "x" et tu calcules le bruit correspondant par B = tabH[x] que tu ajoutes à chaque composante du pixel (en écrêtant à la bonne plage souvent [0 .. 255])
Enfin, il y a tout de même largement mieux pour générer un nombre aléatoire selon une gaussienne ! cf mon tutoriel, et si tu dois vraiment le réaliser par toi-même cherche du côté de la transformation de Box-Muller !
Lequel ? Je ne l'ai pas trouvé dans tes pages... Il faut utiliser la librairie Boost ?
Sur Wikipédia, par exemple ?
D'après ce que j'ai compris, avec cette méthode, les nombres aléatoires "selon un gaussienne" se calculent par paire (z0 et z1) à partir de deux nombres aléatoires "linéaires" (x et y)
Algo simplifié :
- tirer x et y
- calculer s = x^2 + y^2
- z0 = x . sqr{-2.log(s)/s};//(forme cartésienne)
- z1 = y . sqr{-2.log(s)/s}
Pour chaque nombre aléatoire, il faut calculer des carrés, des racines carrées, des logarithmes, des multiplications... Et dans la forme polaire, c'est plus compliqué, il y a des calculs de cosinus !!
Il me semble que cette méthode n'est intéressante que pour la résolution des équations différentielles...
Dans notre cas, je ne vois vraiment pas l'intérêt... (à part pour perdre du temps et faire un code compliqué...)
1) oui, celui dont j'ai donné le lien plus haut, et oui, ça utilise Boost.
2) Tu peux t'amuser avec un histogramme cumulé, mais tu dois le parcourir et si tu veux un peu de précision, Box-Muller sera largement plus avantageux.
Oui, ça-y-est, j'ai trouvé, il faut aller dans http://matthieu-brucher.developpez.c.../boost/random/, puis "Distributions" dans "Autres distributions", choisir : normal_distribution.
Et il les calcule comment ses nombres aléatoires à distribution Gaussienne, Boost ? Si ça se trouve, il fait ce que je propose... :D
Je propose un histogramme non cumulé et simplement un accès direct au nième élément... Plus simple, tu meurs ! :D
C'est vrai que la méthode Box-Muller est plus précise et moins consommatrice en mémoire (pour plus de précision avec ma méthode, prendre un histogramme plus grand, ou faire une interpolation entre tabH[i] et tabH[i+1] [ça coûte 2 multiplications, une somme et une division]).
Ceci dit, pour ajouter du bruit aux pixels d'une image il faut nécessairement des entiers... et donc un résultat discrétisé moins précis d'un résultat continu... La précision n'est donc pas ici un argument prépondérant.
De plus avec Box-Muller, il faut calculer des carrés, des racines carrées, des logarithmes, des multiplications à chacun des nombreux pixels d'une image... j'ai peur que ce soit beaucoup plus lent.
Mais en tous cas, je ne connaissais pas Box-Muller, ça peut servir, merci.;)
Une transformation Box-Muller, on se demande pourquoi ;)
Un histogramme non cumulé ne te servira à rien, il te faut un histogramme cumulé pour générer tes nombres. A moins que je n'ai pas compris ta méthode, il n'y a aucune chance pour que ton code fasse ce que tu crois (parole de statisticien).
J'ai relu ce que tu penses à faire, je te rassure tout de suite, ça ne fait pas du tout une courbe gaussienne ;) (ou plus précisément, ça ressemble à une gaussienne dans le bouillard)
Si tu veux générer une loi aléatoire à partir d'une loi uniforme, tu DOIS partir de p(x<X) et non d(x=X). Une fois que tu as ce tableau, tu peux générer un nombre aléatoire entre 0 et 1 et prendre l'indice correspondant à cette valeur dans ton tableau cumulé. A partir de cet indice, tu as ton nombre aléatoire selon une transformation linéaire. C'est la SEULE solution pour générer n'importe quelle loi de manière acceptable (trace donc l'histogramme final d'une génération avec ton algorithme). De cette manière, tu répartis de manière uniforme (et correctement) les échantillons.
Dans ton exemple, au milieu du tableau, tu génères le nombre 20 le plus grand nombre de fois. Un bruit dans une image, c'est de moyenne nulle.
Plus sérieusement, pour calculer les indices dans ton tableau, je te souhaite bon courage (pour calculer l'intégrale par morceau de la loi gaussienne).
Tu sais, Matthieu, que Claude Allègre a une très bonne formation et qu'il émet des doutes sur le réchauffement climatique ? ;)
Blague à part, la référence pour moi en calcul numérique, c'est Numerical Recipes www.nr.com
Et justement, ils ont traité le problème des nombres aléatoires selon une Gaussienne.
J'ai même trouvé sur le site de Pierre Chatelier une implémentation de l'algo de Numerical Recipes.
http://ktd.club.fr/programmation/cpp-random.php. Il y a même ses tests avec.
Je pense que tu (SmileSoft) devrait le tester et l'utiliser... (avec son autorisation) ;)
Sinon il y a une implémentation toute faite de l'algo de Box-Muller.
En performance, le classement des algos devrait donner ceci :
1) Numerical Recipes (de loin !!)
2) Le mien 8-) ;)
3) Box-Muller
Bon bruitage... ;)
Faut juste une licence pour utiliser le code des NR (et quand je vois le code fourni, c'est parfois...)...
Maintenant, si tu veux vraiment classer le code, la vitesse ne veut rien dire dans ce cas, ce qui est primordial, c'est la qualité de la génération aléatoire, et là ton code est bien loin derrière Box-Muller ou la solution des NR.
Salut Kaji et Matthieu :)
je vous remercie pour cette riche discussion ;)
je travaille maintenant sur une autre méthode, j'ai trouvé ce que donne le générateur des nombre aléatoires de c++ builder, et j'ai pensé à une petite solution qui parait simple.
Supposant que j'ai une image que je vais lui ajouter un bruit B avec le sigma=0.2 alors:Remarque: j'ai utilisé la formule de gauss à 2 dimension (pour image)Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 int i,x,y=0; float B; randomize(); for( i=0;i<Form1->Image1->Picture->Width;i++)// parcours des ligne de l'image. { for(int j=0;j<Form1->Image1->Picture->Height;j++) // parcours des colonnes de l'image. { x=rand()%20; y=rand()%20; B=exp(-(x*x+y*y)/(2*0.2*0.2)); //l'ajout du bruit Form1->Image1->Canvas->Pixels[i][j]=Form1->Image1->Canvas->Pixels[i][j]+B; } } }
f(x,y)=exp( - (x*x+y*y) / (2*sigma*sigma))
- Est ce que je suis dans le bon sens?
- Je trouve une difficulté pour le sigma:
Est ce qu'il doit être calculé ?
ou c'est un paramètre que l'user va entrer?
Merci d'avance :)
Euh... B n'est pas un bruit gaussien...
mais c'est quoi cette horreur 8O
C'est un bruit, mais pas gaussien (fais le calcul par toi-même, il n'est même pas de moyenne nulle)
Box muller c'est quant meme pas compliqué !!!
salut :)
j'ai essayé un autre code, là j'utilise une image couleur (rgb):
sachant que la fonction RandG est le générateur des nombres aléatoires gaussien de c++ builder.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 void __fastcall TForm1::Button2Click(TObject *Sender) { int B; int amplitude=50; randomize(); int r,v,b=0; for(int i=0;i<Form1->Image1->Picture->Width;i++) { for(int j=0;j<Form1->Image1->Picture->Height;j++) { B=(char )( RandG( 0.0,0.3 ) * amplitude ); // RandG génère des nombre aléatoir selon la loi de gauss. // l'ajout du bruit B à chaque composantes R, G et B de l'image r=GetRValue(Image1->Canvas->Pixels[i][j])+B; v=GetGValue(Image1->Canvas->Pixels[i][j])+B; b=GetBValue(Image1->Canvas->Pixels[i][j])+B; Form1->Image1->Canvas->Pixels[i][j]=RGB(r,v,b); } } }
Est ce que B est un bruit gaussien ?
Merci d'avance :)
Dans ce cas, oui. En revanche, je ne connais pas la qualité du générateur sous-jacent, ça peut marcher dans ce cas et si tu le réutilises avec des outils plus complexes planter dans un problème statistique.
Salut SmileSoft,
Désolé pour le retard... félicitations pour ton code... Je ne connaissais pas la fonction RandG de Builder...
D'après la doc BCB, oui...
Pour en être sûr, il faudrait effectuer un petit test et tracer l'histogramme de répartition...
Par contre, j'ai l'impression que tu as oublié dans ton code d'écrêter les valeurs des composantes de tes pixels.
Je ne sais pas quel est la plage de valeurs, mais si c'est du [0..255], et que tu as des pixels blancs [255, 255, 255] auxquels tu ajoutes du bruit, ces pixels vont peut-être se retrouver noirs !! ;)
Bonjour à vous,
Je pense que ce que Kaji veut dire c'est qu'on ajoutant la valeur B (le nombre aléatoire généré)à chaque composante (R,V,B),Il serait possible que les nouvelles valeurs des composantes (R,V,B)dépassent 255!!
Ce qui donnerai des résultats pas trés attendus!:aie: