/// <summary> /// Pour rétrécir une image, on va faire la méthode "inverse" de l'agrandissement. /// C'est à dire que pour un pixel de l'image d'arrivée, on va prendre un nombre de pixels de l'image de départ /// correspondant à une matrice carrée de pixels de taille le facteur d'agrandissement et partant du pixel en haut à gauche. /// Ensuite, on fait la moyenne de toutes les intensités de couleurs (RGB) des pixels et on rentre ces valeurs dans /// le pixel de l'image d'arrivée. /// </summary> /// <param name="facteurRétrécissement">valeur entière correpondant au taux par lequelle on va rétrécir l'image</param> public void Retrecir(int facteurRétrécissement) { //Pour obtenir la hauteur et la largeur de notre matrice d'arrivée, on effectue une division de la hauteur d'origine //par le facteur de rétrécissement. Cependant lorsque l'on fait ce genre de division, on renvoie un entier alors que //les divisions ne se font pas toujours entre nombres multiples entre eux. On aura donc par la suite un problème //d'indexation. Il faut donc aussi prendre en compte le reste de ce quotient car il devient non négligeable dans le //cas où le facteur de rétrécissement est très grand. Dans le cas où la hauteur/largeur n'est pas divisible par //le facteur de rétrécissement, il faut donc rajouter une ligne/colonne dans l'image d'arrivée. C'est pour cela //que dans les formules si dessous on ajoute à la hauteur le facteur- le reste du quotient de la hauteur pour ensuite //le diviser par le facteur car cela nous donne un nombre entier correspondant à une unité de plus que le quotient //traditionnel de la hauteur par le facteur. int Newhauteur = (hauteur + (facteurRétrécissement - hauteur % facteurRétrécissement)) / facteurRétrécissement; int Newlargeur = (largeur + (facteurRétrécissement - largeur % facteurRétrécissement)) / facteurRétrécissement; Pixel[,] ImageArrivée = new Pixel[Newlargeur, Newhauteur]; for (int ligne = 0; ligne < Newhauteur; ligne++) { for (int colonne = 0; colonne < Newlargeur; colonne++) { //Comme à chaque fois que l'on change de pixel dans la matrice d'arrivée, on change de matrice de pixel //dans la matrice de départ. Donc lorsque l'on a parcouru une matrice [3,3] de pixels, on passe à la suivante //et on part dès lors de l'index [ligne,colonne*facteurRétrécissement] car on doit se décaler vu que les cases //colonne jusqu'à colonne+facteurRétrécissement-1 auront déjà été utilisées. Pixel pixeltransition = new Pixel(0, 0, 0); //Ici, on doit vérifier que l'on est pas dans "l'extra colonne/ligne" de la nouvelle matrice pour éviter //des erreurs d'indexation int newligne = ligne * facteurRétrécissement; int newcolonne = colonne * facteurRétrécissement; int endligne = 0; int endcolonne = 0; if (ligne == Newhauteur - 1) { endligne = hauteur % facteurRétrécissement; } if (colonne == Newlargeur - 1) { endcolonne = largeur % facteurRétrécissement; } for (int i = newligne; i < newligne + facteurRétrécissement - endligne; i++) { for (int j = newcolonne; j < newcolonne + facteurRétrécissement - endcolonne; j++) { pixeltransition.AdditionnerPixels(image[newligne, newcolonne]); } } //Une fois que l'on a additionner les valeurs des couleurs RGB des pixels, il faut diviser ces //3 valeurs par le nombre de pixels étudier afin d'obtenir la moyenne des intensités de couleur int diviseur = facteurRétrécissement * facteurRétrécissement; pixeltransition.DiviserValeurs(diviseur); ImageArrivée[ligne, colonne] = pixeltransition; } } }
/// <summary> /// Méthode qui va appliquer le filtre sur l'image grâce à la matrice de convolution choisie à l'aide la méthode ChoisirFiltre. /// Pour appliquer le filtre, il faut multiplier chaque case et son contour par la matrice de convolution. /// La case et son contour doivent former une matrice carrée de dimensions égales à celles de la matrice de convolution. /// Mais il ne s'agit pas d'une multiplication de matrices classiques: on doit multiplier le 'pixel' en haut à gauche de la matrice de l'image /// par le nombre en haut à gauche de la matrice de convolution et ainsi de suite jusqu'à la fin. /// La somme de tous ses termes donne le nouveau pixel de l'image filtrée. On répète cette opération pour tous les pixels de l'image de départ. /// /// Cependant plusieurs problèmes se posent: /// - le premier est un problème d'index. En effet, si on prend le pixel en haut à gauche de l'image, ce dernier n'a pas /// de contour parfait, il lui manque cinq pixels si la matrice de convolution est de dimension 3*3. Il faut donc prendre /// chaque case cas par cas pour sélectionner la bonne matrice de contour de pixel. /// - le deuxième est que l'on traite des pixels et non des nombres ce qui fait que la multiplication est plus complexe: /// il faudrait multiplier chaque composante RGB du pixel par le nombre de la matrice de convolution puis additionner /// ces composantes pour donner le pixel final. /// </summary> public void MatriceFiltre() { int[,] MatriceConvolution = new int[3, 3]; int coefficient = 0;//ce coefficient correspond à la somme des termes de la matrice de convolution Console.WriteLine("Quel filtre voulez-vous appliquer à votre image?"); Console.WriteLine("- Flou (Tapez F)"); Console.WriteLine("- Détection de contour (Tapez D)"); Console.WriteLine("- Repoussage (Tapez R)"); Console.WriteLine("- Renforcements des bords (Tapez B)"); char touche = Convert.ToChar(Console.ReadLine()); while (touche != 'F' && touche != 'D' && touche != 'R' && touche != 'B') { Console.WriteLine("Votre saisie est erronée. Veuillez réessayer (Faites attention à bien écrire les lettres en majuscules): "); touche = Convert.ToChar(Console.ReadLine()); } if (touche == 'F') { int[,] matrice = { { 1, 1, 1 }, { 1, 1, 1 }, { 1, 1, 1 } }; MatriceConvolution = matrice; coefficient = 9; } if (touche == 'D') { int[,] matrice = { { 0, 1, 0 }, { 1, -4, 1 }, { 0, 1, 0 } }; MatriceConvolution = matrice; coefficient = 0; } if (touche == 'R') { int[,] matrice = { { -2, -1, 0 }, { -1, 1, 1 }, { 0, 1, 2 } }; MatriceConvolution = matrice; coefficient = 1; } if (touche == 'B') { int[,] matrice = { { 0, 0, 0 }, { -1, 1, 0 }, { 0, 0, 0 } }; MatriceConvolution = matrice; coefficient = 0; } Pixel[,] ImageArrivée = new Pixel[hauteur, largeur]; Pixel[,] ImageTransition = image; int NbrCases = (hauteur / 2) + 1;//nombre de lignes/colonnes après le point central de la matrice de convolution //On parcourt chaque pixels de l'image avec la double boucle for for (int ligne = 0; ligne < hauteur; ligne++) { for (int colonne = 0; colonne < largeur; colonne++) { Pixel pixeltransition = new Pixel(0, 0, 0); int décalageLigneFin = 0; int décalageLigneDébut = 0; int décalageColonneFin = 0; int décalageColonneDébut = 0; //On veut savoir si les cases de la matrice de convolution sont bien dans la matrice que l'on veut filtrer if (ligne - NbrCases < 0) //si le numéro de la ligne moins NbrCases est inférieur à 0, on est hors-index au dessus de la matrice. //Il faut donc redéfinir la ligne d'où l'on commence la double itération pour faire la multiplication. { décalageLigneDébut = ligne + NbrCases; } if (ligne + NbrCases > hauteur - 1)//De même si la ligne + NbrCases est supérieure à la hauteur -1 de la matrice { décalageLigneFin = ligne - (hauteur - 1) + NbrCases; } if (colonne - NbrCases < 0) { décalageColonneDébut = colonne + NbrCases; } if (colonne + NbrCases > largeur - 1) { décalageColonneFin = colonne - (largeur - 1) + NbrCases; } //on doit déterminer les coordonnées (lignes et colonnes) du début de l'itération pour la multiplication int newligne = ligne - NbrCases; int newcolonne = colonne - NbrCases; for (int i = newligne + décalageLigneDébut; i < newligne + MatriceConvolution.GetLength(0) - décalageLigneFin; i++) { for (int j = newcolonne + décalageColonneDébut; j < newcolonne + MatriceConvolution.GetLength(1) - décalageColonneFin; j++) { // d'abord on fait la multiplication de du pixel de la matrice de convolution avec le pixel de l'image image[i, j].MultiplierValeurs(MatriceConvolution[i - newligne, j - newcolonne]); // Ensuite on additionne la valeur obtenue avec le/les pixels précédents pixeltransition.AdditionnerPixels(image[i, j]); // Pour ne pas modifier les pixels de l'image de départ, on égalise image[i,j] avec l'image de transition [i,j] image[i, j] = ImageTransition[i, j]; } } //On divise le pixel de transition final (après avoir fait la somme de tous les produits) pour ne pas dépasser 255 ou 0 pixeltransition.DiviserValeurs(coefficient); //On donne la valeur du pixel de transition final au pixel de l'image d'arrivée ImageArrivée[ligne, colonne] = pixeltransition; } } }