Détection de contours rustique

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Avatar de l’utilisateur
Huitbit
Messages : 940
Inscription : jeu. 08/déc./2005 5:19
Localisation : Guadeloupe

Détection de contours rustique

Message par Huitbit »

Hello,

Petit programme sans grande prétention sur le traitement de l'image.
Depuis plusieurs mois, je fais du Java (stage éducation nationale).
Maintenant, je comprends mieux les ";{ ;}" dans Pb :mrgreen:
A un moment donné, on a fait mumuse avec les filtres.
Le filtre est ici une petite matrice 3x3 que l'on va appliquer à chaque pixel de l'image.
On stocke le résultat dans une autre matrice "imageFiltrée".
Je suis retombé sur un truc que G-Rom avait utilisé, le filtre de Sobel.
Comme j'en aurai besoin quand je reviendrai sur "Perlin", j'ai fait quelques tests.
J'ai mis en forme avec PBSyntax de LSI (Merci M'sieur)!

Normalement ça fonctionne.
N'hésitez pas à trifouiller dans le filtre pour modifier le résultat.
Si vous avez des questions ou des remarques...

Code : Tout sélectionner

;**********************************************************
;Détection des contours avec le filtre de Sobel
;Auteur Huitbit
;Février 2012
;PureBasic 4.60 (Windows - x86)
;***********************************************************

#facteurDeNormalisation = 5.657 ; 5.657 = 4*Sqr(2)  facteur de normalisation pour le filtre de Sobel  
;dans l'expression :
;imageFiltree(x, y) = Sqr(imageFiltreX(x, y) * imageFiltreX(x, y) + imageFiltreY(x, y) * imageFiltreY(x, y))/ #facteurDeNormalisation
;les valeurs maximales pour les composantes X et Y sont 4*255
; => sans normalisation, la valeur finale maximale serait sqr(4²*255² + 4²*255²) = sqr(2*4²*255²) = 4*sqr(2)*255
; valeur supérieure à 255 et donc incorrecte

;On applique à un élément M(i,j) de la matrice M() le filtre choisi et on met le résultat dans c(i,j)
;On renvoie tout ça au programme principal
Procedure ConvolutionParMatrice3x3(i.i, j.i, Array filtre.i(2), Array M.i(2))
	cij.i ; composante de matrice qui sera renvoyée au programme
	For l = -1 To 1 ; lignes
		For k = -1 To 1 ; colonnes
			cij = cij + filtre(l + 1, k + 1) * M(i + l, j + k)
		Next k
	Next l
	ProcedureReturn cij
EndProcedure

;-PROGRAMME PRINCIPAL

If OpenWindow(0, 100, 100, 800, 600, "PureBasic - Image")
  
  ;-chargement de l'image à filtrer
	title$ = "Choisissez une image au format JPEG, PNG ou BMP"
	image$ = OpenFileRequester(title$, "", "*.JPEG ; *.PNG ; *.BMP", 1, #PB_Requester_MultiSelection)
	UseJPEGImageDecoder()
	UsePNGImageDecoder()
	If image$<> ""
		LoadImage(0, image$)
		height = ImageHeight(0)
		width = ImageWidth(0)
		
		ResizeWindow(0, 100, 100, width, height)
		
		Dim imageTableau.i(width - 1, height - 1)
		Dim imageFiltrex.i(width - 1, height - 1)
		Dim imageFiltreY.i(width - 1, height - 1)
		Dim imageFiltree.i(width - 1, height - 1)
		
		;-Filtres de Sobel
		;--selon X
		Dim filtreX.i(2, 2)
		filtreX(0, 0) = 1
		filtreX(1, 0) = 2
		filtreX(2, 0) = 1
		filtreX(0, 1) = 0
		filtreX(1, 1) = 0
		filtreX(2, 1) = 0
		filtreX(0, 2) = -1
		filtreX(1, 2) = -2
		filtreX(2, 2) = -1
		;--selon Y
		Dim filtreY.i(2, 2)
		filtreY(0, 0) = 1
		filtreY(1, 0) = 0
		filtreY(2, 0) = -1
		filtreY(0, 1) = 2
		filtreY(1, 1) = 0
		filtreY(2, 1) = -2
		filtreY(0, 2) = 1
		filtreY(1, 2) = 0
		filtreY(2, 2) = -1
				
		;- transformation n/b
		StartDrawing(ImageOutput(0))
			For i = 0 To width - 1
				For j = 0 To height - 1
					imageTableau(i, j) = (Red(Point(i, j)) + Green(Point(i, j)) + Blue(Point(i, j))) / 3
				Next j
			Next i
		StopDrawing() ; This is absolutely needed when the drawing operations are finished !!! Never forget it !
		
		;- application des  filtres selon X et Y
		For x = 1 To width - 2
			For y = 1 To height - 2
				imageFiltreX(x, y) = ConvolutionParMatrice3x3(x, y, filtreX(), imageTableau())
				imageFiltreY(x, y) = ConvolutionParMatrice3x3(x, y, filtreY(), imageTableau())
				;-Image finale normalisée
				imageFiltree(x, y) = Sqr(imageFiltreX(x, y) * imageFiltreX(x, y) + imageFiltreY(x, y) * imageFiltreY(x, y)) / #facteurDeNormalisation
			
			Next y
		Next x
		
		;-Création de l'image filtrée (en réalité le négatif pour une meilleure visibilité(choix arbitraire)
		If CreateImage(1, width, height)
		  
			StartDrawing(ImageOutput(1))
				For i = 0 To width - 1
					For j = 0 To height - 1
						niv = imageFiltree(i, j)
						Box(i, j, 1, 1, RGB(255 - niv, 255 - niv, 255 - niv))
					Next j
				Next i
				
			StopDrawing()
		EndIf
	Else
		End
		
		
	EndIf
	
	Repeat
		EventID = WaitWindowEvent()
		
		If EventID = #PB_Event_Repaint
			StartDrawing(WindowOutput(0))
				DrawImage(ImageID(1), 0, 0)
			StopDrawing()
		EndIf
		
	Until EventID = #PB_Event_CloseWindow ; If the user has pressed on the close button
	
EndIf

End ; All the opened windows are closed automatically by PureBasic
Hasta la vista !
Dernière modification par Huitbit le mer. 11/avr./2012 18:41, modifié 1 fois.
Elevé au MSX !
lepiaf31
Messages : 510
Inscription : dim. 25/mars/2007 13:44
Localisation : Toulouse, France
Contact :

Re: Détection de contours rustique

Message par lepiaf31 »

Hum ca me rappel un des mes cours ca tiens =).
Ca à l'air interessant, je pense m'y plonger un peu plus demain.

GG :D
Avatar de l’utilisateur
Ar-S
Messages : 9540
Inscription : dim. 09/oct./2005 16:51
Contact :

Re: Détection de contours rustique

Message par Ar-S »

Le résultat est vraiment pas mal !
~~~~Règles du forum ~~~~
⋅.˳˳.⋅ॱ˙˙ॱ⋅.˳Ar-S ˳.⋅ॱ˙˙ॱ⋅.˳˳.⋅
W11x64 PB 6.x
Section HORS SUJET : ICI
LDV MULTIMEDIA : Dépannage informatique & mes Logiciels PB
UPLOAD D'IMAGES : Uploader des images de vos logiciels
Avatar de l’utilisateur
Kwai chang caine
Messages : 6989
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: Détection de contours rustique

Message par Kwai chang caine »

C'est vraiment splendide...j'suis toujours épaté par ce genre de code "magique". 8O
Marche nikel ici :wink:

Cette fois un petit peu moins, car j'avais déjà vu cet effet avec un code de ATHOW , il y a quelques années....
Alors attention, j'y connais rien en math donc je sais pas si c'est le même style de code, mais le resultat est sensiblement le meme
http://www.purebasic.fr/french/viewtopi ... 671#p62671

En attendant, vous et vos mathematiques, vous me faites rever, moi qui ai du mal a faire une addition sans faute :oops:
En plus on peut se la peter en disant qu'on a un peu de talent dans le dessin...on prend n'importe quelle photo et hop ...grace a vos deux codes...une imprimante....et leonard il a plus qu'a retourner jouer au legos :mrgreen:

Merci beaucoup du partage... 8)
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
Le Soldat Inconnu
Messages : 4312
Inscription : mer. 28/janv./2004 20:58
Localisation : Clermont ferrand OU Olsztyn
Contact :

Re: Détection de contours rustique

Message par Le Soldat Inconnu »

Terrible ce truc, faut que je zieute ça de plus près :D
Je ne suis pas à moitié Polonais mais ma moitié est polonaise ... Vous avez suivi ?

[Intel quad core Q9400 2.66mhz, ATI 4870, 4Go Ram, XP (x86) / 7 (x64)]
Avatar de l’utilisateur
Cool Dji
Messages : 1126
Inscription : ven. 05/sept./2008 11:42
Localisation : Besançon
Contact :

Re: Détection de contours rustique

Message par Cool Dji »

Yeah, bravo Huitbit => ça peut faire des effets sympa dans un jeu en faisant clignoter un écran avec image normale et l'image épurée-calculée :D
Only PureBasic makes it possible
Avatar de l’utilisateur
Huitbit
Messages : 940
Inscription : jeu. 08/déc./2005 5:19
Localisation : Guadeloupe

Re: Détection de contours rustique

Message par Huitbit »

Hugh !

Tant mieux si ça peut servir :D .
Avec des pointeurs(façon G-Rom), ce n'est pas beaucoup plus dur est c'est plus rapide (vu que je l'utiliserai pour des cartes créées avec Perlin) !

@KCC, c'est bien le même principe.

L'idée de départ est assez simple.
On calcule un gradient(grossièrement la manière dont une composante (ou pour le code ci-dessus, le niveau de gris) varie) sur une zone de 3x3 pixels
puis on garde la valeur moyenne à l'emplacement du pixel central.

Exemple :
Soient a, b ,c ,d ,e et f , 9 valeurs allant de 0 à 255
Le pixel traité correspond à la valeur e.

a b c
d e f
g h i

La variation de valeur par rapport à l'horizontale est (f - d) / 2 ("2" car le calcul de la variation se fait sur une distance de 2 pixels)
Si on passe du noir au blanc, on aura (255 - 0 ) / 2
Du blanc au noir, on aura une valeur négative (0 - 255) /2.
En fait, c'est la valeur approchée de la dérivé en math.
Le filtre va travailler simultanément sur les 3 lignes.
A l'emplacement de e, on affectera la valeur (c - a) / 2 + (f - d) / 2 + (i - g) / 2
Un filtre qui calcule le gradient peut donc s'écrire :
-1/2 0 1/2
-1/2 0 1/2
-1/2 0 1/2

Car avec un calcul approprié (attention, ce n'est pas un produit de matrice classique)
on a bien la valeur cherchée eFiltré = -1/2*a + 0*b + 1/2*c - 1/2*d + 0*e +.........
Ensuite, il faut normaliser car si on veut une image, les valeurs ne doivent pas dépasser 255.
Ici, la valeur maximale peut être 3 * 255/2.
Pour normaliser, on va diviser par 3/2

Vu que l'on normalise, on peut très bien travailler avec des entiers positifs :
-1 0 1
-1 0 1
-1 0 1
puis diviser par trois (1 + 1 + 1 = 3) pour normaliser.

Le filtre de Sobel insiste sur ligne principale en mettant un 2
-1 0 1
-2 0 2
-1 0 1
On normalise en divisant par 1 + 2 + 1 = 4

En conjugant les filtres selon l'horizontale et la verticale (Rappel : calcul de la norme d'un vecteur : l = Sqr(x ² + y ²)), on obtient le résultat final.
Remarque : on peut voir que le filtre suivant(celui utilisé dans le code !) donne la même chose après la normalisation
1 0 -1
2 0 -2
1 0 -1


Voilà, c'était pour faire avancer le schmilblick !


Hasta la vista !
Il existe toutes sortes de filtres (en diagonale, ...).
Dernière modification par Huitbit le mer. 11/avr./2012 14:53, modifié 1 fois.
Elevé au MSX !
lepiaf31
Messages : 510
Inscription : dim. 25/mars/2007 13:44
Localisation : Toulouse, France
Contact :

Re: Détection de contours rustique

Message par lepiaf31 »

Pourrais-tu m'éclairer sur une ligne :

Code : Tout sélectionner

imageFiltree(x, y) = Sqr(imageFiltreX(x, y) * imageFiltreX(x, y) + imageFiltreY(x, y) * imageFiltreY(x, y)) / 4
Le sqr(...) c'est une la norme mais je ne comprends pas le '/4'.
Avatar de l’utilisateur
Huitbit
Messages : 940
Inscription : jeu. 08/déc./2005 5:19
Localisation : Guadeloupe

Re: Détection de contours rustique

Message par Huitbit »

Hi,

Je divise par quatre car je n'ai pas normalisé les deux matrices filtreX et filtreY.
En effet la valeur maximale possible est 4*255 pour chaque filtre
Pour faire les choses proprement j'aurai dû diviser par sqr(4²+4²) c'est à dire 4*sqr(2).

Bien vu !
Dernière modification par Huitbit le mer. 11/avr./2012 15:02, modifié 1 fois.
Elevé au MSX !
lepiaf31
Messages : 510
Inscription : dim. 25/mars/2007 13:44
Localisation : Toulouse, France
Contact :

Re: Détection de contours rustique

Message par lepiaf31 »

HA oui très juste autant pour moi =)
Merci ! =)
Avatar de l’utilisateur
Huitbit
Messages : 940
Inscription : jeu. 08/déc./2005 5:19
Localisation : Guadeloupe

Re: Détection de contours rustique

Message par Huitbit »

Re Hugh !

Le plus propre, c'est de normaliser au fur et à mesure les matrices.

Sinon c'est 4*sqr(2) !
(Si tu divises seulement par 4 la matrice finale, tu peux avoir des valeurs supérieures à 255)

Le plus pratique, c'est d'ajuster le coefficient en fonction de la valeur maximale obtenue et du résultat souhaité.

Hasta la vista !
Elevé au MSX !
Avatar de l’utilisateur
Kwai chang caine
Messages : 6989
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: Détection de contours rustique

Message par Kwai chang caine »

Merci pour toutes ces explications.
Y'a pas a tortiller du... pour chi..droit...la bosse des math on l'a ou on l'a pas.
Moi je l'ai eu à force de me tater sur la tete...mais celle la...ell m'a jamais aidé :lol:

En tout cas encore bravo 8)
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
Avatar de l’utilisateur
Huitbit
Messages : 940
Inscription : jeu. 08/déc./2005 5:19
Localisation : Guadeloupe

Re: Détection de contours rustique

Message par Huitbit »

Petite correction suite à la remarque de Lepiaf31

Code : Tout sélectionner

#facteurDeNormalisation = 5.657 ; 5.657 = 4*Sqr(2)  facteur de normalisation pour le filtre de Sobel  
;dans l'expression :
;imageFiltree(x, y) = Sqr(imageFiltreX(x, y) * imageFiltreX(x, y) + imageFiltreY(x, y) * imageFiltreY(x, y)) / #facteurDeNormalisation
;les valeurs maximales pour les composantes X et Y sont 4*255
; => sans normalisation, la valeur finale maximale serait sqr(4²*255² + 4²*255²) = sqr(2*4²*255²) = 4*sqr(2)*255
; valeur supérieure à 255 et donc incorrecte
Hasta la vista !
Elevé au MSX !
lepiaf31
Messages : 510
Inscription : dim. 25/mars/2007 13:44
Localisation : Toulouse, France
Contact :

Re: Détection de contours rustique

Message par lepiaf31 »

Et autre chose: pourquoi calculer la norme pour l'image finale et pas simplement une bête moyenne des deux valeurs ? (je ne sais pas si je suis clair ^^ )
Avatar de l’utilisateur
Huitbit
Messages : 940
Inscription : jeu. 08/déc./2005 5:19
Localisation : Guadeloupe

Re: Détection de contours rustique

Message par Huitbit »

Hugh !

Car tu travailles avec des vecteurs (une dimension selon X, l'autre selon Y), seule la norme tient compte du sens et de la direction des vecteurs !

Hasta la vista !
Elevé au MSX !
Répondre