FILTER : FAIRE DES MOSAIQUES D'IMAGES

Adn56 Messages postés 1172 Date d'inscription jeudi 24 mai 2007 Statut Membre Dernière intervention 28 septembre 2013 - 13 juin 2010 à 08:23
mafieulemouton Messages postés 24 Date d'inscription lundi 30 juin 2008 Statut Membre Dernière intervention 26 janvier 2010 - 17 août 2010 à 23:05
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/51902-filter-faire-des-mosaiques-d-images

mafieulemouton Messages postés 24 Date d'inscription lundi 30 juin 2008 Statut Membre Dernière intervention 26 janvier 2010
17 août 2010 à 23:05
Petit détail: pour le peu que j'en sais, la partie la plus lente de ton code c'est le calcul de la couleur moyenne en bouclant sur tous les pixels de chaque image. Déjà si c'est fait avec la miniature ca ira plus vite; mais pour aller encore plus vite tu peut créer simplement une miniature de 4 pixels juste pour le calcul, la c'est vraiment rapide! (la fonction drawimage native au.net est instantanée chez moi pour le changement de résolution). Au passage j'en profite pour utiliser InterpolationMode.Low qui force le système à ignorer toutes les méthodes d'interpolation, comme ca ça va encore plus vite.

Exemple:

Public Shared Function CouleurMoyenneImage(ByVal myImage As Image) As Color
Dim Thumb1 As New Bitmap(4, 4)
Dim Graph1 As Graphics = Graphics.FromImage(Thumb1)
Graph1.InterpolationMode = Drawing2D.InterpolationMode.Low
Graph1.DrawImage(myImage, New Rectangle(0, 0, 4, 4))
Graph1.Dispose()

Dim canalBleu As Integer = 0
Dim canalVert As Integer = 0
Dim canalRouge As Integer = 0
Dim canalAlfa As Integer = 0
For x As Integer = 0 To 3
For y As Integer = 0 To 3
canalBleu = (Thumb1.GetPixel(x, y).B) + canalBleu
canalVert = (Thumb1.GetPixel(x, y).G) + canalVert
canalRouge = (Thumb1.GetPixel(x, y).R) + canalRouge
canalAlfa = (Thumb1.GetPixel(x, y).A) + canalAlfa
Next
Next
Dim couleurMoy As New Color
couleurMoy = Color.FromArgb(canalAlfa / 16, canalRouge / 16, canalVert / 16, canalBleu / 16)
Return couleurMoy
End Function
mafieulemouton Messages postés 24 Date d'inscription lundi 30 juin 2008 Statut Membre Dernière intervention 26 janvier 2010
17 août 2010 à 22:55
Voila ce que je propose pour une exécution rapide du code sans problème de mémoire:

1- Une boucle sur toutes tes images

-tu génères toutes les miniatures dans un dossier temporaire. (a moins de vouloir une image de plus de 100 millions de pixels en sortie, tu as tout intérêt à adapter la résolution des images; au passage tu en profite pour gérer la rotation et la mise aux proportions)Comme ca ton occupation mémoire est presque nulle (pas plus d'une image à la fois)

-dans une collection tu stockes une structure contenant: chemin de la miniature, R moyen, V moyen, B moyen

rq: à confirmer mais je crois que les canaux de couleurs sont codés sur 256bits, des variables de type Byte seraient donc plus adaptées que des integer

2- Tu redimensionnes ton image support en fonction du nombre de miniatures que tu veux avoir au final (genre 100x150 pixels pour rester dans une proportion standard)

3- Tu n'a plus qu'à lire cette image comme un tableau. Chaque pixel correspond à une miniature que tu pioches facilement dans la collection générée au début (la c'est a toi de définir tes critères de tolérance pour la couleur, c'est juste l'exploitation de la collection)
raffika Messages postés 269 Date d'inscription dimanche 31 mai 2009 Statut Membre Dernière intervention 12 mars 2011
15 juil. 2010 à 11:27
Salut, GILLARDG, en fait le code
que tu montres permet de récupérer
une couleur standard pour le web à partir d'une couleur RGB ?
J'ai rajouté la source sur la page @+
gillardg Messages postés 3275 Date d'inscription jeudi 3 avril 2008 Statut Membre Dernière intervention 14 septembre 2014 2
14 juin 2010 à 16:00
moi j'utilise ceci

Private Shared WebColors As ArrayList
Private Shared colo As Object

''' <summary>
''' Returns the "nearest" color from a given "color space"
''' </summary>
''' The color to be approximated

''' <returns>The nearest color</returns>
Public Shared Function GetNearestWebColor(ByVal input_color As Color) As Color
' get the colorspace as an ArrayList
WebColors = GetWebColors()
' initialize the RGB-Values of input_color
Dim dbl_input_red As Double = Convert.ToDouble(input_color.R)
Dim dbl_input_green As Double = Convert.ToDouble(input_color.G)
Dim dbl_input_blue As Double = Convert.ToDouble(input_color.B)
' the Euclidean distance to be computed
' set this to an arbitrary number
' must be greater than the largest possible distance (appr. 441.7)
Dim distance As Double = 500.0
' store the interim result
Dim temp As Double
' RGB-Values of test colors
Dim dbl_test_red As Double
Dim dbl_test_green As Double
Dim dbl_test_blue As Double
' initialize the result
Dim nearest_color As Color = Color.Empty
For Each o As Object In WebColors
' compute the Euclidean distance between the two colors
' note, that the alpha-component is not used in this example
dbl_test_red = Math.Pow(Convert.ToDouble((CType(o, Color)).R) - dbl_input_red, 2.0)
dbl_test_green = Math.Pow(Convert.ToDouble((CType(o, Color)).G) - dbl_input_green, 2.0)
dbl_test_blue = Math.Pow(Convert.ToDouble((CType(o, Color)).B) - dbl_input_blue, 2.0)
temp = Math.Sqrt(dbl_test_blue + dbl_test_green + dbl_test_red)
' explore the result and store the nearest color
If temp < distance Then
distance = temp
nearest_color = CType(o, Color)
End If
Next o
' done :-)
Return nearest_color
End Function
''' <summary>
''' Returns an ArrayList filled with "WebColors"
''' </summary>
''' <returns>WebColors</returns>
''' <remarks>Many thanks to Julijan Sribar for his excellent article (http://www.codeproject.com/cs/miscctrl/MultiTabColorPicker.asp)</remarks>
Private Shared Function GetWebColors() As ArrayList
Dim color As Type = (GetType(Color))
Dim propertyInfos() As PropertyInfo = color.GetProperties(BindingFlags.Public Or BindingFlags.Static)
Dim colors As New ArrayList()
For Each pi As PropertyInfo In propertyInfos
If pi.PropertyType.Equals(GetType(Color)) Then
Dim c As Color = CType(pi.GetValue(CObj(GetType(Color)), Nothing), Color)
colors.Add(c)
End If
Next pi
Return colors
End Function
raffika Messages postés 269 Date d'inscription dimanche 31 mai 2009 Statut Membre Dernière intervention 12 mars 2011
14 juin 2010 à 15:53
Pour trouver la bonne image
je calcule la distance entre deux points
dans un tableau à trois dimensions
Les deux points sont défini avec
un axe X Y et Z, par exemple si la couleur
dominante est 255,120,89
et que la couleur recherchée est : 255,0,32
On compare les deux couleurs comme ceci :
Sqrt((255-255)² + (120-0)² + (89-32)²)
Sqrt(0 + 14400 + 3249)
= 132,84 (Sqrt correspond à Racine carré)
Comme ça après il suffit de trouver la distance la plus petite
entre ce qu'on recherche et les images qu'on a
pour avoir la couleur la plus proche du résultat...

salut
gillardg Messages postés 3275 Date d'inscription jeudi 3 avril 2008 Statut Membre Dernière intervention 14 septembre 2014 2
14 juin 2010 à 14:52
nombre d'images 2700
problème numéro 1
si on ne trouve pas la bonne couleur
alors utiliser couleur la plus proche parmi les couleurs connues KnowColors
raffika Messages postés 269 Date d'inscription dimanche 31 mai 2009 Statut Membre Dernière intervention 12 mars 2011
14 juin 2010 à 11:39
Bonjour,
Gillardg oui c'est pour faire ce genre
d'images sauf que sur celle de ton lien
il ne dois pas y avoir beaucoup d'images
différentes, car les couleurs me semblent mal
restituées... là je suis en train de tester
les limites de mon programme, la derniere image
que j'ai faite avait pour résolution 4096x3072...
salut
gillardg Messages postés 3275 Date d'inscription jeudi 3 avril 2008 Statut Membre Dernière intervention 14 septembre 2014 2
14 juin 2010 à 06:04
bonjour,
j'ai fait un prog dans le genre, au départ c'était pour faire des affiches, mais vu la limitation de 2^31 bytes pour une image sur un système 32bits je me suis dit que j'allais attendre d'avoir une bécane en 64bits
est ce que ça donne + - ce genre de résultat ???
http://gillardg.net/s/sigrid-mozaic.htm

j'utilise une fonction pour trouver une couleur proche s'il n'y a pas,dans ma librairie, d'image dont la couleur dominante correspond a un pixel donné
raffika Messages postés 269 Date d'inscription dimanche 31 mai 2009 Statut Membre Dernière intervention 12 mars 2011
13 juin 2010 à 11:34
Salut, je vais expliquer un peu comment utiliser mon programme :
Tout d'abord c'est un programme qui permet de faire des mosaiques
d'images avec plein de petites images (à voir de loin =) cf la capture)
Donc tout d'abord, il faut calculer toutes les images
que l'on souhaite utiliser dans la réalisation de la mosaique,
pour ce, il faut utiliser mon programme SampleFilter
qui utilise un BackroundWorker pour lire pixel
par pixel toutes les images puis faire un moyenne
de Rouge Vert et Bleu qui sera enregistrée dans
le fichier Rapport.txt avec le nom et chemin du fichier correspondant.
Il faut donc mettre toutes les images dans le sous
dossier Samples du programme SampleFilter
puis démarrer SampleFilter et là l'utilisation est
simple, il suffit de cliquer sur le gros bouton tout
en haut pour commencer le calcul,
le calcul est fait en tâche de fond et la
progression en pourcents est affichée...
Il ne reste plus qu'à attendre... A la fin le fichier
Rapport.txt est crée, il faut ensuite le copier
dans le dossier de Filter, puis lancer Filter et là
il suffit de charger une image avec le bouton
Charger une image puis une fois l'image chargée, cliquer
sur Faire une mosaique puis regarder la mosaique
se former petits carrés par petits carrés...
A la fin, la mosaique est prete, il ne vous
reste plus qu'à faire un capture d'écran (touche
Impr écran sur le clavier) et faire un coller
dans Paint, recadrer l'image puis l'enregistrer
si vous souhaitez garder la mosaique...
Adn56 Messages postés 1172 Date d'inscription jeudi 24 mai 2007 Statut Membre Dernière intervention 28 septembre 2013 1
13 juin 2010 à 08:23
Salut, tu peux expliquer un peu plus ce que fait ton code ? utilisation de base quoi ?
Sinon de ce que j'ai lu vite fait, je vois que tu utilise encore le VB6 dans ton code, le NET est pourtant pas plus dur (voir plus simple)
regarde cette exemple :
Tu ecris :
54. Dim oki = MsgBox("Astuce : Réduisez la taille des images peux accélérer grandement l'opération.", vbOKCancel)
55. If oki = vbCancel Then
56. GoTo endy
57. End If

En VB.NET il suffit de ça :
If MessageBox.Show("Astuce : Réduisez la taille des images", _
"Attention", MessageBoxButtons.OKCancel, MessageBoxIcon.Exclamation) _
= Windows.Forms.DialogResult.Cancel Then Exit Sub

cela tiens sur une ligne est c'est je trouve plus lisible.
Bonne prog, ++
Rejoignez-nous