Page 1 sur 1

Neti : Un nettoyeur de photo de texte

Publié : jeu. 09/mai/2013 2:32
par graph100
Ce type de logiciel existe déjà sur les smartPhones, mais je me suis retrouvé avec des scans / photos de document écrit, et ils ne gèrent pas de manière pratique les photos déjà prisent.
Je me suis donc creusé la cervelle pour faire la même chose sur un pc, pour profiter de la puissance de calcul de nos machine (si un tel peut le faire pourquoi pas mon ordi ?! :lol: )

Bref, voila NETI (pour NETtoie Image) : Neti.zip

Ce que ça fait :
Prend un dossier d'image, nettoie les images selon 3 paramètres qui permettent d'obtenir le résultat désiré
si le cadre rouge est bougé, l'image finale sera un rectangle calculé à partir du cadre rouge.

Le même rectangle est appliqué pour tout le dossier, il est donc préférable de ne pas avoir bougé les documents et l'appareil (photo / scan..) entre chaque photo.
La détection des bords de l'image n'est pas encore faite.

Honnêtement le prog est pas fini, l'interface n'est pas vraiment au point, ça peut crasher si le cadre rouge sort des images, etc..
Mais j'en avais besoin pour bosser, donc je l'ai mis à ce point là.

EXEMPLE

Image originale :
Image

Image Nettoyée :
Image

Re: Neti : Un nettoyeur de photo de texte

Publié : sam. 11/mai/2013 9:15
par Backup
je n'en aurai probablement pas l'utilisation , mais merci pour le partage :)

ps : je pense que tu n'as pas eu beaucoup de retour, car les gens sont en vacances
donc moins présent :)

par contre ton algo est t'il compliqué ?
je dis ça car je l'aurai bien inclue dans Barbouille :)

Re: Neti : Un nettoyeur de photo de texte

Publié : sam. 11/mai/2013 23:43
par graph100
Je n'ai pas mis le code de cette application car elle fait appel à des gadgets CustomGadget.
Et que ça n'est pas un code copier-collable rapidement.

J'ai fait quelques recherche et test pour arriver à terminer la partie nettoyage (la partie transformation est postée sur le forum dans les astuces :D ).
Et j'ai pu confirmer mes théories de l'algo de nettoyage avec des documents de recherche utilisés pour nettoyer des photos de télescope pour voir mieux les étoiles et les satellites (enlèvement du bruit du capteur de l'appareil).

Ici le code de nettoyage seul :

Principe :

on fait le calcul d'une moyenne de l'image qui servira pour la comparaison avec un seuil
A partir de là on détermine quels sont les pixels d'information utile ou non. Les pixels considérés comme utiles sont "sombres".
Le code a une préférence marquée pour les informations à fort contraste (les lignes et points, et non les zones unies).

On pourrais aussi voir ce que donnerais une atténuation progression en fonction de la distance au seuil.

Code : Tout sélectionner


UsePNGImageEncoder()
UsePNGImageDecoder()
UseJPEGImageDecoder()


;{ structure & procedure


Structure QuatreOctet
	o1.a
	o2.a
	o3.a
	o4.a
EndStructure

Structure couleur
	StructureUnion
		c.l
		o.QuatreOctet
	EndStructureUnion
EndStructure

Structure image
	hdl.l
	file.s
	
	hdl_reduit.l
	
	hdl_res.l
	
	diviseur.l
	rayon.l
	seuil_diviseur.d
	
	x_end.l
	y_end.l
	
	moy.d
	sdt.d
	
	Array lum.a(1, 1)
EndStructure


Procedure ImageToArrayLum(*image.image)
	
	*image\hdl_reduit = CopyImage(*image\hdl, #PB_Any)
	ResizeImage(*image\hdl_reduit, ImageWidth(*image\hdl) / *image\diviseur, ImageHeight(*image\hdl) / *image\diviseur)
	
	If StartDrawing(ImageOutput(*image\hdl_reduit)) = 0
			ProcedureReturn #False
		EndIf
		
		
		*image\x_end = OutputWidth() - 1
		*image\y_end = OutputHeight() - 1
		
		Dim *image\lum(*image\x_end, *image\y_end)
		
		moyenne.l = 0
		variance.d = 0
		
		Define couleur.couleur
		
		DisableDebugger
		
		For y = 0 To *image\y_end
			For x = 0 To *image\x_end
				couleur\c = Point(x, y)
				*image\lum(x, y) = (couleur\o\o1 + couleur\o\o2 + couleur\o\o3) / 3
				
				moyenne + *image\lum(x, y)
			Next
		Next
		
		*image\moy = moyenne / (*image\y_end + 1) / (*image\x_end + 1)
		
		div.d = 1 / ((*image\y_end + 1) * (*image\x_end + 1) + 1)
		
		; calcul de la variance
		For y = 0 To *image\y_end
			For x = 0 To *image\x_end
				sous = *image\lum(x, y) - *image\moy
				
				variance = variance	+ sous * sous * div
			Next
		Next
		
		EnableDebugger
		
		*image\sdt = Sqr(variance)
		
	StopDrawing()
	
	FreeImage(*image\hdl_reduit)
	
	ProcedureReturn #True
EndProcedure

Procedure ImageMoyenneLocale(*image.image)
	
	rayon_max = *image\rayon
	
	;{ Précalcul des tranches de cercle
	Dim x_largeur.l(rayon_max * 2 + 1)
	
	For rayon = -rayon_max To rayon_max
		x_largeur(rayon + rayon_max) = Sqr(rayon_max * rayon_max - rayon * rayon)
		
		Debug x_largeur(rayon + rayon_max)
	Next
	;}
	
	r_max = rayon_max - 1
	r_min = -rayon_max + 1
	
	image_w = *image\x_end + 1
	image_h = *image\y_end + 1
	
	xmax.l = *image\x_end
	ymax.l = *image\y_end
	
	
	Dim moy.a(1,1)
	CopyArray(*image\lum(), moy())
	
	DisableDebugger
	
	For y = 0 To ymax
		For x = 0 To xmax
			
			n.l = 0 ; nb de point comptés dans la moyenne
			moy.l = 0 ; init de la moyenne locale
			
			For rayon = r_min To r_max
				; x_largeur.l = Sqr(rayon_max * rayon_max - rayon * rayon)
				x_largeur.l = x_largeur(rayon + rayon_max)
				x_max.l = x + x_largeur
				
				y_m = y + rayon
				
				If y_m > -1 And y_m < image_h
					For x_m = x - x_largeur To x_max
						If x_m > -1 And  x_m < image_w
							n + 1
							moy + moy(x_m, y_m)
							
						EndIf
					Next
				EndIf
				
			Next
			
			moy(x, y) = moy / n
		Next
	Next
	
	EnableDebugger
	
	CopyArray(moy(), *image\lum())
EndProcedure

Procedure CalculImage(*image.image)
	
	*image\hdl_res = CopyImage(*image\hdl, #PB_Any)
	
	
	If StartDrawing(ImageOutput(*image\hdl_res)) = 0
			ProcedureReturn #False
		EndIf
		
		x_end = OutputWidth() - 1
		y_end = OutputHeight() - 1
		
		seuil = *image\sdt / *image\seuil_diviseur
		
		DisableDebugger
		For y = 0 To y_end
			y_rounded.l = Round(y / *image\diviseur, #PB_Round_Down)
			
			For x = 0 To x_end
				couleur.couleur\c = Point(x, y)
				
				lum = (couleur\o\o1 + couleur\o\o2 + couleur\o\o3) / 3
				
				x_rounded.l = Round(x / *image\diviseur, #PB_Round_Down)
				
				If lum > *image\lum(x_rounded, y_rounded) - seuil
					Plot(x, y, #White)
				EndIf
			Next
		Next
		EnableDebugger
		
	StopDrawing()
	
	ProcedureReturn *image\hdl_res
EndProcedure



;}


;{ test area

img.image\file = OpenFileRequester("Ouvrir une image", "", "Images|*.bmp;*.jpg;*.png", 0)

; Paramètre de nettoyage
img\diviseur = 10
img\rayon = 15
img\seuil_diviseur = 1.2


img\hdl = LoadImage(#PB_Any, img\file)
If IsImage(img\hdl) = 0 : End : EndIf


time = ElapsedMilliseconds()


ImageToArrayLum(img)
ImageMoyenneLocale(img)
CalculImage(img)

time = ElapsedMilliseconds() - time

MessageRequester("", "Tps total = " + time + " ms")

SaveImage(img\hdl_res, GetPathPart(img\file) + StringField(GetFilePart(img\file), 1, ".") + "_res_rapide.png", #PB_ImagePlugin_PNG)


;}



Re: Neti : Un nettoyeur de photo de texte

Publié : dim. 12/mai/2013 9:57
par Backup
Merci pour le partage :)

Re: Neti : Un nettoyeur de photo de texte

Publié : lun. 13/mai/2013 11:28
par Frenchy Pilou
Et les mots qui sont encore difficilement lisibles par le programme, on les envoie au système de re Captcha! ;)

http://www.youtube.com/watch?v=-Ht4qiDRZE8

(on peut mettre des sous-titres en français)

Re: Neti : Un nettoyeur de photo de texte

Publié : lun. 13/mai/2013 13:52
par Ar-S
Salut Graph.
Dans ton exemple tu passes de l'image marron à l'image traitée ? Ton programme zappe la déformation ou tu as utilisé une autre image ?

Re: Neti : Un nettoyeur de photo de texte

Publié : lun. 13/mai/2013 16:39
par graph100
Effectivement l'image d'entrée est l'image marron, et celle en sortie est présentée en dessous, je n'ai rien fait d'autre que de les mettre en plus petit sur le post.

Mon programme effectue la transformation d'un quadrangle vers un rectangle. Il faut utiliser le cadre rouge (normalement sur le tour de l'image au début) pour donner la forme du quadrangle.
Je ne me suis pas encore attaqué à la détection de la forme automatiquement.