Pour les matheux ..se contruire un mini OCR

Vous débutez et vous avez besoin d'aide ? N'hésitez pas à poser vos questions
Avatar de l’utilisateur
Kwai chang caine
Messages : 6989
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Pour les matheux ..se contruire un mini OCR

Message par Kwai chang caine »

Bonjour à tous,

Voila j'aimerais essayer de me faire un petit code qui essaie de reconnaître les lettres et chiffres d'une image.
En fait pour simplifier les choses, j'avais pensé couper les phrases en minuscules images ne contenant qu'une seule petite lettre.
Je me suis dit que ce serait peut être plus rapide et facile
Donc, je me retrouve avec une image en BMP et je voudrais essayer de lire pixel/pixel pour essayer de savoir quelle lettre c'est.

Quelqu'un a des idées de départ, y'a t'il un algo de matheu comme j'en connait pas pour effectuer cette tache...
Ce qui facilite ma tache c'est que la police est toujours la même, par contre elle est pas toujours de la même taille c'est ce qui complique l'affaire.

J'avais essayé avec ce code de DarkDragon qui marche super bien
http://www.purebasic.fr/english/viewtop ... 78#p374278
Mais comme les caractères n'ont pas la même taille, le code ne retrouve pas un "2" par exemple si il est 1% plus gros ou autre
J'ai essayé le resize mais apparemment ça doit déformer l'image légèrement et le code ne reconnait que les "1", normal, un 1 plus petit c'est toujours une barre

Alors j'en sais rien, peut etre mettre le caractère a rechercher dans une matrice, et le caractère témoin dans une autre...et comparer les tableaux..c'est ma première idée

Merci et bonne journée
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
G-Rom
Messages : 3641
Inscription : dim. 10/janv./2010 5:29

Re: Pour les matheux ..se contruire un mini OCR

Message par G-Rom »

je vais faire comme sph, de l'ultra condensé : perceptron
Avatar de l’utilisateur
Mindphazer
Messages : 695
Inscription : mer. 24/août/2005 10:42

Re: Pour les matheux ..se contruire un mini OCR

Message par Mindphazer »

Bureau : Win10 64bits
Maison : Macbook Pro M3 16" SSD 512 Go / Ram 24 Go - iPad Pro 32 Go (pour madame) - iPhone 15 Pro Max 256 Go
Frenchy Pilou
Messages : 2194
Inscription : jeu. 27/janv./2005 19:07

Re: Pour les matheux ..se contruire un mini OCR

Message par Frenchy Pilou »

Pour tester ses résultats: système d'OCR gratuit en ligne! ;)
http://www.free-ocr.com/

... et vous verrez que le système de Captcha du lien ci-dessus est aussi un système de reconnaissance de caractères, mais là c'est vous le système de reconnaissance! :D
la théorie!
http://www.youtube.com/watch?v=-Ht4qiDRZE8
Est beau ce qui plaît sans concept :)
Speedy Galerie
Avatar de l’utilisateur
graph100
Messages : 1318
Inscription : sam. 21/mai/2005 17:50

Re: Pour les matheux ..se contruire un mini OCR

Message par graph100 »

Bonjour KCC,

il y à de ça 3 mois j'ai codé un truc pour tester mes connaissances de cours pour un cours de modélisation avancée avec des réseaux de neurones.
Ca ne fonctionne pas super, et l'apprentissage n'est pas forcé d'arriver à un résultat mais voila :

En gros tu créés ta base d'exemple a apprendre, ensuite tu définies la taille du réseau de neurone, puis tu effectues l'apprentissage jusqu'à ce que les résultats soient acceptables.

En fin de compte tu peux dégrader les exemples de la base d'apprentissage et regarder si le réseau les reconstruit correctement... Ce n'est pas vraiment de l'ocr, mais plutôt un début.

Un des problèmes des ces techniques d'ocr consiste à isolé les caractères pour les soumettre à l’algorithme de reconnaissance.
C'est complexe, et il faut plein d'hypothèse sur la position des caractères etc... Il y a un paquet de théorie à maitriser avant.

Code : Tout sélectionner

UsePNGImageDecoder()
UsePNGImageEncoder()


;{ structure

CompilerIf #PB_Compiler_OS <> #PB_OS_Windows
	#White = 16777215
CompilerEndIf


Structure BaseApprentissage_Exemple
	List Entree.l()
EndStructure

Structure BaseApprentissage
	List Exemple.BaseApprentissage_Exemple()
	
	NombreEntree.l
	
	IS_Memory.b
EndStructure

Structure Neurone
	List PoidsEntree.d()
	
	Seuil.d
	
	IS_Memory.b
EndStructure


Structure MemoireAssociative
	List Neurone.Neurone()
	
	IS_Memory.b
EndStructure



;}

;{ variables

Global WD_Window_0

Global GD_ListIcon_0
Global GD_Image_0, GD_Image_1
Global GD_Text_0, GD_Text_1, GD_Text_2, GD_Text_3, GD_Text_4, GD_Text_5, GD_Text_6, GD_Text_7, GD_Text_8, GD_Text_9
Global GD_Frame3D_0, GD_Frame3D_1, GD_Frame3D_2
Global GD_Button_0, GD_Button_1, GD_Button_2, GD_Button_3, GD_Button_4, GD_Button_5, GD_Button_6
Global GD_String_0, GD_String_1, GD_String_2, GD_String_3, GD_String_4, GD_String_5, GD_String_6
Global GD_Canvas_0
Global GD_Editor_0

Global IMG_canvas.l, Canvas_RATIO.d, Canvas_W, Canvas_H

;}


;{ macro générale

Macro Message(Message)
	AddGadgetItem(GD_Editor_0, 0, "[" + FormatDate("%hh:%ii:%ss", Date()) + "] - " + Message)
EndMacro

;}


;{ procedures neuronales

EnableExplicit

Procedure.i CreationBaseApprentissage(NombreEntree.l, *NouvelleBase.BaseApprentissage = 0)
	Protected IS_memory.b
	
	If *NouvelleBase = 0
		*NouvelleBase = AllocateMemory(SizeOf(BaseApprentissage))
		
		IS_memory = #True
	EndIf
	
	InitializeStructure(*NouvelleBase, BaseApprentissage)
	*NouvelleBase\IS_Memory = IS_memory
	*NouvelleBase\NombreEntree = NombreEntree
	
	ProcedureReturn *NouvelleBase
EndProcedure

Procedure FreeBaseApprentissage(*Base.BaseApprentissage)
	ForEach *base\Exemple()
		FreeList(*Base\Exemple()\Entree())
	Next
	
	FreeList(*Base\Exemple())
	
	If *Base\IS_Memory
		FreeMemory(*Base)
	EndIf
EndProcedure

Procedure Ajout_Exemple_Apprentissage(*Base.BaseApprentissage, Image)
	Protected x.l, y.l
	
	If IsImage(Image) = 0
		Message("ERREUR Ajout Exemple d'apprentissage : l'image n'est pas correctement initialisée")
		
		ProcedureReturn #False
	EndIf
	
	If *Base\NombreEntree <> ImageWidth(Image) * ImageHeight(Image)
		Message("ERREUR Ajout Exemple d'apprentissage : Le nb d'entrée est différent du produit W*H de l'image")
		
		ProcedureReturn #False
	EndIf
	
	AddElement(*Base\Exemple())
	InitializeStructure(*Base\Exemple(), BaseApprentissage_Exemple)
	
	
	If StartDrawing(ImageOutput(Image))
			For x = 0 To ImageWidth(Image) - 1
				For y = 0 To ImageHeight(Image) - 1
					AddElement(*Base\Exemple()\Entree())
					
					If Point(x, y) = 0 ; noir
						*Base\Exemple()\Entree() = -1
					Else
						*Base\Exemple()\Entree() = 1
					EndIf
				Next
			Next
			
		StopDrawing()
	EndIf
	
	ProcedureReturn #True
EndProcedure


Procedure.i CreationNeurone(NombreEntree.l, Seuil.d, Hazard.b, *NouveauNeurone.Neurone = 0)
	Protected i, IS_memory.b
	
	If *NouveauNeurone = 0
		*NouveauNeurone = AllocateMemory(SizeOf(Neurone))
		
		IS_memory = #True
	EndIf
	
	InitializeStructure(*NouveauNeurone, Neurone)
	*NouveauNeurone\Seuil = Seuil
	*NouveauNeurone\IS_Memory = IS_memory
	
	For i = 1 To NombreEntree
		AddElement(*NouveauNeurone\PoidsEntree())
		
		If Hazard
			*NouveauNeurone\PoidsEntree() = (Random(20) - 10) / 10
		EndIf
	Next
	
	ProcedureReturn *NouveauNeurone
EndProcedure

Procedure FreeNeurone(*Neurone.Neurone)
	FreeList(*Neurone\PoidsEntree())
	
	If *Neurone\IS_Memory
		FreeMemory(*Neurone)
	EndIf
EndProcedure

;{ Mono Neurone

; Procedure Apprentissage_MonoNeurone(*Neurone.Neurone, *Base.BaseApprentissage, correcteur_nu.d, IterationMaximum.l = 100)
; 	Protected PasdErreur.b, SortieObtenue.d, x.b, Iteration.l
; 	
; 	Repeat
; 		PasdErreur = #True
; 		
; 		ForEach *Base\Exemple()
; 			SortieObtenue = - *Neurone\Seuil
; 			
; 			If ListSize(*Neurone\PoidsEntree()) <> ListSize(*Base\Exemple()\Entree())
; 				Debug "ERREUR : Nombre d'entrée différents du nombre de poids"
; 				ProcedureReturn #False
; 			EndIf
; 			
; 			ResetList(*Neurone\PoidsEntree())
; 			ForEach *Base\Exemple()\Entree()
; 				NextElement(*Neurone\PoidsEntree())
; 				SortieObtenue = SortieObtenue + *Neurone\PoidsEntree() * *base\Exemple()\Entree()
; 			Next
; 			
; 			If SortieObtenue > 0
; 				x = 1
; 			Else
; 				x = -1
; 			EndIf
; 			
; 			Debug "Exemple " + Str(ListIndex(*base\Exemple()) + 1) + " :  x = " + Str(x) + "   Sortie désirée = " + *base\Exemple()\Sortie_desiree + "  Obtenue = " + SortieObtenue
; 			
; 			If x <> *Base\Exemple()\Sortie_desiree
; 				; modification des poids
; 				PasdErreur = #False
; 				
; 				Debug "Modification des poids :"
; 				
; 				ResetList(*Base\Exemple()\Entree())
; 				ForEach *Neurone\PoidsEntree()
; 					NextElement(*Base\Exemple()\Entree())
; 					*Neurone\PoidsEntree() = *Neurone\PoidsEntree() + correcteur_nu * *Base\Exemple()\Entree() * (*base\Exemple()\Sortie_desiree - x)
; 					
; 					Debug "w" + Str(ListIndex(*Neurone\PoidsEntree())+1) + " = " + *Neurone\PoidsEntree()
; 				Next
; 				; correction du seuil pour une convergence plus rapide
; 				*Neurone\Seuil = *Neurone\Seuil - correcteur_nu * (*base\Exemple()\Sortie_desiree - x)
; 				Debug "Seuil = " + *Neurone\Seuil
; 				
; 			Else
; 				; rien, on passe à l'exemple suivant !
; 			EndIf
; 			
; 		Next
; 		
; 		Iteration + 1
; 	Until PasdErreur = #True Or Iteration >= IterationMaximum
; 	
; 	ProcedureReturn PasdErreur
; EndProcedure
; 
; Procedure Reponse_MonoNeurone(*Neurone.Neurone, Sequence$)
; 	Protected SortieObtenue.d, Nb.l
; 	
; 	Nb = CountString(Sequence$, ",")
; 	
; 	If Nb + 1 <> ListSize(*Neurone\PoidsEntree())
; 		ProcedureReturn 0 ; pas de calcul
; 	EndIf
; 	
; 	SortieObtenue = - *Neurone\Seuil
; 	ForEach *Neurone\PoidsEntree()
; 		SortieObtenue = SortieObtenue + *Neurone\PoidsEntree() * Val(StringField(Sequence$, ListIndex(*Neurone\PoidsEntree()) + 1, ","))
; 	Next
; 	
; 	If SortieObtenue > 0
; 		ProcedureReturn 1
; 	Else
; 		ProcedureReturn -1
; 	EndIf
; EndProcedure
; 
;}

Procedure.i CreationMemoireAssociative(NombreNeurones, NombreEntreeParNeurone, *NouvelleMemoireAssociative.MemoireAssociative = 0)
	Protected i, IS_memory.b
	
	If *NouvelleMemoireAssociative = 0
		*NouvelleMemoireAssociative = AllocateMemory(SizeOf(MemoireAssociative))
		
		IS_memory = #True
	EndIf
	
	InitializeStructure(*NouvelleMemoireAssociative, MemoireAssociative)
	*NouvelleMemoireAssociative\IS_Memory = IS_memory
	
	For i = 1 To NombreNeurones
		AddElement(*NouvelleMemoireAssociative\Neurone())
		
		CreationNeurone(NombreEntreeParNeurone, 0, #False, *NouvelleMemoireAssociative\Neurone())
	Next
	
	Message("Memoire Associative Créée - " + Str(NombreNeurones) + " Neurones à " + Str(NombreEntreeParNeurone) + " Entrées")
	
	ProcedureReturn *NouvelleMemoireAssociative
EndProcedure

Procedure FreeMemoireAssociative(*MemoireAssociative.MemoireAssociative)
	ForEach *MemoireAssociative\Neurone()
		FreeNeurone(*MemoireAssociative\Neurone())
	Next
	
	FreeList(*MemoireAssociative\Neurone())
	
	If *MemoireAssociative\IS_Memory
		FreeMemory(*MemoireAssociative)
	EndIf
EndProcedure


Procedure Apprentissage_MemoireAssociative(*MemoireAssociative.MemoireAssociative, *Base.BaseApprentissage, Pas_ModificationPoids.d = 0.2, CycleOut = 100)
	Protected Erreur, Resultat.d, x_bool.b, entre_bool.b, Cycle.l, time, text$
	Protected res.l ;, avant.d
	
	FirstElement(*MemoireAssociative\Neurone())
	If ListSize(*MemoireAssociative\Neurone()\PoidsEntree()) <> *base\NombreEntree
		Message("ERREUR : Le nombre des entrées de la Base d'apprentissage n'est pas celui prévu pour cette mémoire.")
		
		ProcedureReturn -1
	EndIf
	
	; initialisation des poids
	ForEach *MemoireAssociative\Neurone()
		ForEach *MemoireAssociative\Neurone()\PoidsEntree()
			*MemoireAssociative\Neurone()\PoidsEntree() = 0 ; (-Random(20) + 10) / 100
		Next
		
		*MemoireAssociative\Neurone()\Seuil = 2
	Next
	
	Message("######## Début de l'apprentissage")
	
	time = ElapsedMilliseconds()
	
	Protected NewList erreur()
	
	Repeat
		Erreur = #False
		Cycle + 1
		
		If ElapsedMilliseconds() - time > 500
			While WindowEvent() : Wend
			time = ElapsedMilliseconds()
		EndIf
		
		Message("## Cycle : " + Str(Cycle))
		
		
		ForEach *Base\Exemple()
			
			Message("## # Exemple : " + Str(ListIndex(*Base\Exemple())))
			
			
			ClearList(erreur())
			
			ForEach *MemoireAssociative\Neurone()
; 				Message("## # # Neurone : " + Str(ListIndex(*MemoireAssociative\Neurone())))
				
				Resultat = - *MemoireAssociative\Neurone()\Seuil
				
				ResetList(*Base\Exemple()\Entree())
				ForEach *MemoireAssociative\Neurone()\PoidsEntree()
					NextElement(*Base\Exemple()\Entree())
					
					Resultat = Resultat + *Base\Exemple()\Entree() * *MemoireAssociative\Neurone()\PoidsEntree()
				Next
				
				If Resultat > 0
					x_bool = 1
				Else
					x_bool = -1
				EndIf
				
				; test du résultat par rapport à l'état voulu :
				SelectElement(*base\Exemple()\Entree(), ListIndex(*MemoireAssociative\Neurone())) ; correspondance Neurone / Entrée
				
				
; 				Message("Etat = " + Str(x_bool) + "  Sortie désirée = " + Str(entre_bool))
				
				If x_bool <> *base\Exemple()\Entree() ; Erreur, on procède à la correction de la valeur des Poids
					Erreur = #True
; 					Message("Correction")
					
					AddElement(erreur())
					erreur() = ListIndex(*MemoireAssociative\Neurone())
					
					ResetList(*base\Exemple()\Entree())
					ForEach *MemoireAssociative\Neurone()\PoidsEntree()
						NextElement(*Base\Exemple()\Entree())
						
						*MemoireAssociative\Neurone()\PoidsEntree() = *MemoireAssociative\Neurone()\PoidsEntree() - Pas_ModificationPoids * *Base\Exemple()\Entree() * x_bool
					Next
				EndIf
				
			Next
			
			text$ = ""
			ForEach erreur()
				text$ = text$ + ", " + Str(erreur())
			Next
			Message("Neurones corrigés : " + Mid(text$, 3, Len(text$)))
			
		Next
	Until Erreur = #False Or Cycle >= CycleOut
	
	Message("######## Fin de l'apprentissage")
	
	If erreur	= #False
		ProcedureReturn 0
	EndIf
	
	ProcedureReturn Cycle
EndProcedure

Procedure CalculReponse(*MemoireAssociative.MemoireAssociative, Image)
	Protected x.l, y.l, Resultat.d, x_bool.b, Image_res
	
	If IsImage(Image) = 0
		Message("ERREUR Calcul Réponse : l'image n'est pas correctement initialisée")
		
		ProcedureReturn -1
	EndIf
	
	FirstElement(*MemoireAssociative\Neurone())
	If ListSize(*MemoireAssociative\Neurone()\PoidsEntree()) <> ImageWidth(Image) * ImageHeight(Image)
		Message("ERREUR Calcul Réponse : Le nb d'entrée est différent du produit W*H de l'image")
		
		ProcedureReturn -1
	EndIf
	
	Protected NewList Image()
	
	If StartDrawing(ImageOutput(Image))
			For x = 0 To ImageWidth(Image) - 1
				For y = 0 To ImageHeight(Image) - 1
					AddElement(Image())
					
					If Point(x, y) = 0 ; noir
						Image() = -1
					Else
						Image() = 1
					EndIf
				Next
			Next
			
		StopDrawing()
	EndIf
	
	
	Protected NewList Image_res()
	
	ForEach *MemoireAssociative\Neurone()
		; 				Message("## # # Neurone : " + Str(ListIndex(*MemoireAssociative\Neurone())))
		
		Resultat = - *MemoireAssociative\Neurone()\Seuil
		
		ResetList(Image())
		ForEach *MemoireAssociative\Neurone()\PoidsEntree()
			NextElement(Image())
			
			Resultat = Resultat + Image() * *MemoireAssociative\Neurone()\PoidsEntree()
		Next
		
		If Resultat > 0
			x_bool = 1
		Else
			x_bool = -1
		EndIf
		
		AddElement(Image_res())
		Image_res() = x_bool
	Next
	
	Image_res = CreateImage(#PB_Any, ImageWidth(Image), ImageHeight(Image))
	
	ResetList(Image_res())
	StartDrawing(ImageOutput(Image_res))
		For x = 0 To ImageWidth(Image) - 1
			For y = 0 To ImageHeight(Image) - 1
				NextElement(Image_res())
				
				If Image_res() = -1 ; noir
					Plot(x, y, 0)
				Else
					Plot(x, y, #White)
				EndIf
			Next
		Next
	StopDrawing()
	
	ProcedureReturn Image_res
EndProcedure


;}


;{ procedure interface

Procedure ChargementImageDATA(file$); retourne le nb d'images chargées
	Protected file_ID, nb, erreur, i, taille, *mem, img_ID, Nom$
	
	file_ID = OpenFile(#PB_Any, file$)
	
	If file_ID = 0
		MessageRequester("Chargement des données Image", "Le fichier " + file$ + " n'a pu être ouvert." + #CR$ + "Rien n'a été chargé")
		ProcedureReturn #False
	EndIf
	
	
	ClearGadgetItems(GD_ListIcon_0)
	
	nb = ReadLong(file_ID)
	
	For i = 1 To nb
		taille = ReadLong(file_ID)
		
		If taille = 0
			erreur + 1
		Else
			*mem = AllocateMemory(taille, #PB_Memory_NoClear)
			
			If *mem = 0
				erreur + 1
			Else
				Nom$ = ReadString(file_ID)
				ReadData(file_ID, *mem, taille)
				
				img_ID = CatchImage(#PB_Any, *mem)
				FreeMemory(*mem)
				
				If img_ID = 0
					erreur + 1
				Else
					AddGadgetItem(GD_ListIcon_0, -1, Nom$, ImageID(img_ID))
					SetGadgetItemData(GD_ListIcon_0, CountGadgetItems(GD_ListIcon_0) - 1, img_ID)
					
				EndIf
			EndIf
			
		EndIf
	Next
	
	CloseFile(file_ID)
	
	ProcedureReturn nb - erreur
EndProcedure

Procedure SauvegardeImageDATA(file$)
	Protected nb, file_ID, i, *mem, erreur, img
	
	file_ID = CreateFile(#PB_Any, file$)
	
	If file_ID = 0
		MessageRequester("Sauvegarde des Données Images", "Impossible de créer le fichier" + #CR$ + file$)
		ProcedureReturn #False
	EndIf
	
	; écriture du nb d'image
	nb = CountGadgetItems(GD_ListIcon_0) - 1
	WriteLong(file_ID, nb + 1)
	
	For i = 0 To nb
		img = GetGadgetItemData(GD_ListIcon_0, i)
		
		If IsImage(img) = 0
			erreur + 1
		Else
			*mem = EncodeImage(img, #PB_ImagePlugin_PNG)
			
			If *mem = 0
				erreur + 1
			Else
				WriteLong(file_ID, MemorySize(*mem))
				WriteStringN(file_ID, GetGadgetItemText(GD_ListIcon_0, i))
				
				WriteData(file_ID, *mem, MemorySize(*mem))
			EndIf
		EndIf
	Next
	
	; on tient compte des erreurs de sauvegarde possibles
	FileSeek(file_ID, 0)
	WriteLong(file_ID, nb + 1 - erreur)
	
	CloseFile(file_ID)
	
	ProcedureReturn nb + 1 - erreur
EndProcedure


Procedure MiseAJour_TailleCanvas(NePasToucherImage = #False)
	Protected w, h, ratio.d, Canvas_0_w, Canvas_0_h
	
	;{ taille et protections
	w = Val(GetGadgetText(gd_string_2))
	h = Val(GetGadgetText(GD_String_3))
	
	If IsImage(IMG_canvas)
		If w = Canvas_W And h = Canvas_H
			ProcedureReturn #False
		EndIf
	EndIf
	
	If w < 1 : w = 1 : EndIf
	If h < 1 : h = 1 : EndIf
	If w > 100 : w = 100 : EndIf
	If h > 100 : h = 100 : EndIf
	
	SetGadgetText(GD_String_2, Str(w))
	SetGadgetText(GD_String_3, Str(h))
	;}
	
	ratio = w / h
	Canvas_W = w
	Canvas_H = h
	
	If ratio > 1
		Canvas_0_w = 220
		Canvas_0_h = 220 / ratio
	Else
		Canvas_0_h = 220
		Canvas_0_w = 220 * ratio
	EndIf
	
	Canvas_RATIO = Canvas_0_w / w
	
	ResizeGadget(GD_Canvas_0, 340 + 110 - Canvas_0_w / 2, 50 + 110 - Canvas_0_h / 2, Canvas_0_w, Canvas_0_h)
	
	If NePasToucherImage = #False
		If IsImage(IMG_canvas)
			FreeImage(IMG_canvas)
		EndIf
		
		IMG_canvas = CreateImage(#PB_Any, w, h)
		
		StartDrawing(ImageOutput(IMG_canvas))
			Box(0, 0, w, h, #White)
		StopDrawing()
		StartDrawing(CanvasOutput(GD_Canvas_0))
			Box(0, 0, Canvas_0_w, Canvas_0_h, #White)
		StopDrawing()
	EndIf
EndProcedure

Procedure MiseAJour_ImageCanvas(image)
	Protected x, y
	
	If IsImage(image) = 0
		ProcedureReturn #False
	EndIf
	
	SetGadgetText(GD_String_2, Str(ImageWidth(IMG_canvas)))
	SetGadgetText(GD_String_3, Str(ImageHeight(IMG_canvas)))
	
	MiseAJour_TailleCanvas(#True)
	
	
	Protected Dim tableau(ImageWidth(image) - 1, ImageHeight(image) - 1)
	StartDrawing(ImageOutput(image))
		For x = 0 To ImageWidth(image) - 1
			For y = 0 To ImageHeight(image) - 1
				tableau(x, y) = Point(x, y)
			Next
		Next
	StopDrawing()
	
	StartDrawing(CanvasOutput(GD_Canvas_0))
		For x = 0 To ImageWidth(image) - 1
			For y = 0 To ImageHeight(image) - 1
				Box(x * Canvas_RATIO, y * Canvas_RATIO, Round(Canvas_RATIO, #PB_Round_Up), Round(Canvas_RATIO, #PB_Round_Up), tableau(x, y))
			Next
		Next
	StopDrawing()
	
EndProcedure

Procedure MiseAJour_DessinCanvas()
	Protected mouse.POINT, color
	
	If IsImage(IMG_canvas) = 0
		MiseAJour_TailleCanvas()
	EndIf
	
	
	If GetGadgetAttribute(GD_Canvas_0, #PB_Canvas_Buttons) & #PB_Canvas_LeftButton = #PB_Canvas_LeftButton
		color = 0
	ElseIf GetGadgetAttribute(GD_Canvas_0, #PB_Canvas_Buttons) & #PB_Canvas_RightButton = #PB_Canvas_RightButton
		color = #White
	Else
		ProcedureReturn #False
	EndIf
	
	mouse\x = GetGadgetAttribute(GD_Canvas_0, #PB_Canvas_MouseX)
	mouse\y = GetGadgetAttribute(GD_Canvas_0, #PB_Canvas_MouseY)
	
	; 	If mouse\x < 0 : mouse\x = 0 : EndIf
	; 	If mouse\y < 0 : mouse\y = 0 : EndIf
	; 	If mouse\x > GadgetWidth(GD_Canvas_0) : mouse\x = GadgetWidth(GD_Canvas_0) : EndIf
	; 	If mouse\y > GadgetHeight(GD_Canvas_0) : mouse\y = GadgetHeight(GD_Canvas_0) : EndIf
	
	mouse\x = Round(mouse\x / Canvas_RATIO, #PB_Round_Down)
	mouse\y = Round(mouse\y / Canvas_RATIO, #PB_Round_Down)
	
	If mouse\x >= ImageWidth(IMG_canvas) : mouse\x = ImageWidth(IMG_canvas) - 1: EndIf
	If mouse\y >= ImageHeight(IMG_canvas) : mouse\y = ImageHeight(IMG_canvas) - 1 : EndIf
	
	If StartDrawing(ImageOutput(IMG_canvas))
			Plot(mouse\x, mouse\y, color)
			
		StopDrawing()
	EndIf
	
	If StartDrawing(CanvasOutput(GD_Canvas_0))
			Box(mouse\x * Canvas_RATIO, mouse\y * Canvas_RATIO, Round(Canvas_RATIO, #PB_Round_Up), Round(Canvas_RATIO, #PB_Round_Up), color)
			
; 			DrawImage(ImageID(IMG_canvas), 0, 0)
		StopDrawing()
	EndIf
	
	ProcedureReturn #True
EndProcedure


Procedure MiseAJour_Image(Gadget, image, pos_x, pos_y, largeur_cote)
	Protected x, y, image_old, ratio.d, Image_w, Image_h, RATIO_petit_grand.d
	
	If IsImage(image) = 0
		ProcedureReturn #False
	EndIf
	
	image_old = GetGadgetData(Gadget)
	If IsImage(image_old)
		FreeImage(image_old)
	EndIf
	
	Protected Dim tableau(ImageWidth(image) - 1, ImageHeight(image) - 1)
	StartDrawing(ImageOutput(image))
		For x = 0 To ImageWidth(image) - 1
			For y = 0 To ImageHeight(image) - 1
				tableau(x, y) = Point(x, y)
			Next
		Next
	StopDrawing()
	
	ratio = ImageWidth(image) / ImageHeight(image)
	
	If ratio > 1
		Image_w = largeur_cote
		Image_h = largeur_cote / ratio
	Else
		Image_h = largeur_cote
		Image_w = largeur_cote * ratio
	EndIf
	
	RATIO_petit_grand = Image_w / ImageWidth(image)
	
	image_old = CreateImage(#PB_Any, Image_w, Image_h)
	
	StartDrawing(ImageOutput(image_old))
		For x = 0 To ImageWidth(image) - 1
			For y = 0 To ImageHeight(image) - 1
				Box(x * RATIO_petit_grand, y * RATIO_petit_grand, Round(RATIO_petit_grand, #PB_Round_Up), Round(RATIO_petit_grand, #PB_Round_Up), tableau(x, y))
			Next
		Next
	StopDrawing()
	
	SetGadgetData(Gadget, image_old)
	SetGadgetState(Gadget, ImageID(image_old))
	ResizeGadget(Gadget, pos_x + (largeur_cote - image_w) / 2, pos_y + (largeur_cote - image_h) / 2, #PB_Ignore, #PB_Ignore)
	
EndProcedure


DisableExplicit

;{ Fenêtre

Procedure OpenWD_Window_0()
	WD_Window_0 = OpenWindow(#PB_Any, 0, 0, 690, 550, "Memoire Associative", #PB_Window_ScreenCentered | #PB_Window_SystemMenu)
	
	GD_ListIcon_0 = ListIconGadget(#PB_Any, 10, 10, 110, 270, "Images", 50, #PB_ListIcon_AlwaysShowSelection)
	
	GD_Frame3D_0 = Frame3DGadget(#PB_Any, 130, 0, 190, 140, "")
	GD_Text_0 = TextGadget(#PB_Any, 140, 20, 90, 20, "Image soumise :")
	GD_Image_0 = ImageGadget(#PB_Any, 260, 20, 50, 50, 0, #PB_Image_Border)
	GD_Text_1 = TextGadget(#PB_Any, 140, 80, 90, 20, "Résultat :")
	GD_Image_1 = ImageGadget(#PB_Any, 260, 80, 50, 50, 0, #PB_Image_Border)
	
	GD_Frame3D_1 = Frame3DGadget(#PB_Any, 130, 140, 190, 140, "")
	GD_Text_2 = TextGadget(#PB_Any, 140, 150, 170, 20, "Taille de l'info de sortie :")
	GD_Text_3 = TextGadget(#PB_Any, 140, 173, 50, 20, "W x H =")
	GD_String_0 = StringGadget(#PB_Any, 200, 170, 30, 20, "5", #PB_String_Numeric)
	GD_Text_4 = TextGadget(#PB_Any, 240, 173, 10, 20, "x")
	GD_String_1 = StringGadget(#PB_Any, 260, 170, 30, 20, "7", #PB_String_Numeric)
	
	GD_Text_8 = TextGadget(#PB_Any, 140, 198, 50, 20, "Cycle Out")
	GD_String_5 = StringGadget(#PB_Any, 200, 195, 30, 20, "20", #PB_String_Numeric)
	GD_Text_9 = TextGadget(#PB_Any, 240, 198, 10, 20, "µ")
	GD_String_6 = StringGadget(#PB_Any, 260, 195, 30, 20, "0.2")
	
	GD_Button_0 = ButtonGadget(#PB_Any, 140, 250, 170, 20, "Effectuer l'apprentissage")
	GD_Button_1 = ButtonGadget(#PB_Any, 140, 220, 170, 20, "Redéfinir les neurones")
	
	GD_Frame3D_2 = Frame3DGadget(#PB_Any, 330, 0, 350, 280, "")
  GD_Text_7 = TextGadget(#PB_Any, 340, 20, 40, 20, "Nom :")
  GD_String_4 = StringGadget(#PB_Any, 390, 20, 50, 20, "")
  
	GD_Canvas_0 = CanvasGadget(#PB_Any, 340, 50, 220, 220, #PB_Canvas_ClipMouse)
	
	GD_Text_5 = TextGadget(#PB_Any, 520, 20, 50, 20, "W x H =")
	GD_String_2 = StringGadget(#PB_Any, 580, 20, 30, 20, "5", #PB_String_Numeric)
	GD_Text_6 = TextGadget(#PB_Any, 620, 20, 10, 20, "x")
	GD_String_3 = StringGadget(#PB_Any, 640, 20, 30, 20, "7", #PB_String_Numeric)
	
	GD_Button_2 = ButtonGadget(#PB_Any, 570, 50, 100, 20, "Soumettre")
	GD_Button_3 = ButtonGadget(#PB_Any, 570, 80, 100, 40, "Enregistrer une nouvelle Image", #PB_Button_MultiLine)
	GD_Button_4 = ButtonGadget(#PB_Any, 570, 130, 100, 50, "Enregistrer sur l'image sélectionnée", #PB_Button_MultiLine)
  GD_Button_5 = ButtonGadget(#PB_Any, 570, 190, 100, 40, "Supprimer l'image sélectionnée", #PB_Button_MultiLine)
  GD_Button_6 = ButtonGadget(#PB_Any, 570, 240, 100, 30, "Chargement auto", #PB_Button_MultiLine | #PB_Button_Toggle)
  
  GD_Editor_0 = EditorGadget(#PB_Any, 10, 290, 670, WindowHeight(WD_Window_0) - 300)
  
	AddKeyboardShortcut(WD_Window_0, #PB_Shortcut_Escape, 0)
	AddKeyboardShortcut(WD_Window_0, #PB_Shortcut_Return, 1)
	
	SetGadgetAttribute(GD_ListIcon_0, #PB_ListIcon_DisplayMode, #PB_ListIcon_DisplayMode)
	SetGadgetState(GD_Button_6, #True)
	
	MiseAJour_TailleCanvas()
EndProcedure

OpenWD_Window_0()

;}

;}


;{ chargement de la base de donnée des images

ChargementImageDATA("Image_DATA.img")

Nb = Val(GetGadgetText(GD_String_0)) * Val(GetGadgetText(GD_String_1))
*Memoire.MemoireAssociative = CreationMemoireAssociative(Nb, Nb)

;}


Repeat
	event = WaitWindowEvent()
	
	;{ gestion évènements
	Select event
		Case #PB_Event_Menu
			;{ menus
			Select EventMenu()
				Case 0 ; Key_escape
					event = #PB_Event_CloseWindow
					
				Case 1 ; Key_Return
					If GetActiveGadget() = GD_String_2 Or GetActiveGadget() = GD_String_3
						MiseAJour_TailleCanvas()
					EndIf
					
			EndSelect
			;}
			
			;{ Gadgets
		Case #PB_Event_Gadget
			Select EventGadget()
				Case GD_Button_3
					;{ enregistrer une nouvelle image
					
					If IsImage(IMG_canvas)
						AddGadgetItem(GD_ListIcon_0, -1, GetGadgetText(GD_String_4), ImageID(IMG_canvas))
						
						SetGadgetItemData(GD_ListIcon_0, CountGadgetItems(GD_ListIcon_0) - 1, IMG_canvas)
						
						IMG_canvas = 0
						
						MiseAJour_TailleCanvas()
					EndIf
					
					;}
					
				Case GD_Button_4
					;{ enregistrer sur l'image sélectionnée, l'ancienne image est perdue
					
					elem_selc = GetGadgetState(GD_ListIcon_0)
					
					If elem_selc <> -1 And IsImage(IMG_canvas)
						IMG_suppr = GetGadgetItemData(GD_ListIcon_0, elem_selc)
						
						If IsImage(IMG_suppr)
							FreeImage(IMG_suppr)
						EndIf
						
						SetGadgetItemText(GD_ListIcon_0, elem_selc, GetGadgetText(GD_ListIcon_0))
						SetGadgetItemImage(GD_ListIcon_0, elem_selc, ImageID(IMG_canvas))
						SetGadgetItemData(GD_ListIcon_0, elem_selc, IMG_canvas)
						
						IMG_canvas = 0
						
						MiseAJour_TailleCanvas()
					EndIf
					
					;}
					
				Case GD_Button_5
					;{ supprimer l'image sélectionnée
					
					elem_selc = GetGadgetState(GD_ListIcon_0)
					
					If elem_selc <> -1
						IMG_suppr = GetGadgetItemData(GD_ListIcon_0, elem_selc)
						
						If IsImage(img_suppr)
							FreeImage(IMG_suppr)
						EndIf
						
						RemoveGadgetItem(GD_ListIcon_0, elem_selc)
					EndIf
					
					;}
					
				Case GD_ListIcon_0
					;{ Chargement d'une image par clic sur la ListIcon
					
					If GetGadgetState(GD_Button_6) = #True
						; chargement dans le panneau de modification
						elem_selc = GetGadgetState(GD_ListIcon_0)
						
						If elem_selc <> -1
							If IsImage(IMG_canvas)
								FreeImage(IMG_canvas)
							EndIf
							
							IMG_canvas = GetGadgetItemData(GD_ListIcon_0, elem_selc)
							IMG_canvas = CopyImage(IMG_canvas, #PB_Any)
							
							SetGadgetText(GD_String_4, GetGadgetItemText(GD_ListIcon_0, elem_selc))
							
							; dessin de l'image dans le canvas
							MiseAJour_ImageCanvas(IMG_canvas)
							
						EndIf
					EndIf
					
					;}
					
				Case GD_String_2, GD_String_3
					;{ Modification de la taille du canvas
					
					If EventType() = #PB_EventType_LostFocus
						MiseAJour_TailleCanvas()
					EndIf
					
					;}
					
				Case GD_Canvas_0
					;{ dessin sur le canvas
					
					MiseAJour_DessinCanvas()
					
					;}
					
				Case GD_Button_1
					;{ Redéfinir les neurones
					
					If *Memoire
						FreeMemoireAssociative(*Memoire)
					EndIf
					
					Nb = Val(GetGadgetText(GD_String_0)) * Val(GetGadgetText(GD_String_1))
					*Memoire = CreationMemoireAssociative(Nb, Nb)
					
					;}
					
				Case GD_Button_0
					;{ Effectuer l'apprentissage
					
					If CountGadgetItems(GD_ListIcon_0) = 0
						MessageRequester("Attention", "Base d'Image vide")
					Else
						IMG_premierItem = GetGadgetItemData(GD_ListIcon_0, 0)
						
						If IsImage(IMG_premierItem)
							; création de la base d'apprentissage
							*Base.BaseApprentissage = CreationBaseApprentissage(ImageWidth(IMG_premierItem) * ImageHeight(IMG_premierItem))
							Message("Base d'apprentissage créée")
							
							; ajout des exemples, ils doivent avoir la même dimension que la première image, sinon, ils ne seront pas ajoutés
							image_ajoutee = 0
							
							For i = 0 To CountGadgetItems(GD_ListIcon_0) - 1
								IMG_select = GetGadgetItemData(GD_ListIcon_0, i)
								
								If IsImage(IMG_select) And ImageWidth(IMG_premierItem) = ImageWidth(IMG_select) And ImageHeight(IMG_premierItem) = ImageHeight(IMG_select) And Ajout_Exemple_Apprentissage(*Base, IMG_select)
									image_ajoutee + 1
								EndIf
							Next
							
							Message(Str(image_ajoutee) + " images de " + Str(ImageWidth(IMG_premierItem)) + " x "+ Str(ImageHeight(IMG_premierItem)) + " ajoutées à la Base d'apprentissage")
							
							; Lancement de l'apprentissage :
							CycleOut = Val(GetGadgetText(GD_String_5))
							Mu.d = ValD(GetGadgetText(GD_String_6))
							
							If Mu = 0 : Mu = 0.2 : SetGadgetText(GD_String_6, StrD(Mu)) : EndIf
							
							res = Apprentissage_MemoireAssociative(*Memoire, *Base, Mu, CycleOut)
							
							Select res
								Case -1
									Message("Apprentissage Echoué - Non correspondance entre le nombre d'entrée de la base et de la mémoire")
									
								Case 0
									Message("Apprentissage Réussi")
									
								Default
									Message("Apprentissage Impossible - " + Str(res) + " Cycles")
									
							EndSelect
							
							FreeBaseApprentissage(*Base)
							Message("Base d'apprentissage libérée")
							
						EndIf
					EndIf
					
					;}
					
				Case GD_Button_2
					;{ Soumettre une image
					
					If IsImage(IMG_resultat)
						FreeImage(IMG_resultat)
					EndIf
					
					If IsImage(IMG_canvas)
						Message("Nouvelle image soumise à la mémoire")
						
						MiseAJour_Image(GD_Image_0, IMG_canvas, 260, 20, 50)
						
						IMG_resultat = CalculReponse(*Memoire, IMG_canvas)
						
						If IsImage(IMG_resultat)
							MiseAJour_Image(GD_Image_1, IMG_resultat, 260, 80, 50)
						EndIf
					EndIf
					
					;}
					
			EndSelect
			
			;}
			
	EndSelect
	;}
	
Until event = #PB_Event_CloseWindow


;{ sauvegarde des données images

SauvegardeImageDATA("Image_DATA.img")

;}

End


; Début du test

;{ Test 1

; ; création de la base d'exemple
; *Base.BaseApprentissage = CreationBaseApprentissage(4)
; 
; ; ajout des exemples dans la base :
; Ajout_Exemple_Apprentissage(*Base, "1,-1,1,-1,1")
; Ajout_Exemple_Apprentissage(*Base, "1,1,1,1,1")
; Ajout_Exemple_Apprentissage(*Base, "1,1,1,-1,-1")
; Ajout_Exemple_Apprentissage(*Base, "1,-1,-1,1,-1")
; 
; 
; ; création du neurone
; *Neurone.Neurone = CreationNeurone(4, 0.1, #False)
; 
; ; Apprentissage
; If Apprentissage(*Neurone, *Base, 0.1) = #False
; 	Debug ""
; 	Debug "Aucune solution n'a été trouvée."
; EndIf
; 
; 
; ; Affichage des résultats (poids) :
; Debug ""
; Debug "Résultats"
; ForEach *Neurone\PoidsEntree()
; 	Debug "w" + Str(ListIndex(*Neurone\PoidsEntree())+1) + " = " + *Neurone\PoidsEntree()
; Next
; Debug "Seuil = " + *Neurone\Seuil

;}

_________________________________________________
Mon site : CeriseCode (Attention Chantier perpétuel ;))
Avatar de l’utilisateur
Kwai chang caine
Messages : 6989
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: Pour les matheux ..se contruire un mini OCR

Message par Kwai chang caine »

Tout d'abord merci à tous de votre réponse 8)


@GRom et MindPhaser
Sincèrement, je voyais pas ça si compliqué, étant donné que je connais la police qui va être utilisée, que c'est toujours la même, juste la hauteur varie selon la page.
Parce que le coups du perfectron 8O
Autant vous dire que ça dépasse mes capacités et surement celle de 5 générations de ma descendance que je n'aurais jamais :mrgreen:
Et puis mon code a pas besoin d'apprendre, il a besoin de savoir :D
Une fois qu'on lui aura expliqué correctement ce qu'est un A, ce sera toujours le même.

En tout cas merci, GRom, encore un lien qui me prouve que j'aurais du aller à l’école plus longtemps, et surtout ne pas avoir passé mon temps à me retourner et de ce fait visiter les 4 angles toute l'année :oops:
C'est ce genre de page qui me déprime, une fois j'avais eu la géniale idée de créer un cryptage, et comme le résultat était trop long, je me suis lancé a aller sur les forums de matheux, pour leur demander comment on pourrait réduire ce dernier.
Les gens ont été gentils, mais plus ils m'expliquait, plus je visitais ces sites, plus lé genèse de l'humanité que je croyais sommeiller au plus profond de moi resurgissait, pour ne plus générer qu'un seul son qui fut emmis de ma bouche beante : "Honk honk" Image
C'est à ce moment que l'on s'apperçoit de la monstruasité du savoir de l'humanité 8O
On se retrouve a la marternelle devant des sites comme ceux-ci, que dis je la maternelle....à la creche :oops:

Et c'est ça dans tous les domaines, le français, les math, chaque type de technologie (Des milliers), le médical, etc ..

Quoi qu'il en soit merci encore de ta reponse Grom et du lien Mindphaser 8)

@Frenchy pilou
Merci pour le lien, mais j'ai déjà un mal fou à lire et écrire l'anglais, mais je comprend pas le canard ...ce mec a le débit d'une mitrailleuse et l'articulation d'un anus de none :mrgreen:
Ce qui est sur, c'est que j'avais appris qu'un malin avait pensé à créer un site de cul par exemple, ou un site de warez en proposant des trucs de "guedin" à la portée d'un clic
Style la photo de mylene farmer nue, ou johnny hallyday en pleine action, ou des maxis logiciels gratuits...etc

Evidemment plein de bourrins naifs cliquaient sur les liens et se retrouvaient devant un captcha qu'ils decryptaient manuellement et envoyaient au site qui en retour évidemment ne donnait pas les choses promises.
L’intérêt ?? c'est que tellement de personnes s'occupaient donc de décrypter gratos les fameux captcha en direct, il suffisait d'attendre un peu pour qu'un pigeon se fasse prendre et decrypte a la place du robot le captcha et renvoi la reponse au robot pour qu'a son tour il clique sur un lien l'ammenant devant un autre captcha qu'il envoyait a nouveau a ce faux sites en attendant le prochain pigeon :lol:
En attendant l'idée était géniale...je sais pas si c'est celle ci ??

Pour l'OCR, je ne peux pas utiliser internet, mais quoi qu'il en soit merci pour le lien ça peu être utile :wink:
J'ai aussi testé des OCR open source comme tesseract, mais les resultats sont pas tres probants :(

@Graph100
Merci pour ton code 8O
Et ben, je vais essayer de le comprendre..mais je pensais pas qu'il faille que je refasse "la creation" en partant de l'atome pour decoder 62 lettres et 10 chiffres.
En tout cas bravo, tu fais de ces trucs de dingues dans tes cours 8)

Encore merci à vous tous de m'avoir donné votre avis, on peut pas dire que ce soit super encourageant, mais ça aide quand même 8)
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Re: Pour les matheux ..se contruire un mini OCR

Message par Backup »

si effectivement la police reste la meme , pas besoin d'usine a gaz !

j'avais balancé sur le forum , un prg qui etait capable de différencier 2 images

ben la le principe est le meme ,
le seul probleme va etre de caler chaque lettre de sorte qu'elle soient toute positionné
de la meme façon par rapport a un repère , comme le bas-gauche ou le haut gauche de l'image contenant chaque lettre
a analyser ... ya un decoupage a faire ... une image= le caractère a analyser ..

une fois que tu as resolu ce probleme ,
tu fait un petit algo qui va regarder certains pixel de l'image contenant la lettre
tu retiens leur couleur (l'ideal serai d'avoir juste le noir et le blanc il existe des algo sur le forum pour ça)
tu as donc une "matrice" de pixel( de position de pixel noirs) ( pas besoin d'en avoir beaucoup , je pense que 10 serai bien)

il te suffit de faire "Apprendre" a ton programe que lorsque le pixel (20,10) et le pixel(30,30) .....etc.. sont tous noir
tu recherche la correspondance dans tes matrices, si ça correspond au information de ta matrice "_A" , donc il s'agit d'un "A" (par exemple)

une fois ta base de donnée de position de pixel noir est faite (il y aura donc environs 130 "Matrices" de 10 positions de pixels
130 car je compte les signes comme la virgule etc ...

il te suffira donc de comparer l'image a analyser , avec ta base de donnée et de sortir le caractère correspondant


je sais pas si je suis clair , mais j'me comprends , c'est deja pas mal :)


une matrice peut etre encodé sur une seule ligne sous la forme binaire des points noir , ça evite de retenir une coordonées

exemple le Signe "L" correspondrai a
"100000"
"100000"
"100000"
"11111"
ce qui fait "10000010000010000011111" ... bon il ya surement d'autres façon d'encoder l'info ;)

donc si dans ton image la sequence binaire correspond a "10000010000010000011111" ou a une grosse partie de cette info comme "1xxx00100xxx10000011xx1"
ben c'est que c'est un "L" ou que ça y ressemble vachement :)
G-Rom
Messages : 3641
Inscription : dim. 10/janv./2010 5:29

Re: Pour les matheux ..se contruire un mini OCR

Message par G-Rom »

pas bête ton tableau de boolean , tu pourrais même en comparant les tableaux entre eux fixé un % de marge d'erreur pour donner de la souplesse au système.
Backup
Messages : 14526
Inscription : lun. 26/avr./2004 0:40

Re: Pour les matheux ..se contruire un mini OCR

Message par Backup »

oui , tout a fait :)

pour le fait de repérer quelques pixel dans une image pour l'identifier , ça marche deja tres bien a partir
de 3 pixels :)
mais pour une fonte c'est plus precis , pour ne pas confondre un "V" avec un "U" ils faut augmenter
la matrice de reference :)

revoici mon code qui compare 2 images, et qui est capable de dire si elle sont pareil ou pas ...
pour une lettre c'est la meme chose, on la compare a une reference (binaire..ou quelques pixel clef sont important) au lieu de la comparer a une autre lettre ..
ici la tolerance est lié au nombres de pixels vérifié ..


le principe est là :)

Code : Tout sélectionner

;{- Enumerations / DataSections
;{ Windows

; Code Par Dobro
; en Purebasic 5.11
Enumeration
	#Window
EndEnumeration
;}
;{ Gadgets
Enumeration
	#titre
	#info
	#Button_image1
	#Button_image2
	#Button_compare
	#input
	#image1
	#image2
EndEnumeration

global path$=""
UseJPEGImageDecoder()
UsePNGImageDecoder()
UseTGAImageDecoder()

;

Declare  OpenWindow_Window()
Declare  compare(im1,im2,po)
Declare  taux(couleur)

;to predict the test on the color component of the point and not on the exact color .... (taux de rouge, vert,bleu)


;}
;{ Fonts
Enumeration
	#Font_titre
EndEnumeration
;}
Define.l Event, EventWindow, EventGadget, EventType, EventMenu
;}
Procedure OpenWindow_Window()
	If OpenWindow(#Window, 554, 111, 354, 191, "By Dobro", #PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_TitleBar|#PB_Window_SizeGadget)
		
		TextGadget(#titre, 10, 10, 375, 35, "Comparateur d'image", #PB_Text_Center)
		ButtonGadget(#Button_image1, 30, 90, 115, 35, "Load Picture 1")
		ButtonGadget(#Button_image2, 30, 135, 115, 35, "Load Picture  2")
		ButtonGadget(#Button_compare, 230, 135, 115, 35, "compare !")
		TextGadget(#info, 10, 60, 200, 35, "number of points to be compared", #PB_Text_Center)  ; >3 !!
		StringGadget(#input, 200, 60, 50, 35, "3" ,#PB_String_Numeric   )
		; Gadget Fonts
		SetGadgetFont(#titre, LoadFont(#Font_titre, "Comic Sans MS", 16, #PB_Font_Bold|#PB_Font_HighQuality))
		
	EndIf
EndProcedure

OpenWindow_Window()

;{- Event loop
Repeat
	
	Event = WaitWindowEvent()
	Select Event
		; ///////////////////
		Case #PB_Event_Gadget
		EventGadget = EventGadget()
		EventType = EventType()
		select  EventGadget 
			case #titre
			
			case #Button_image1
			if path$=""
				path$="c:\"
			endif
			file$=OpenFileRequester("Load Picture 1",path$,"*.*",0)
			if loadimage(#image1,file$)<>0
				Else
				MessageRequester("info","Picture not loaded",#PB_MessageRequester_Ok)
			endif
			
			
			case  #Button_image2
			if path$=""
				path$="c:\"
			endif
			file$=OpenFileRequester("Load Picture 2",path$,"*.*",0)
			if loadimage(#image2,file$) <>0
				else
				MessageRequester("info","Picture not loaded",#PB_MessageRequester_Ok)
			endif
			
			case #Button_compare
			po=val(GetGadgetText(#input))
			
			if compare(#image1,#image2,po)=#true
				MessageRequester("info","This is certainly the same image",#PB_MessageRequester_Ok)
				Else
				MessageRequester("info","This is not the same image",#PB_MessageRequester_Ok)
			endif
			
			
		Endselect
		; ////////////////////////
		Case #PB_Event_CloseWindow
		EventWindow = EventWindow()
		If EventWindow = #Window
			CloseWindow(#Window)
			Break
		EndIf
	EndSelect
Forever

; **************************** Zone des procedures **********************************²
procedure compare(im1,im2,po)
	; By Dobro
	; im1 = numero de l'image 1
	; im2 = numero de l'image 2
	; po = nombre de points de comparaison , plus il y en a plus c'est long, mais plus c'est bon  LOL
	structure coordo
		x.l ; coordonné x du point
		y.l ; coordonné y du point
		couleur.l  ; la couleur du point
	endstructure
	dim coordo.coordo(po) ; et met leur coordonnés dans la structure ainsi que leur couleur !
	
	
	if po<=3 :po=3:endif ; petite securité on verifie au moins 1 point
	
	if IsImage(#image1)<>0
		Else
		MessageRequester("Erreur","the images were not loaded", #PB_MessageRequester_Ok )
		ProcedureReturn #false
	endif
	if IsImage(#image2)<>0
		Else
		MessageRequester("Erreur","the images were not loaded", #PB_MessageRequester_Ok )
		ProcedureReturn #false
	endif
	
	x_im1=ImageWidth(#image1)
	y_im1=ImageHeight(#image1) 
	x_im2=ImageWidth(#image2)
	y_im2=ImageHeight(#image2) 
	if x_im1<=x_im2:x_de=x_im1:else: x_de=x_m2-1:endif ; on va recuperer la resolution la plus petite 
	if y_im1<=y_im2:y_de=y_im1:else: y_de=y_m2-1:endif; entre les 2 images
	if po> (x_de * y_de) : po=(x_de * y_de)/4:endif ; petite securité au cas ou po serai superieur au nombre de points de l'image
	
	; ********* tire les points au dé ************
	
	StartDrawing(ImageOutput(#image1)) 
		for i=1 to po  ; pour tout les points
			coordo(i)\x.l=random(x_de-1) ; on recup la coordonée x dans l'image 1
			coordo(i)\y.l=random(y_de-1) ; on recup la coordonée y dans l'image 1
			coordo(i)\couleur.l=taux(point(coordo(i)\x.l,coordo(i)\y.l) ) ; on recup la couleur dans l'image 1
		next i
	StopDrawing()
	; ****************************************
	; on va comparer si les points sont pareil entre les 2 images
	
	StartDrawing(ImageOutput(#image2)) 
		for i=1 to po  ; pour tout les points
			coul=taux(point(coordo(i)\x.l,coordo(i)\y.l) )
			if coul <> coordo(i)\couleur.l  ; le point est different .. c'est pas le meme image
				diff=diff+1
			endif
		next i
	StopDrawing()
	
	if diff<(po/3) ; le seuil de difference est inferieur au tier des points (moins du tier des points sont different)
		ProcedureReturn #true ; c'est certainement la meme image ( tout depend du nombre de point testé )
		Else
		ProcedureReturn #false ; trop de difference !  c'est pas la meme image
	endif
endprocedure

procedure taux(couleur)
	taux_rouge=int((red(couleur)/255)*100)
	taux_vert=int((green(couleur)/255)*100)
	taux_bleu=int((blue(couleur)/255)*100)
	total=int(taux_rouge+taux_vert+taux_bleu)/3
	ProcedureReturn total
endprocedure

; **********************************************************************************


;}

; EPB
Frenchy Pilou
Messages : 2194
Inscription : jeu. 27/janv./2005 19:07

Re: Pour les matheux ..se contruire un mini OCR

Message par Frenchy Pilou »

En attendant l'idée était géniale...je sais pas si c'est celle ci ??
Pour plus de précision (et en français ;)
http://fr.wikipedia.org/wiki/CAPTCHA

et évidemment celle-ci qui est sacrément futée! (toujours en français :wink:
http://fr.wikipedia.org/wiki/ReCAPTCHA
Est beau ce qui plaît sans concept :)
Speedy Galerie
Avatar de l’utilisateur
Kwai chang caine
Messages : 6989
Inscription : sam. 23/sept./2006 18:32
Localisation : Isere

Re: Pour les matheux ..se contruire un mini OCR

Message par Kwai chang caine »

@DOBRO
Alors la l'idée de mettre tout en une seule phrase c'est fort, j'y avais pas pensé 8O
Moi j'avais eu la même idée en utilisant un tableau, parce que bettement un tableau est "carré" donc ressemble à une matrice, mais c'est vrais que y mettre sur une ligne, c'est un peu moins lisible pour l'humain, mais surement mieux pour la machine 8)

Pour ce qui est de la couleur, j'avais aussi pensé à la retirer, car mes essais de la semaine derniere avaient été sur des images enregistrées avec un programme SnapShot en 1 bit, en fait je savais pas ce que ça voulait dire, mais j'ai decouvert a force d'essais que moins on mettait de bit et plus le rechercheur d'image l'une dans l'autre s'en sortait.
apres j'ai vu que 1 bit ça donnait noir et blanc (Normal deux etats, mais j'ai compris qu'apres :oops:)

En plus j'suis obligé, parce que ces bourrins pour corser le tout ont mis une ligne sur deux de fond de chaque couleur, et aussi une autre couleur de fond au survol de la souris :?

Donc pour la couleur, je devrais avoir trouvé le truc, en plus, les dieux sont un peu avec moi, car en plus de votre aide, je viens de voir un post qui convertit les images en 1 bit (On aurait dit qu'il m'avait entendu dans mes nuits :lol:)

J'ai aussi remarqué que le travail en BMP est préférable, les programmes retrouvent mieux les images dans les BMP que les autres formats compressés.

Pour le callage, tu as raison, j'ai pas encore commencé la découpe des bandes mais je devrait y arriver, il suffit de scanner les pixels avec un trait comme sur un scanner en partant de la gauche par exemple, et des que l'on trouve un pixel sur la ligne qui n'est pas de la couleur du fond a priori ce devrait être le début de la lettre, si y'a pas des merdouilles autour, car j'ai aussi découverts que quand on grossi mortel l'image autour y'a des pixels qui sont ni couleur du fond, ni couleur du caractère, mais comme le dit GRom je pourrais peut être utiliser une marge d'erreur, enfin si j'y arrive :mrgreen:

Reste le problème de la taille, car même police, mais taille différente, donc comme tu me le confirme, le fait de créer une matrice devrait annuler ce problème car comme je l'avais pensé, chaque matrice serait par rapport a son image, donc pas une image par rapport à l'autre comme le code de darkDragon qui a fonctionné nickel que tant que je prenais les caractères sur la même page que je comparais la bande (Car même hauteur), mais quand j'ai voulu faire une demo a un copain, "je me suis trouvé couille et bite" (Expression de ma région :mrgreen:) avec mes caracteres de la page 1 un peu plus petits comparant une bande de la page 2, et la ...le super dragon a eu une extinction de feu :lol: (En attendant encore bravo quand même pour son comparateur efficace jusqu'a la)

Pour ce qui est de ton code, je l'avais vu et l'avais essayé en le trouvant efficace à l'epoque, mais je n'avais pas percuté pour mon besoin.
Car ton code compare deux images ce qui est super pour par exemple faire du tri de repertoires avec des photos redondantes, et je m'etais dit tiens ça peut etre utile... 8)
Alors que celui de darkDragon recherchais une photo dans une autre, en se déplaçant et donne les coordonnées de cette image si il la trouve, et c'est ça qui fait toute la différence, et ça j'en avais sacrement besoin :D
Car j'avais essayé de piloter IE en reperant des parties d'ecran, pour deplacer la souris a cette position et la faire cliquer, j'avais aussi ouvert un POST sur ce forum a ce sujet, pour avoir un peu d'aide de matheux encore une fois, car je recherchais dans toute la page et ce code etait trop long :(
Alors tout naturellement c'est vers ce code que je ma premiere idée est venue, car il m'avait trop épaté, et en plus etait encore mieux adapté puisqu'il ne compare pas deux image mais en recherche une dans l'autre et c'est mon cas car si elles sont pas exactement bien calées comme on l'a dit au dessus..ça va "merder" :(

En tout cas mille merci DOBRO de ta précieuse aide 8)
Je vais regarder ça de plus pres, mais grâce à vous je reprend espoir 8)

@FrenchyPilou
Merci pour les liens je vais aussi y jeter un oeil 8)
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
Avatar de l’utilisateur
Ulix
Messages : 315
Inscription : ven. 04/juin/2004 14:27
Localisation : Frontignan

Re: Pour les matheux ..se contruire un mini OCR

Message par Ulix »

Salut a tous !

Très intéressant votre raisonnement ! :lol:

Je trouve que le plus difficile à faire sera bien la découpe :
- des lignes
- puis la découpe caractère par caractère.

Une piste : peut-être en recherchant les pixels adjacent ?
Exemple en reprenant l'idée de matrice

l1 : 00000000
l2 : 01000000
l3 : 01000000
l4 : 01000000
l5 : 01111110
l6 : 00000000

Après détection du premier pixel (couleur différente du fond), ici l2 2ème bit
Recherche des pixels adjacent de même couleur :
- 8 combinaisons possibles (boucle possible ; certaine peut être négligé : gauche et haut.. a voir au cas par cas)

- pas l2 3ème bit, pas l3 1er bit, pas l3 3ème bit....etc
seul trouvé l3 2ème bit, donc a partir de celui là faire une nouvelle recherche... ainsi de suite.
Dernier trouvé l5 7ème bit : c'est la fin de la lettre.

Cela donne donc la hauteur de ligne est la largueur de la lettre.
On peut donc :
- Traiter ce caractère (comparaison avec une matrice...etc)
- Réduire la ligne d'un caractère
- Recommence avec le suivant.


Ce ne sont que quelque idées ! (pour faire avance le schmilblick, comme dirais l'autre...)

Dans tous les cas, n'hésite pas a balancé du code ca aide a avancé !
Bonne programmation... :mrgreen:

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

Re: Pour les matheux ..se contruire un mini OCR

Message par Ar-S »

C'est comme ça que boss subtitle Workshop pour ceux qui connaissent.
il lit les sous titres dvd sous forme d'image et demande à quoi correspond la 1ere, on lui indique la lettre puis il continue.
On créée une suite complète et on sauve la matrice générée. Celle ci sera réutilisable pour d'autre film même si ce n'est pas dit que ça fonctionne (il faudra alors recommencer).

Il faut tout de même que le programme soit capable de détecter la hauteur de la ligne contenant les caractères.
~~~~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: Pour les matheux ..se contruire un mini OCR

Message par Kwai chang caine »

Merci ULIX de l'idée.
J'ai eu un peu de mal a comprendre ton explication, mais en fait je connais la couleur de fond, donc je peux en déduire ou est écrit le caractère.
Le plus dur est bien sur le calage du caractère, mais aussi ces pixels perdus, qui sont ni chien ni loups.
Quand on grossi un caractère qui parait propre j'ai vu des pixels autour qui n'ont ni la couleur du fond, ni celle vraiment du caractère.
Souvent aussi pour faire l'arrondi dans les angles c'est pas vraiment la couleur du caractère et pas celle du fond.
Mais comme le dit DOBRO, quelques points devraient pouvoir déterminer la lettre, enfin j’espère.
Le tout est de faire la liste des points cruciaux de chaque lettre.
Je commencerais mercredi, car la j'suis pas au boulot, mais j'avais aussi pensé empiler les 26 lettres les unes sur les autres pour voir lesquels points ne sont pas communs, mais je pense que ça va être un gros foutoir
J'y pense maintenant, une fois les matrices faites, faire un programme qui repère les points particuliers de chaque lettre, un peu comme on pourrait dire les points "Premier" qui ne s'identifient que pour lui-meme en analogie aux nombre premiers qui ne se divisent que par 1 ou eux meme...(Putain ...KCC il a sorti l'artillerie lourde c'est la seule chose qui doit me rester de ma "carriere" mathématique scolaire :mrgreen:)

@Ars
J'avais aussi pensé à faire un groupe d'image par page, mais j'suis même pas sur que dans la même page les caractères ne vont pas varier d'un jour a l'autre selon si elle est plus chargé ou non.
Et puis j'me suis fait un fion comme ça rien qu'a récupérer les 10 chiffres minuscules, sans avoir commencé les 60 lettres...alors faire ça par page..sans être sur du résultat...
Ou alors y'aurais fallu que la decoupe se fasse au moins toute seule, et que l'on se tape à renommer les images, mais encore une fois sans certitude de reussite.
J'ai peur que ce soit un peu trop aléatoire tout ça :cry:

Non l'idée de DOBRO me parait cool au premier abord, je pense que je vais me lancer dans cette direction...et que trépasse si je faibli :mrgreen:
ImageLe bonheur est une route...
Pas une destination

PureBasic Forum Officiel - Site PureBasic
Avatar de l’utilisateur
Fortix
Messages : 559
Inscription : mar. 30/mai/2006 17:03

Re: Pour les matheux ..se contruire un mini OCR

Message par Fortix »

Personnellement, je pige rien au rôle que peut avoir ce
gadget Canvas

puisqu'il est incapable d'afficher une simple image :lol:

Code : Tout sélectionner


UseJPEGImageDecoder() 

img = LoadImage(#PB_Any,"mon_image.jpg");Changer le chemin svp

L = ImageWidth(img)
H = ImageHeight(img)

If OpenWindow(0,0,0,L,H,"CanvasGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
	CanvasGadget(0,0,0,L,H)
    
    Repeat
      	Event = WaitWindowEvent()
          
      	If Event = #PB_Event_Gadget And EventGadget() = 0 
        	If EventType() = #PB_EventType_LeftButtonDown Or (EventType() = #PB_EventType_MouseMove And GetGadgetAttribute(0, #PB_Canvas_Buttons|#PB_Canvas_Image) & #PB_Canvas_LeftButton)
          		StartDrawing(CanvasOutput(0))
		        	DrawImage(ImageID(img), 0, 0)
		        StopDrawing()
        	EndIf
      	EndIf    
      
	Until Event = #PB_Event_CloseWindow
EndIf


:lol:
Répondre